From 827906c1401a2842575f4d602875b0b4f563507f Mon Sep 17 00:00:00 2001 From: Anmol Gomra <50433033+pineapple45@users.noreply.github.com> Date: Thu, 10 Dec 2020 22:24:11 +0530 Subject: [PATCH] added prime-factors algo in src/algorithms/math (#532) --- README.md | 1 + src/algorithms/math/prime-factors/README.md | 34 ++++++++++++++ .../__test__/primefactors.test.js | 40 +++++++++++++++++ .../math/prime-factors/primefactors.js | 44 +++++++++++++++++++ 4 files changed, 119 insertions(+) create mode 100644 src/algorithms/math/prime-factors/README.md create mode 100644 src/algorithms/math/prime-factors/__test__/primefactors.test.js create mode 100644 src/algorithms/math/prime-factors/primefactors.js diff --git a/README.md b/README.md index 98d5c43c5e..3008a6abda 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ a set of rules that precisely define a sequence of operations. * `B` [Bit Manipulation](src/algorithms/math/bits) - set/get/update/clear bits, multiplication/division by two, make negative etc. * `B` [Factorial](src/algorithms/math/factorial) * `B` [Fibonacci Number](src/algorithms/math/fibonacci) - classic and closed-form versions + * `B` [Prime Factors](src/algorithms/math/prime-factors) - finding distinct prime-factor count using both accurate & Hardy-Ramanujan's Algorithm * `B` [Primality Test](src/algorithms/math/primality-test) (trial division method) * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD) * `B` [Least Common Multiple](src/algorithms/math/least-common-multiple) (LCM) diff --git a/src/algorithms/math/prime-factors/README.md b/src/algorithms/math/prime-factors/README.md new file mode 100644 index 0000000000..6b855d37d7 --- /dev/null +++ b/src/algorithms/math/prime-factors/README.md @@ -0,0 +1,34 @@ +# Prime Factors + +Prime factors are basically those prime numbers which multiply together to give the orignal number. For ex: 39 will have prime factors as 3 and 13 which are also prime numbers. Another example is 15 whose prime factors are 3 and 5. + +#### Method for finding the prime factors and their count accurately + +The approach is to basically keep on dividing the natural number 'n' by indexes from i = 2 to i = n by prime indexes only. This is ensured by an 'if' check. Then value of 'n' keeps on overriding by (n/i). +The time complexity till now is O(n) in worst case since the loop run from index i = 2 to i = n even when no index 'i' is left to be divided by 'n' other than n itself. This time complexity can be reduced to O(sqrt(n)) from O(n). This optimisation is acheivable when loop is ran from i = 2 to i = sqrt(n). Now, we go only till O(sqrt(n)) because when 'i' becomes greater than sqrt(n), we now have the confirmation there is no index 'i' left which can divide 'n' completely other than n itself. + +##### Optimised Time Complexity: O(sqrt(n)) + + +#### Hardy-Ramanujan formula for approximate calculation of prime-factor count + +In 1917, a theorem was formulated by G.H Hardy and Srinivasa Ramanujan which approximately tells the total count of distinct prime factors of most 'n' natural numbers. +The fomula is given by ln(ln(n)). + +#### Code Explaiation + +There are on 4 functions used: + +- getPrimeFactors : returns array containing all distinct prime factors for given input n. + +- getPrimeFactorsCount: returns accurate total count of distinct prime factors of given input n. + +- hardyRamanujanApprox: returns approximate total count of distinct prime factors of given input n using Hardy-Ramanujan formula. + +- errorPercent : returns %age of error in approximation using formula to that of accurate result. The formula used is: **[Modulus(accurate_val - approximate_val) / accurate_val ] * 100**. This shows deviation from accurate result. + + +## References + +- [Youtube](https://www.youtube.com/watch?v=6PDtgHhpCHo) +- [Wikipedia](https://en.wikipedia.org/wiki/Hardy%E2%80%93Ramanujan_theorem) \ No newline at end of file diff --git a/src/algorithms/math/prime-factors/__test__/primefactors.test.js b/src/algorithms/math/prime-factors/__test__/primefactors.test.js new file mode 100644 index 0000000000..7a1ba96377 --- /dev/null +++ b/src/algorithms/math/prime-factors/__test__/primefactors.test.js @@ -0,0 +1,40 @@ +import primefactors from '../primefactors'; + +describe('prime-factors', () => { + it('should give prime factors', () => { + expect(primefactors.getPrimeFactors(510510)).toEqual([2, 3, 5, 7, 11, 13, 17]); + expect(primefactors.getPrimeFactors(343434)).toEqual([2, 3, 7, 13, 17, 37]); + expect(primefactors.getPrimeFactors(456745)).toEqual([5, 167, 547]); + expect(primefactors.getPrimeFactors(8735463)).toEqual([3, 11, 88237]); + expect(primefactors.getPrimeFactors(873452453)).toEqual([149, 1637, 3581]); + expect(primefactors.getPrimeFactors(52734)).toEqual([2, 3, 11, 17, 47]); + }); + + it('should give prime factors count accurately', () => { + expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(510510))).toEqual(7); + expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(343434))).toEqual(6); + expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(456745))).toEqual(3); + expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(8735463))).toEqual(3); + expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(873452453))).toEqual(3); + expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(52734))).toEqual(5); + }); + + it('should give prime factors count approximately using Hardy-Ramanujan-Approx', () => { + expect(primefactors.hardyRamanujanApprox(510510)).toBeCloseTo(2.5759018900,5); + expect(primefactors.hardyRamanujanApprox(343434)).toBeCloseTo(2.54527635538,5); + expect(primefactors.hardyRamanujanApprox(456745)).toBeCloseTo(2.5673987036,5); + expect(primefactors.hardyRamanujanApprox(8735463)).toBeCloseTo(2.771519494900,5); + expect(primefactors.hardyRamanujanApprox(873452453)).toBeCloseTo(3.0247066455016,5); + expect(primefactors.hardyRamanujanApprox(52734)).toBeCloseTo(2.386284094835,5); + }); + + it('should give error percentage of deviation of Hardy-Ramanujan-Approx prime-factors count from accurate prime-factors count', () => { + expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(510510)),primefactors.hardyRamanujanApprox(510510))).toBeCloseTo(63.20140157059997,5); + expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(343434)),primefactors.hardyRamanujanApprox(343434))).toBeCloseTo(57.5787274,5); + expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(456745)),primefactors.hardyRamanujanApprox(456745))).toBeCloseTo(14.420043212851,5); + expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(8735463)),primefactors.hardyRamanujanApprox(8735463))).toBeCloseTo(7.61601683663378,5); + expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(873452453)),primefactors.hardyRamanujanApprox(873452453))).toBeCloseTo(0.8235548500,5); + expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(52734)),primefactors.hardyRamanujanApprox(52734))).toBeCloseTo(52.27431810328,5); + }); +}); + diff --git a/src/algorithms/math/prime-factors/primefactors.js b/src/algorithms/math/prime-factors/primefactors.js new file mode 100644 index 0000000000..d951a37153 --- /dev/null +++ b/src/algorithms/math/prime-factors/primefactors.js @@ -0,0 +1,44 @@ +export default { + + getPrimeFactors : (n) => { + let factorsArray = []; // an array where all the prime factors will be stored + + //over here optimisation is made by running loop till sqrt(n) instead of n + for (let i = 2 ; i <= Math.sqrt(n); i++){ + if(n % i === 0){ // if check to ensure i completely divides n + let count = 0; // This count keeps track of number of times i divides n + while(n % i === 0){ + n = n/i; // override the value of n + count++; // count value updated + } + factorsArray.push(i); // array gets populated + } + } + if(n !== 1){ // finally we cannot push 1 to array since it cannot be a prime-factor + factorsArray.push(n); + } + + return factorsArray; + }, + + //returns accurate prime-factors count + getPrimeFactorsCount : (factorsArray) => { + return factorsArray.length; + }, + + + //returns Hardy-Ramanujan Approximation of prime-factors count + hardyRamanujanApprox : (n) => { + return Math.log(Math.log(n)); + }, + + //returns %age of error in approximation using formula to that of accurate result. + errorPercent : (exactFactorCount,approximateFactorCount) => { + let diff = exactFactorCount-approximateFactorCount > 0 ? exactFactorCount-approximateFactorCount: -(exactFactorCount-approximateFactorCount); + return (diff/exactFactorCount * 100); + } + + +} + +