Skip to content

Commit 827906c

Browse files
authored
added prime-factors algo in src/algorithms/math (trekhleb#532)
1 parent 498ab10 commit 827906c

File tree

4 files changed

+119
-0
lines changed

4 files changed

+119
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ a set of rules that precisely define a sequence of operations.
6666
* `B` [Bit Manipulation](src/algorithms/math/bits) - set/get/update/clear bits, multiplication/division by two, make negative etc.
6767
* `B` [Factorial](src/algorithms/math/factorial)
6868
* `B` [Fibonacci Number](src/algorithms/math/fibonacci) - classic and closed-form versions
69+
* `B` [Prime Factors](src/algorithms/math/prime-factors) - finding distinct prime-factor count using both accurate & Hardy-Ramanujan's Algorithm
6970
* `B` [Primality Test](src/algorithms/math/primality-test) (trial division method)
7071
* `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD)
7172
* `B` [Least Common Multiple](src/algorithms/math/least-common-multiple) (LCM)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Prime Factors
2+
3+
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.
4+
5+
#### Method for finding the prime factors and their count accurately
6+
7+
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).
8+
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.
9+
10+
##### Optimised Time Complexity: O(sqrt(n))
11+
12+
13+
#### Hardy-Ramanujan formula for approximate calculation of prime-factor count
14+
15+
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.
16+
The fomula is given by ln(ln(n)).
17+
18+
#### Code Explaiation
19+
20+
There are on 4 functions used:
21+
22+
- getPrimeFactors : returns array containing all distinct prime factors for given input n.
23+
24+
- getPrimeFactorsCount: returns accurate total count of distinct prime factors of given input n.
25+
26+
- hardyRamanujanApprox: returns approximate total count of distinct prime factors of given input n using Hardy-Ramanujan formula.
27+
28+
- 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.
29+
30+
31+
## References
32+
33+
- [Youtube](https://www.youtube.com/watch?v=6PDtgHhpCHo)
34+
- [Wikipedia](https://en.wikipedia.org/wiki/Hardy%E2%80%93Ramanujan_theorem)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import primefactors from '../primefactors';
2+
3+
describe('prime-factors', () => {
4+
it('should give prime factors', () => {
5+
expect(primefactors.getPrimeFactors(510510)).toEqual([2, 3, 5, 7, 11, 13, 17]);
6+
expect(primefactors.getPrimeFactors(343434)).toEqual([2, 3, 7, 13, 17, 37]);
7+
expect(primefactors.getPrimeFactors(456745)).toEqual([5, 167, 547]);
8+
expect(primefactors.getPrimeFactors(8735463)).toEqual([3, 11, 88237]);
9+
expect(primefactors.getPrimeFactors(873452453)).toEqual([149, 1637, 3581]);
10+
expect(primefactors.getPrimeFactors(52734)).toEqual([2, 3, 11, 17, 47]);
11+
});
12+
13+
it('should give prime factors count accurately', () => {
14+
expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(510510))).toEqual(7);
15+
expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(343434))).toEqual(6);
16+
expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(456745))).toEqual(3);
17+
expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(8735463))).toEqual(3);
18+
expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(873452453))).toEqual(3);
19+
expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(52734))).toEqual(5);
20+
});
21+
22+
it('should give prime factors count approximately using Hardy-Ramanujan-Approx', () => {
23+
expect(primefactors.hardyRamanujanApprox(510510)).toBeCloseTo(2.5759018900,5);
24+
expect(primefactors.hardyRamanujanApprox(343434)).toBeCloseTo(2.54527635538,5);
25+
expect(primefactors.hardyRamanujanApprox(456745)).toBeCloseTo(2.5673987036,5);
26+
expect(primefactors.hardyRamanujanApprox(8735463)).toBeCloseTo(2.771519494900,5);
27+
expect(primefactors.hardyRamanujanApprox(873452453)).toBeCloseTo(3.0247066455016,5);
28+
expect(primefactors.hardyRamanujanApprox(52734)).toBeCloseTo(2.386284094835,5);
29+
});
30+
31+
it('should give error percentage of deviation of Hardy-Ramanujan-Approx prime-factors count from accurate prime-factors count', () => {
32+
expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(510510)),primefactors.hardyRamanujanApprox(510510))).toBeCloseTo(63.20140157059997,5);
33+
expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(343434)),primefactors.hardyRamanujanApprox(343434))).toBeCloseTo(57.5787274,5);
34+
expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(456745)),primefactors.hardyRamanujanApprox(456745))).toBeCloseTo(14.420043212851,5);
35+
expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(8735463)),primefactors.hardyRamanujanApprox(8735463))).toBeCloseTo(7.61601683663378,5);
36+
expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(873452453)),primefactors.hardyRamanujanApprox(873452453))).toBeCloseTo(0.8235548500,5);
37+
expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(52734)),primefactors.hardyRamanujanApprox(52734))).toBeCloseTo(52.27431810328,5);
38+
});
39+
});
40+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
export default {
2+
3+
getPrimeFactors : (n) => {
4+
let factorsArray = []; // an array where all the prime factors will be stored
5+
6+
//over here optimisation is made by running loop till sqrt(n) instead of n
7+
for (let i = 2 ; i <= Math.sqrt(n); i++){
8+
if(n % i === 0){ // if check to ensure i completely divides n
9+
let count = 0; // This count keeps track of number of times i divides n
10+
while(n % i === 0){
11+
n = n/i; // override the value of n
12+
count++; // count value updated
13+
}
14+
factorsArray.push(i); // array gets populated
15+
}
16+
}
17+
if(n !== 1){ // finally we cannot push 1 to array since it cannot be a prime-factor
18+
factorsArray.push(n);
19+
}
20+
21+
return factorsArray;
22+
},
23+
24+
//returns accurate prime-factors count
25+
getPrimeFactorsCount : (factorsArray) => {
26+
return factorsArray.length;
27+
},
28+
29+
30+
//returns Hardy-Ramanujan Approximation of prime-factors count
31+
hardyRamanujanApprox : (n) => {
32+
return Math.log(Math.log(n));
33+
},
34+
35+
//returns %age of error in approximation using formula to that of accurate result.
36+
errorPercent : (exactFactorCount,approximateFactorCount) => {
37+
let diff = exactFactorCount-approximateFactorCount > 0 ? exactFactorCount-approximateFactorCount: -(exactFactorCount-approximateFactorCount);
38+
return (diff/exactFactorCount * 100);
39+
}
40+
41+
42+
}
43+
44+

0 commit comments

Comments
 (0)