Skip to content
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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions maths/binary_exponentiation.ts
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @summary Binary exponentiation calculatoes A^B in logarithmic time of B instead of linear time
* @summary Binary exponentiation calculates A^B in time O(log B) instead of O(B)

* @param {Number} num - An array of two natural numbers, [A, B], where A^B will be solved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just take two numbers, base and exponent, as parameters instead.

* @return {number} A^B
* @see [Wikipedia](https://cp-algorithms.com/algebra/binary-exp.html)
Copy link
Contributor

Choose a reason for hiding this comment

The 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')
Copy link
Contributor

Choose a reason for hiding this comment

The 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])) {
Copy link
Contributor

Choose a reason for hiding this comment

The 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));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a recursive call instead. Math.floor(x / 2) is more elegantly (and possibly efficiently) expressed as x >> 1.

// if B is even or odd
if (numbers[1] % 2 === 1) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could also use & 1 instead of % 2

return res * res * numbers[0];
}
else {
return res * res;
}
}
51 changes: 51 additions & 0 deletions maths/co_prime.ts
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).
Copy link
Contributor

Choose a reason for hiding this comment

The 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not isPrime

* @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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just reuse factors.ts

for (let i = 2; i <= Math.sqrt(numbers[0]); i++) {
if (numbers[0] % i === 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The 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)
Copy link
Contributor

Choose a reason for hiding this comment

The 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++) {
Copy link
Contributor

Choose a reason for hiding this comment

The 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
}
39 changes: 39 additions & 0 deletions maths/geometric_mean.ts
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;
}
28 changes: 28 additions & 0 deletions maths/hexagon_area.ts
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
}



25 changes: 25 additions & 0 deletions maths/octagon_area.ts
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
}
25 changes: 25 additions & 0 deletions maths/pentagon_area.ts
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
}
29 changes: 29 additions & 0 deletions maths/test/binary_exponentiation.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { binaryExponent } from '../binary_exponentiation'

describe('Tests for HexArea', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
describe('Tests for HexArea', () => {
describe('HexArea', () => {

it('should be a function', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The 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)
})
})
25 changes: 25 additions & 0 deletions maths/test/co_prime.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { coPrime } from '../co_prime'

describe('Tests for CoPrime', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
describe('Tests for CoPrime', () => {
describe('CoPrime', () => {

it('should be a function', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The 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)
})
})
30 changes: 30 additions & 0 deletions maths/test/geometric_mean.test.ts
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)
})
})
25 changes: 25 additions & 0 deletions maths/test/hexagon_area.test.ts
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)
})
})
25 changes: 25 additions & 0 deletions maths/test/octagon_area.test.ts
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)
})
})
25 changes: 25 additions & 0 deletions maths/test/pentagon_area.test.ts
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)
})
})
Loading
Loading