diff --git a/maths/binary_exponentiation.ts b/maths/binary_exponentiation.ts new file mode 100644 index 00000000..c528f3c5 --- /dev/null +++ b/maths/binary_exponentiation.ts @@ -0,0 +1,37 @@ +/** + * @function binaryExponent + * @description Returns the power of a number A raised to the power of B with binary exponentiation + * @summary Binary exponentiation calculatoes A^B in logarithmic time of B instead of linear time + * @param {Number} num - An array of two natural numbers, [A, B], where A^B will be solved + * @return {number} A^B + * @see [Wikipedia](https://cp-algorithms.com/algebra/binary-exp.html) + * @example binaryExponent([5, 2]) = 25 + * @example binaryExponent([10, 18]) = 1000000000000000000 + */ + +export const binaryExponent = (numbers: number[]): number => { + // raise errors upon invalid inputs + if (numbers.length != 2) { + throw new TypeError('Invalid Input') + } + for(let i=0; i < numbers.length; i++){ + if (numbers[i] < 0 || !Number.isInteger(numbers[i])) { + throw new TypeError('Invalid Input') + } + } + + // binary exponentiation algorithm + // if B == 0 + if (numbers[1] === 0) { + // A^0 = 1 + return 1; + } + let res = Math.pow(numbers[0], Math.floor(numbers[1] / 2)); + // if B is even or odd + if (numbers[1] % 2 === 1) { + return res * res * numbers[0]; + } + else { + return res * res; + } + } diff --git a/maths/co_prime.ts b/maths/co_prime.ts new file mode 100644 index 00000000..7937cc47 --- /dev/null +++ b/maths/co_prime.ts @@ -0,0 +1,51 @@ +/** + * @function coPrime + * @description Determine if given two numbers have no common factor (are coprimes). The common factor cannot be 1 or itself. + * @param {number} num - An array of two natural numbers (positive integers not including 0). + * @return {boolean} - Whether the given two number are coprimes + * @see https://en.wikipedia.org/wiki/Coprime_integers + * @example isPrime(2, 3) = 0 + * @example isPrime(3, 6) = 2 + */ +export const coPrime = (numbers: number[]): boolean => { + // raise corresponding errors upon invalid inputs + if (numbers.length != 2) { + throw new TypeError('Invalid Input') + } + for(let i=0; i < numbers.length; i++){ + if (numbers[i] < 1 || !Number.isInteger(numbers[i])) { + throw new TypeError('Invalid Input') + } + } + + // handle input being 1 + if (numbers[0] === 1 || numbers[1] === 1) return false + + let factors0 = [] + let factors1 = [] + + // iterate from 2 to the square root of num to find a factor + // add factors to arrays + for (let i = 2; i <= Math.sqrt(numbers[0]); i++) { + if (numbers[0] % i === 0) { + factors0.push(i) + } + } + for (let i = 2; i <= Math.sqrt(numbers[1]); i++) { + if (numbers[1] % i === 0) { + factors1.push(i) + } + } + console.log(factors0) + console.log(factors1) + + // check if same factors + for (let i = 0; i <= factors0.length; i++) { + if (factors1.includes(factors0[i])) { + return false + } + } + + // if the entire loop runs without finding a similar factor, return true + return true + } diff --git a/maths/geometric_mean.ts b/maths/geometric_mean.ts new file mode 100644 index 00000000..a5138b3a --- /dev/null +++ b/maths/geometric_mean.ts @@ -0,0 +1,39 @@ +/** + * @function geometricMean + * @description Returns the geometric mean of the provided array of numbers + * @summary The geometric mean of an array of numbers a_1, a_2,..., a_n is given by (a_1 * a_2 * ... * a_n)^(1/n) + * So, for example, the geometric mean of numbers 1, 2, 3, 4 is (1 * 2 * 3 * 4) ^ (1/4) + * @param {number[]} numbers - Array of numeric values + * @return {number} The aliquot sum of the number + * @see [Wikipedia](https://en.wikipedia.org/wiki/Geometric_mean) + * @example aliquotSum([2, 8]) = 4 + * @example aliquotSum([4, 8, 16]) = 8 + */ +export const geometricMean = (numbers: number[]): number => { + if (numbers.length < 1) { + throw new TypeError('Invalid Input') + } + for(let i=0; i < numbers.length; i++){ + if (numbers[i] === 0) { + return 0 + } + } + for(let i=0; i < numbers.length; i++){ + if (numbers[i] < 0) { + throw new TypeError('Invalid Input') + } + } + + // This loop multiplies all values in the 'numbers' array using an array reducer + const product = numbers.reduce((product, current) => product * current, 1) + + // Divide product by the length of the 'numbers' array. + let geo_mean = product ** (1/numbers.length) + + // Round to nearest integer if close enough due to imprecise float + if (Math.abs(geo_mean - Math.round(geo_mean)) < 0.000000000000001) { + geo_mean = Math.round(geo_mean); + } + + return geo_mean; +} \ No newline at end of file diff --git a/maths/hexagon_area.ts b/maths/hexagon_area.ts new file mode 100644 index 00000000..857f19d4 --- /dev/null +++ b/maths/hexagon_area.ts @@ -0,0 +1,28 @@ +/** + * @function hexArea + * @description Returns area of a regular hexagon + * @summary Finds the area of a regular hexagon (all 6 sides are equal lenght) + * @param {Number} num - A natural number + * @return {number} The area of a regular hexagon + * @see [Wikipedia](https://en.wikipedia.org/wiki/Hexagon) + * @example hexArea(3) = 23.382685902179844 + * @example hexArea(10) = 259.8076211353316 + */ + +export const hexArea = (side: number): number => { + if (side <= 0) { + throw new TypeError('Invalid Input') + } + + let area = ((3 * (3 ** (1/2)) / 2)) * (side ** 2) + + // Round to nearest integer if close enough due to imprecise float + if (Math.abs(area - Math.round(area)) < 0.000000000000001) { + area = Math.round(area); + } + + return area + } + + + \ No newline at end of file diff --git a/maths/octagon_area.ts b/maths/octagon_area.ts new file mode 100644 index 00000000..1a3cb884 --- /dev/null +++ b/maths/octagon_area.ts @@ -0,0 +1,25 @@ +/** + * @function octArea + * @description Returns area of a regular octagon + * @summary Finds the area of a regular octagon (all 8 sides are equal lenght) + * @param {Number} num - A natural number + * @return {number} The area of a regular octagon + * @see [Wikipedia](https://en.wikipedia.org/wiki/Octagon) + * @example octArea(3) = 43.45584412271571 + * @example octArea(10) = 482.84271247461896 + */ + +export const octArea = (side: number): number => { + if (side <= 0) { + throw new TypeError('Invalid Input') + } + + let area = (2 * (1 + (2 ** (1/2)))) * (side ** 2) + + // Round to nearest integer if close enough due to imprecise float + if (Math.abs(area - Math.round(area)) < 0.000000000000001) { + area = Math.round(area); + } + + return area + } \ No newline at end of file diff --git a/maths/pentagon_area.ts b/maths/pentagon_area.ts new file mode 100644 index 00000000..be0c400b --- /dev/null +++ b/maths/pentagon_area.ts @@ -0,0 +1,25 @@ +/** + * @function pentArea + * @description Returns area of a regular pentagon + * @summary Finds the area of a regular pentagon (all 5 sides are equal lenght) + * @param {Number} num - A natural number + * @return {number} The area of a regular pentagon + * @see [Wikipedia](https://en.wikipedia.org/wiki/Pentagon) + * @example pentArea(1) = 1.72048 + * @example pentArea(8) = 110.11055 + */ + +export const pentArea = (side: number): number => { + if (side <= 0) { + throw new TypeError('Invalid Input') + } + + let area = (1/4) * ((5 * (5 + 2 * (5 ** (1/2)))) ** (1/2)) * (side ** 2) + + // Round to nearest integer if close enough due to imprecise float + if (Math.abs(area - Math.round(area)) < 0.000000000000001) { + area = Math.round(area); + } + + return area + } \ No newline at end of file diff --git a/maths/test/binary_exponentiation.test.ts b/maths/test/binary_exponentiation.test.ts new file mode 100644 index 00000000..5337d7a6 --- /dev/null +++ b/maths/test/binary_exponentiation.test.ts @@ -0,0 +1,29 @@ +import { binaryExponent } from '../binary_exponentiation' + +describe('Tests for HexArea', () => { + it('should be a function', () => { + expect(typeof binaryExponent).toEqual('function') + }) + + it('should throw error for invalid input', () => { + expect(() => binaryExponent([])).toThrow() + }) + + it('should throw error for invalid input', () => { + expect(() => binaryExponent([-1, 1])).toThrow() + }) + + it('should throw error for invalid input', () => { + expect(() => binaryExponent([0])).toThrow() + }) + + it('should return A^B', () => { + const binaryExponentFunction = binaryExponent([1, 0]) + expect(binaryExponentFunction).toBe(1) + }) + + it('should return A^B', () => { + const binaryExponentFunction = binaryExponent([10, 18]) + expect(binaryExponentFunction).toBe(1000000000000000000) + }) +}) \ No newline at end of file diff --git a/maths/test/co_prime.test.ts b/maths/test/co_prime.test.ts new file mode 100644 index 00000000..d8e3bd11 --- /dev/null +++ b/maths/test/co_prime.test.ts @@ -0,0 +1,25 @@ +import { coPrime } from '../co_prime' + +describe('Tests for CoPrime', () => { + it('should be a function', () => { + expect(typeof coPrime).toEqual('function') + }) + + it('should throw error for invalid input', () => { + expect(() => coPrime([1])).toThrow() + }) + + it('should throw error for invalid input (less than 1)', () => { + expect(() => coPrime([1, -3])).toThrow() + }) + + it('should return if two numbers are coprimes', () => { + const coPrimeFunction = coPrime([4, 8]) + expect(coPrimeFunction).toBe(false) + }) + + it('should return if two numbers are coprimes', () => { + const coPrimeFunction = coPrime([9, 16]) + expect(coPrimeFunction).toBe(true) + }) +}) \ No newline at end of file diff --git a/maths/test/geometric_mean.test.ts b/maths/test/geometric_mean.test.ts new file mode 100644 index 00000000..a05fee98 --- /dev/null +++ b/maths/test/geometric_mean.test.ts @@ -0,0 +1,30 @@ +import { geometricMean } from '../geometric_mean' + +describe('Tests for GeometricMean', () => { + it('should be a function', () => { + expect(typeof geometricMean).toEqual('function') + }) + + it('should throw error for invalid input', () => { + expect(() => geometricMean([])).toThrow() + }) + + it('should throw error for invalid input (negative numbers)', () => { + expect(() => geometricMean([1, -3, 4, -7])).toThrow() + }) + + it('should return 0 if 0 is in array', () => { + const meanFunction = geometricMean([4, 8, 16, -3, 0]) + expect(meanFunction).toBe(0) + }) + + it('should return the geometric mean of an array of numbers', () => { + const meanFunction = geometricMean([4, 8, 16]) + expect(meanFunction).toBe(8) + }) + + it('should return the geometric mean of an array of decimal numbers', () => { + const meanFunction = geometricMean([1.2, 3.4, 5]) + expect(meanFunction).toBe(2.7323944160944684) + }) +}) \ No newline at end of file diff --git a/maths/test/hexagon_area.test.ts b/maths/test/hexagon_area.test.ts new file mode 100644 index 00000000..69ac9eac --- /dev/null +++ b/maths/test/hexagon_area.test.ts @@ -0,0 +1,25 @@ +import { hexArea } from '../hexagon_area' + +describe('Tests for HexArea', () => { + it('should be a function', () => { + expect(typeof hexArea).toEqual('function') + }) + + it('should throw error for invalid input', () => { + expect(() => hexArea(0)).toThrow() + }) + + it('should throw error for invalid input', () => { + expect(() => hexArea(-1)).toThrow() + }) + + it('should return if hexagon area', () => { + const hexFunction = hexArea(3) + expect(hexFunction).toBe(23.382685902179844) + }) + + it('should return if hexagon area', () => { + const hexFunction = hexArea(10) + expect(hexFunction).toBe(259.8076211353316) + }) +}) \ No newline at end of file diff --git a/maths/test/octagon_area.test.ts b/maths/test/octagon_area.test.ts new file mode 100644 index 00000000..36510571 --- /dev/null +++ b/maths/test/octagon_area.test.ts @@ -0,0 +1,25 @@ +import { octArea } from '../octagon_area' + +describe('Tests for HexArea', () => { + it('should be a function', () => { + expect(typeof octArea).toEqual('function') + }) + + it('should throw error for invalid input', () => { + expect(() => octArea(0)).toThrow() + }) + + it('should throw error for invalid input', () => { + expect(() => octArea(-1)).toThrow() + }) + + it('should return octagon area', () => { + const octFunction = octArea(3) + expect(octFunction).toBe(43.45584412271571) + }) + + it('should return if octagon area', () => { + const octFunction = octArea(10) + expect(octFunction).toBe(482.84271247461896) + }) +}) \ No newline at end of file diff --git a/maths/test/pentagon_area.test.ts b/maths/test/pentagon_area.test.ts new file mode 100644 index 00000000..e2e73df5 --- /dev/null +++ b/maths/test/pentagon_area.test.ts @@ -0,0 +1,25 @@ +import { pentArea } from '../pentagon_area' + +describe('Tests for HexArea', () => { + it('should be a function', () => { + expect(typeof pentArea).toEqual('function') + }) + + it('should throw error for invalid input', () => { + expect(() => pentArea(0)).toThrow() + }) + + it('should throw error for invalid input', () => { + expect(() => pentArea(-1)).toThrow() + }) + + it('should return if pentagon area', () => { + const pentFunction = pentArea(5) + expect(pentFunction).toBe(43.01193501472417) + }) + + it('should return if pentagon area', () => { + const pentFunction = pentArea(15) + expect(pentFunction).toBe(387.10741513251753) + }) +}) \ No newline at end of file diff --git a/maths/test/triangle_inequality.test.ts b/maths/test/triangle_inequality.test.ts new file mode 100644 index 00000000..8604733a --- /dev/null +++ b/maths/test/triangle_inequality.test.ts @@ -0,0 +1,25 @@ +import { triIneq } from '../triangle_inequality' + +describe('Tests for CoPrime', () => { + it('should be a function', () => { + expect(typeof triIneq).toEqual('function') + }) + + it('should throw error for invalid input', () => { + expect(() => triIneq([1])).toThrow() + }) + + it('should throw error for invalid input (less than 1)', () => { + expect(() => triIneq([1, -3, 4])).toThrow() + }) + + it('should return if valid triangle', () => { + const meanFunction = triIneq([1, 2, 3]) + expect(meanFunction).toBe(true) + }) + + it('should return if valid triangle', () => { + const meanFunction = triIneq([2, 9, 16]) + expect(meanFunction).toBe(false) + }) +}) \ No newline at end of file diff --git a/maths/triangle_inequality.ts b/maths/triangle_inequality.ts new file mode 100644 index 00000000..ab1620e1 --- /dev/null +++ b/maths/triangle_inequality.ts @@ -0,0 +1,34 @@ +/** + * @function triIneq + * @description Returns whether or not a triangle is valid based on the length of three sides + * @summary The sum of two sides of a triangle is always greater than or equal the third side. + * @param {number[]} numbers - Array of 3 natural numbers + * @return {boolean} true if valid triangle, false otherwise + * @see [Wikipedia](https://en.wikipedia.org/wiki/Triangle_inequality) + * @example aliquotSum([1, 2, 3]) = true + * @example aliquotSum([4, 8, 16]) = false + */ + +export const triIneq = (numbers: number[]): boolean => { + if (numbers.length != 3) { + throw new TypeError('Invalid Input') + } + for(let i=0; i < numbers.length; i++){ + if (numbers[i] <= 0) { + throw new TypeError('Invalid Input') + } + } + + if (numbers[0] + numbers[1] < numbers[2]) { + return false + } + if (numbers[2] + numbers[1] < numbers[0]) { + return false + } + if (numbers[0] + numbers[2] < numbers[1]) { + return false + } + + return true; + } + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index ad263744..a358efc2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,12 +9,14 @@ "version": "1.0.0", "license": "MIT", "devDependencies": { - "@types/jest": "^29.0.3", + "@types/jest": "^29.5.13", + "@types/node": "^22.7.4", "husky": "^8.0.1", "jest": "^29.0.3", "prettier": "^3.2.5", "ts-jest": "^29.0.2", - "ts-node": "^10.9.1" + "ts-node": "^10.9.1", + "typescript": "^5.6.2" } }, "node_modules/@ampproject/remapping": { @@ -1091,9 +1093,9 @@ } }, "node_modules/@types/jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.0.3.tgz", - "integrity": "sha512-F6ukyCTwbfsEX5F2YmVYmM5TcTHy1q9P5rWlRbrk56KyMh3v9xRGUO3aa8+SkvMi0SHXtASJv1283enXimC0Og==", + "version": "29.5.13", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.13.tgz", + "integrity": "sha512-wd+MVEZCHt23V0/L642O5APvspWply/rGY5BcW4SUETo2UzPU3Z26qr8jC2qxpimI2jjx9h7+2cj2FwIr01bXg==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -1101,10 +1103,13 @@ } }, "node_modules/@types/node": { - "version": "18.7.23", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", - "integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==", - "dev": true + "version": "22.7.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz", + "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==", + "dev": true, + "dependencies": { + "undici-types": "~6.19.2" + } }, "node_modules/@types/prettier": { "version": "2.7.1", @@ -3531,19 +3536,24 @@ } }, "node_modules/typescript": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", - "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", "dev": true, - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true + }, "node_modules/update-browserslist-db": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", @@ -4571,9 +4581,9 @@ } }, "@types/jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.0.3.tgz", - "integrity": "sha512-F6ukyCTwbfsEX5F2YmVYmM5TcTHy1q9P5rWlRbrk56KyMh3v9xRGUO3aa8+SkvMi0SHXtASJv1283enXimC0Og==", + "version": "29.5.13", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.13.tgz", + "integrity": "sha512-wd+MVEZCHt23V0/L642O5APvspWply/rGY5BcW4SUETo2UzPU3Z26qr8jC2qxpimI2jjx9h7+2cj2FwIr01bXg==", "dev": true, "requires": { "expect": "^29.0.0", @@ -4581,10 +4591,13 @@ } }, "@types/node": { - "version": "18.7.23", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", - "integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==", - "dev": true + "version": "22.7.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz", + "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==", + "dev": true, + "requires": { + "undici-types": "~6.19.2" + } }, "@types/prettier": { "version": "2.7.1", @@ -6360,11 +6373,16 @@ "dev": true }, "typescript": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", - "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", - "dev": true, - "peer": true + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "dev": true + }, + "undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true }, "update-browserslist-db": { "version": "1.0.9", diff --git a/package.json b/package.json index b45ab4ea..4f9bed2f 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,17 @@ { "name": "typescript", "version": "1.0.0", - "type": "module", "description": "A repository for All algorithms implemented in Typescript (for educational purposes only)", "main": "", "devDependencies": { - "@types/jest": "^29.0.3", + "@types/jest": "^29.5.13", + "@types/node": "^22.7.4", "husky": "^8.0.1", "jest": "^29.0.3", "prettier": "^3.2.5", "ts-jest": "^29.0.2", - "ts-node": "^10.9.1" + "ts-node": "^10.9.1", + "typescript": "^5.6.2" }, "scripts": { "test": "jest --no-cache",