mirror of
https://github.com/TheAlgorithms/JavaScript.git
synced 2025-07-05 00:01:37 +08:00
merge: Decimal Expansion (#787)
* Add Math function for representing the decimal expansion of a given fraction (decimal or any base from 2 to 10). * Auto-update DIRECTORY.md * DecimalExpansion Jest tests. * chore: trigger update * Auto-update DIRECTORY.md * Auto-update DIRECTORY.md * chore: trigger checks Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: Rak Laptudirm <rak@laptudirm.com> Co-authored-by: Rak Laptudirm <raklaptudirm@gmail.com>
This commit is contained in:
@ -18,6 +18,8 @@
|
|||||||
* [LFUCache](https://github.com/TheAlgorithms/Javascript/blob/master/Cache/LFUCache.js)
|
* [LFUCache](https://github.com/TheAlgorithms/Javascript/blob/master/Cache/LFUCache.js)
|
||||||
* [LRUCache](https://github.com/TheAlgorithms/Javascript/blob/master/Cache/LRUCache.js)
|
* [LRUCache](https://github.com/TheAlgorithms/Javascript/blob/master/Cache/LRUCache.js)
|
||||||
* [Memoize](https://github.com/TheAlgorithms/Javascript/blob/master/Cache/Memoize.js)
|
* [Memoize](https://github.com/TheAlgorithms/Javascript/blob/master/Cache/Memoize.js)
|
||||||
|
* test
|
||||||
|
* [cacheTest](https://github.com/TheAlgorithms/Javascript/blob/master/Cache/test/cacheTest.js)
|
||||||
|
|
||||||
## Cellular-Automata
|
## Cellular-Automata
|
||||||
* [ConwaysGameOfLife](https://github.com/TheAlgorithms/Javascript/blob/master/Cellular-Automata/ConwaysGameOfLife.js)
|
* [ConwaysGameOfLife](https://github.com/TheAlgorithms/Javascript/blob/master/Cellular-Automata/ConwaysGameOfLife.js)
|
||||||
@ -65,11 +67,13 @@
|
|||||||
* Graph
|
* Graph
|
||||||
* [Graph](https://github.com/TheAlgorithms/Javascript/blob/master/Data-Structures/Graph/Graph.js)
|
* [Graph](https://github.com/TheAlgorithms/Javascript/blob/master/Data-Structures/Graph/Graph.js)
|
||||||
* [Graph2](https://github.com/TheAlgorithms/Javascript/blob/master/Data-Structures/Graph/Graph2.js)
|
* [Graph2](https://github.com/TheAlgorithms/Javascript/blob/master/Data-Structures/Graph/Graph2.js)
|
||||||
|
* [Graph3](https://github.com/TheAlgorithms/Javascript/blob/master/Data-Structures/Graph/Graph3.js)
|
||||||
* Heap
|
* Heap
|
||||||
* [MaxHeap](https://github.com/TheAlgorithms/Javascript/blob/master/Data-Structures/Heap/MaxHeap.js)
|
* [MaxHeap](https://github.com/TheAlgorithms/Javascript/blob/master/Data-Structures/Heap/MaxHeap.js)
|
||||||
* [MinHeap](https://github.com/TheAlgorithms/Javascript/blob/master/Data-Structures/Heap/MinHeap.js)
|
* [MinHeap](https://github.com/TheAlgorithms/Javascript/blob/master/Data-Structures/Heap/MinHeap.js)
|
||||||
* [MinPriorityQueue](https://github.com/TheAlgorithms/Javascript/blob/master/Data-Structures/Heap/MinPriorityQueue.js)
|
* [MinPriorityQueue](https://github.com/TheAlgorithms/Javascript/blob/master/Data-Structures/Heap/MinPriorityQueue.js)
|
||||||
* Linked-List
|
* Linked-List
|
||||||
|
* [AddTwoNumbers](https://github.com/TheAlgorithms/Javascript/blob/master/Data-Structures/Linked-List/AddTwoNumbers.js)
|
||||||
* [CycleDetection](https://github.com/TheAlgorithms/Javascript/blob/master/Data-Structures/Linked-List/CycleDetection.js)
|
* [CycleDetection](https://github.com/TheAlgorithms/Javascript/blob/master/Data-Structures/Linked-List/CycleDetection.js)
|
||||||
* [DoublyLinkedList](https://github.com/TheAlgorithms/Javascript/blob/master/Data-Structures/Linked-List/DoublyLinkedList.js)
|
* [DoublyLinkedList](https://github.com/TheAlgorithms/Javascript/blob/master/Data-Structures/Linked-List/DoublyLinkedList.js)
|
||||||
* [RotateListRight](https://github.com/TheAlgorithms/Javascript/blob/master/Data-Structures/Linked-List/RotateListRight.js)
|
* [RotateListRight](https://github.com/TheAlgorithms/Javascript/blob/master/Data-Structures/Linked-List/RotateListRight.js)
|
||||||
@ -143,6 +147,7 @@
|
|||||||
* [Abs](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/Abs.js)
|
* [Abs](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/Abs.js)
|
||||||
* [AliquotSum](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/AliquotSum.js)
|
* [AliquotSum](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/AliquotSum.js)
|
||||||
* [Area](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/Area.js)
|
* [Area](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/Area.js)
|
||||||
|
* [ArithmeticGeometricMean](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/ArithmeticGeometricMean.js)
|
||||||
* [ArmstrongNumber](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/ArmstrongNumber.js)
|
* [ArmstrongNumber](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/ArmstrongNumber.js)
|
||||||
* [AverageMean](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/AverageMean.js)
|
* [AverageMean](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/AverageMean.js)
|
||||||
* [AverageMedian](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/AverageMedian.js)
|
* [AverageMedian](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/AverageMedian.js)
|
||||||
@ -153,6 +158,7 @@
|
|||||||
* [CheckKishnamurthyNumber](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/CheckKishnamurthyNumber.js)
|
* [CheckKishnamurthyNumber](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/CheckKishnamurthyNumber.js)
|
||||||
* [Coordinate](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/Coordinate.js)
|
* [Coordinate](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/Coordinate.js)
|
||||||
* [CoPrimeCheck](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/CoPrimeCheck.js)
|
* [CoPrimeCheck](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/CoPrimeCheck.js)
|
||||||
|
* [DecimalExpansion](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/DecimalExpansion.js)
|
||||||
* [DecimalIsolate](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/DecimalIsolate.js)
|
* [DecimalIsolate](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/DecimalIsolate.js)
|
||||||
* [DegreeToRadian](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/DegreeToRadian.js)
|
* [DegreeToRadian](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/DegreeToRadian.js)
|
||||||
* [EulerMethod](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/EulerMethod.js)
|
* [EulerMethod](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/EulerMethod.js)
|
||||||
@ -168,6 +174,7 @@
|
|||||||
* [FindHcf](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/FindHcf.js)
|
* [FindHcf](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/FindHcf.js)
|
||||||
* [FindLcm](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/FindLcm.js)
|
* [FindLcm](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/FindLcm.js)
|
||||||
* [FindMin](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/FindMin.js)
|
* [FindMin](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/FindMin.js)
|
||||||
|
* [FindMinIterator](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/FindMinIterator.js)
|
||||||
* [GetEuclidGCD](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/GetEuclidGCD.js)
|
* [GetEuclidGCD](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/GetEuclidGCD.js)
|
||||||
* [GridGet](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/GridGet.js)
|
* [GridGet](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/GridGet.js)
|
||||||
* [IsDivisible](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/IsDivisible.js)
|
* [IsDivisible](https://github.com/TheAlgorithms/Javascript/blob/master/Maths/IsDivisible.js)
|
||||||
@ -290,6 +297,7 @@
|
|||||||
* [AlternativeStringArrange](https://github.com/TheAlgorithms/Javascript/blob/master/String/AlternativeStringArrange.js)
|
* [AlternativeStringArrange](https://github.com/TheAlgorithms/Javascript/blob/master/String/AlternativeStringArrange.js)
|
||||||
* [CheckAnagram](https://github.com/TheAlgorithms/Javascript/blob/master/String/CheckAnagram.js)
|
* [CheckAnagram](https://github.com/TheAlgorithms/Javascript/blob/master/String/CheckAnagram.js)
|
||||||
* [CheckCamelCase](https://github.com/TheAlgorithms/Javascript/blob/master/String/CheckCamelCase.js)
|
* [CheckCamelCase](https://github.com/TheAlgorithms/Javascript/blob/master/String/CheckCamelCase.js)
|
||||||
|
* [CheckExceeding](https://github.com/TheAlgorithms/Javascript/blob/master/String/CheckExceeding.js)
|
||||||
* [CheckFlatCase](https://github.com/TheAlgorithms/Javascript/blob/master/String/CheckFlatCase.js)
|
* [CheckFlatCase](https://github.com/TheAlgorithms/Javascript/blob/master/String/CheckFlatCase.js)
|
||||||
* [CheckKebabCase](https://github.com/TheAlgorithms/Javascript/blob/master/String/CheckKebabCase.js)
|
* [CheckKebabCase](https://github.com/TheAlgorithms/Javascript/blob/master/String/CheckKebabCase.js)
|
||||||
* [CheckPalindrome](https://github.com/TheAlgorithms/Javascript/blob/master/String/CheckPalindrome.js)
|
* [CheckPalindrome](https://github.com/TheAlgorithms/Javascript/blob/master/String/CheckPalindrome.js)
|
||||||
|
67
Maths/DecimalExpansion.js
Normal file
67
Maths/DecimalExpansion.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* @author Eric Lavault <https://github.com/lvlte>
|
||||||
|
*
|
||||||
|
* Represents the decimal (or binary, octal, any base from 2 to 10) expansion
|
||||||
|
* of a/b using euclidean division.
|
||||||
|
*
|
||||||
|
* Because this function is recursive, it may throw an error when reaching the
|
||||||
|
* maximum call stack size.
|
||||||
|
*
|
||||||
|
* Returns an array containing : [
|
||||||
|
* 0: integer part of the division
|
||||||
|
* 1: array of decimals (if any, or an empty array)
|
||||||
|
* 2: indexOf 1st cycle digit in decimals array if a/b is periodic, or undef.
|
||||||
|
* ]
|
||||||
|
*
|
||||||
|
* @see https://mathworld.wolfram.com/DecimalExpansion.html
|
||||||
|
*
|
||||||
|
* @param {number} a
|
||||||
|
* @param {number} b
|
||||||
|
* @param {number} [base=10]
|
||||||
|
* @returns {array}
|
||||||
|
*/
|
||||||
|
export function decExp (a, b, base = 10, exp = [], d = {}, dlen = 0) {
|
||||||
|
if (base < 2 || base > 10) {
|
||||||
|
throw new RangeError('Unsupported base. Must be in range [2, 10]')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a === 0) {
|
||||||
|
return [0, [], undefined]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a === b && dlen === 0) {
|
||||||
|
return [1, [], undefined]
|
||||||
|
}
|
||||||
|
|
||||||
|
// d contains the dividends used so far and the corresponding index of its
|
||||||
|
// euclidean division by b in the expansion array.
|
||||||
|
d[a] = dlen++
|
||||||
|
|
||||||
|
if (a < b) {
|
||||||
|
exp.push(0)
|
||||||
|
return decExp(a * base, b, base, exp, d, dlen)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Euclid's division lemma : a = bq + r
|
||||||
|
const r = a % b
|
||||||
|
const q = (a - r) / b
|
||||||
|
|
||||||
|
// Decimal expansion (1st element is the integer part)
|
||||||
|
exp.push(+q.toString(base))
|
||||||
|
|
||||||
|
if (r === 0) {
|
||||||
|
// got a regular number (division terminates)
|
||||||
|
return [exp[0], exp.slice(1), undefined]
|
||||||
|
}
|
||||||
|
|
||||||
|
// For the next iteration
|
||||||
|
a = r * base
|
||||||
|
|
||||||
|
// Check if `a` has already been used as a dividend, in which case it means
|
||||||
|
// the expansion is periodic.
|
||||||
|
if (a in d) {
|
||||||
|
return [exp[0], exp.slice(1), d[a] - 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return decExp(a, b, base, exp, d, dlen)
|
||||||
|
}
|
192
Maths/test/DecimalExpansion.test.js
Normal file
192
Maths/test/DecimalExpansion.test.js
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
import { decExp } from '../DecimalExpansion'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decimal
|
||||||
|
*/
|
||||||
|
|
||||||
|
describe('Finite Decimal Expansion', () => {
|
||||||
|
it('1/2 = 0.5', () => {
|
||||||
|
const [integer, decimals, cycleIndex] = decExp(1, 2)
|
||||||
|
expect(integer).toBe(0)
|
||||||
|
expect(decimals).toEqual([5])
|
||||||
|
expect(cycleIndex).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('1/5 = 0.2', () => {
|
||||||
|
const [integer, decimals, cycleIndex] = decExp(1, 5)
|
||||||
|
expect(integer).toBe(0)
|
||||||
|
expect(decimals).toEqual([2])
|
||||||
|
expect(cycleIndex).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('1/8 = 0.125', () => {
|
||||||
|
const [integer, decimals, cycleIndex] = decExp(1, 8)
|
||||||
|
expect(integer).toBe(0)
|
||||||
|
expect(decimals).toEqual([1, 2, 5])
|
||||||
|
expect(cycleIndex).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('255/40 = 6.375', () => {
|
||||||
|
const [integer, decimals, cycleIndex] = decExp(255, 40)
|
||||||
|
expect(integer).toBe(6)
|
||||||
|
expect(decimals).toEqual([3, 7, 5])
|
||||||
|
expect(cycleIndex).toBeUndefined()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Repeating Decimal Expansion', () => {
|
||||||
|
it('1/3 = 0.(3)', () => {
|
||||||
|
expect(decExp(1, 3)).toStrictEqual([0, [3], 0])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('1/6 = 0.1(6)', () => {
|
||||||
|
expect(decExp(1, 6)).toStrictEqual([0, [1, 6], 1])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('1/7 = 0.(142857)', () => {
|
||||||
|
expect(decExp(1, 7)).toStrictEqual([0, [1, 4, 2, 8, 5, 7], 0])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binary
|
||||||
|
*/
|
||||||
|
|
||||||
|
describe('Finite Binary Expansion', () => {
|
||||||
|
it('1/2 = 0.1₂', () => {
|
||||||
|
const [integer, decimals, cycleIndex] = decExp(1, 2, 2)
|
||||||
|
expect(integer).toBe(0)
|
||||||
|
expect(decimals).toEqual([1])
|
||||||
|
expect(cycleIndex).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('1/8 = 0.001₂', () => {
|
||||||
|
const [integer, decimals, cycleIndex] = decExp(1, 8, 2)
|
||||||
|
expect(integer).toBe(0)
|
||||||
|
expect(decimals).toEqual([0, 0, 1])
|
||||||
|
expect(cycleIndex).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('255/40 = 110.011₂', () => {
|
||||||
|
const [integer, decimals, cycleIndex] = decExp(255, 40, 2)
|
||||||
|
expect(integer).toBe(110)
|
||||||
|
expect(decimals).toEqual([0, 1, 1])
|
||||||
|
expect(cycleIndex).toBeUndefined()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Repeating Binary Expansion', () => {
|
||||||
|
it('1/3 = 0.(01)₂', () => {
|
||||||
|
expect(decExp(1, 3, 2)).toStrictEqual([0, [0, 1], 0])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('1/5 = 0.(0011)₂', () => {
|
||||||
|
expect(decExp(1, 5, 2)).toStrictEqual([0, [0, 0, 1, 1], 0])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('1/6 = 0.0(01)₂', () => {
|
||||||
|
expect(decExp(1, 6, 2)).toStrictEqual([0, [0, 0, 1], 1])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('1/7 = 0.(001)₂', () => {
|
||||||
|
expect(decExp(1, 7, 2)).toStrictEqual([0, [0, 0, 1], 0])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Octal
|
||||||
|
*/
|
||||||
|
|
||||||
|
describe('Finite Octal Expansion', () => {
|
||||||
|
it('1/2 = 0.4₈', () => {
|
||||||
|
const [integer, decimals, cycleIndex] = decExp(1, 2, 8)
|
||||||
|
expect(integer).toBe(0)
|
||||||
|
expect(decimals).toEqual([4])
|
||||||
|
expect(cycleIndex).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('1/8 = 0.1₈', () => {
|
||||||
|
const [integer, decimals, cycleIndex] = decExp(1, 8, 8)
|
||||||
|
expect(integer).toBe(0)
|
||||||
|
expect(decimals).toEqual([1])
|
||||||
|
expect(cycleIndex).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('255/40 = 6.3₈', () => {
|
||||||
|
const [integer, decimals, cycleIndex] = decExp(255, 40, 8)
|
||||||
|
expect(integer).toBe(6)
|
||||||
|
expect(decimals).toEqual([3])
|
||||||
|
expect(cycleIndex).toBeUndefined()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Repeating Octal Expansion', () => {
|
||||||
|
it('1/3 = 0.(25)₈', () => {
|
||||||
|
expect(decExp(1, 3, 8)).toStrictEqual([0, [2, 5], 0])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('1/5 = 0.(1463)₈', () => {
|
||||||
|
expect(decExp(1, 5, 8)).toStrictEqual([0, [1, 4, 6, 3], 0])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('1/6 = 0.1(25)₈', () => {
|
||||||
|
expect(decExp(1, 6, 8)).toStrictEqual([0, [1, 2, 5], 1])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('1/7 = 0.(1)₈', () => {
|
||||||
|
expect(decExp(1, 7, 8)).toStrictEqual([0, [1], 0])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integers
|
||||||
|
*/
|
||||||
|
|
||||||
|
describe('Integers', () => {
|
||||||
|
it('1/1 = 1', () => {
|
||||||
|
const [integer, decimals, cycleIndex] = decExp(1, 1)
|
||||||
|
expect(integer).toBe(1)
|
||||||
|
expect(decimals).toStrictEqual([])
|
||||||
|
expect(cycleIndex).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('5/5 = 1', () => {
|
||||||
|
const [integer, decimals, cycleIndex] = decExp(5, 5)
|
||||||
|
expect(integer).toBe(1)
|
||||||
|
expect(decimals).toStrictEqual([])
|
||||||
|
expect(cycleIndex).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('2/1 = 2', () => {
|
||||||
|
const [integer, decimals, cycleIndex] = decExp(2, 1)
|
||||||
|
expect(integer).toBe(2)
|
||||||
|
expect(decimals).toStrictEqual([])
|
||||||
|
expect(cycleIndex).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('9/3 = 3', () => {
|
||||||
|
const [integer, decimals, cycleIndex] = decExp(9, 3)
|
||||||
|
expect(integer).toBe(3)
|
||||||
|
expect(decimals).toStrictEqual([])
|
||||||
|
expect(cycleIndex).toBeUndefined()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsupported base
|
||||||
|
*/
|
||||||
|
|
||||||
|
describe('Throws on unsupported base', () => {
|
||||||
|
it('negative base', () => {
|
||||||
|
expect(() => decExp(1, 1, -2)).toThrow(RangeError)
|
||||||
|
})
|
||||||
|
it('base 0', () => {
|
||||||
|
expect(() => decExp(1, 1, 0)).toThrow(RangeError)
|
||||||
|
})
|
||||||
|
it('base 1', () => {
|
||||||
|
expect(() => decExp(1, 1, 1)).toThrow(RangeError)
|
||||||
|
})
|
||||||
|
it('base 11', () => {
|
||||||
|
expect(() => decExp(1, 1, 11)).toThrow(RangeError)
|
||||||
|
})
|
||||||
|
})
|
Reference in New Issue
Block a user