-
-
Notifications
You must be signed in to change notification settings - Fork 348
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New math functions #253
base: master
Are you sure you want to change the base?
New math functions #253
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just take two numbers, |
||
* @return {number} A^B | ||
* @see [Wikipedia](https://cp-algorithms.com/algebra/binary-exp.html) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's not Wikipedia. |
||
* @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') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This becomes obsolete if you fix the signature. |
||
} | ||
for(let i=0; i < numbers.length; i++){ | ||
if (numbers[i] < 0 || !Number.isInteger(numbers[i])) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The base can very well be negative. You could also support negative exponents but you don't have to. |
||
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)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be a recursive call instead. |
||
// if B is even or odd | ||
if (numbers[1] % 2 === 1) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could also use |
||
return res * res * numbers[0]; | ||
} | ||
else { | ||
return res * res; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again just take two parameters instead. You can still pack them up in an array of two items when it is convenient to do so. |
||
* @return {boolean} - Whether the given two number are coprimes | ||
* @see https://en.wikipedia.org/wiki/Coprime_integers | ||
* @example isPrime(2, 3) = 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not |
||
* @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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just reuse |
||
for (let i = 2; i <= Math.sqrt(numbers[0]); i++) { | ||
if (numbers[0] % i === 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Inconsistent formatting |
||
factors0.push(i) | ||
} | ||
} | ||
for (let i = 2; i <= Math.sqrt(numbers[1]); i++) { | ||
if (numbers[1] % i === 0) { | ||
factors1.push(i) | ||
} | ||
} | ||
console.log(factors0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please don't leave such remnants here. |
||
console.log(factors1) | ||
|
||
// check if same factors | ||
for (let i = 0; i <= factors0.length; i++) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could be optimized e.g. by doing a sorted merge instead. This is O(nm) but could be O(n + m). Not really necessary since the factorization is more expensive though (which should be noted however). |
||
if (factors1.includes(factors0[i])) { | ||
return false | ||
} | ||
} | ||
|
||
// if the entire loop runs without finding a similar factor, return true | ||
return true | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,29 @@ | ||||||
import { binaryExponent } from '../binary_exponentiation' | ||||||
|
||||||
describe('Tests for HexArea', () => { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
it('should be a function', () => { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is unnecessary. |
||||||
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) | ||||||
}) | ||||||
}) |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,25 @@ | ||||||
import { coPrime } from '../co_prime' | ||||||
|
||||||
describe('Tests for CoPrime', () => { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
it('should be a function', () => { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. |
||||||
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) | ||||||
}) | ||||||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
}) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
}) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
}) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
}) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.