Skip to content

Commit 3c2fdf7

Browse files
Add Fermat Primality Test
1 parent 5f601fa commit 3c2fdf7

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-0
lines changed

Maths/FermatPrimalityTest.test.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { modularExponentiation, fermatPrimeCheck } from '../FermatPrimalityTest'
2+
3+
describe('modularExponentiation', () => {
4+
it('should give the correct output for all exponentiations', () => {
5+
expect(modularExponentiation(38, 220, 221)).toBe(1)
6+
expect(modularExponentiation(24, 220, 221)).toBe(81)
7+
})
8+
})
9+
10+
describe('fermatPrimeCheck', () => {
11+
it('should give the correct output for prime and composite numbers', () => {
12+
expect(fermatPrimeCheck(2, 50)).toBe(true)
13+
expect(fermatPrimeCheck(10, 50)).toBe(false)
14+
expect(fermatPrimeCheck(94286167, 50)).toBe(true)
15+
expect(fermatPrimeCheck(83165867, 50)).toBe(true)
16+
expect(fermatPrimeCheck(13268774, 50)).toBe(false)
17+
expect(fermatPrimeCheck(13233852, 50)).toBe(false)
18+
})
19+
})

Maths/test/FermatPrimalityTest.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/**
2+
* The Fermat primality test is a probabilistic test to determine whether a number is a probable prime. It relies on
3+
* Fermat's Little Theorem, which states that if p is prime and a is not divisible by p, then
4+
*
5+
* a^(p - 1) % p = 1
6+
*
7+
* However, there are certain numbers (so called Fermat Liars) that screw things up;
8+
* if a is one of these liars the equation will hold even though p is composite.
9+
*
10+
* But not everything is lost! It's been proven that at least half of all integers aren't Fermat Liar (these ones called
11+
* Fermat Witnesses). Thus, if we keep testing the primality with random integers, we can achieve higher reliability.
12+
*
13+
* The interesting about all of this is that since half of all integers are Fermat Witnesses, the precision gets really
14+
* high really fast! Suppose that we make the test 50 times: the chance of getting only Fermat Liars in all runs is
15+
*
16+
* 1 / 2^50 = 8.8 * 10^-16 (a pretty small number)
17+
*
18+
* For comparison, the probability of a cosmic ray causing an error to your infalible program is around 1.4 * 10^-15. An
19+
* order of magnitude below!
20+
*
21+
* You can find more about the Fermat primality test and its flaws here:
22+
* https://en.wikipedia.org/wiki/Fermat_primality_test
23+
*/
24+
25+
/**
26+
* Faster exponentiation that capitalize on the fact that we are only interested
27+
* in the modulus of the exponentiation.
28+
*
29+
* Find out more about it here: https://en.wikipedia.org/wiki/Modular_exponentiation
30+
*
31+
* @param {number} base
32+
* @param {number} exponent
33+
* @param {number} modulus
34+
*/
35+
const modularExponentiation = (base, exponent, modulus) => {
36+
if (modulus === 1) return 0 // after all, any x % 1 = 0
37+
38+
let result = 1
39+
base %= modulus // make sure that base < modulus
40+
41+
while (exponent > 0) {
42+
// if exponent is odd, multiply the result by the base
43+
if (exponent % 2 === 1) {
44+
result = (result * base) % modulus
45+
exponent--
46+
} else {
47+
exponent = exponent / 2 // exponent is even for sure
48+
base = (base * base) % modulus
49+
}
50+
}
51+
52+
return result
53+
}
54+
55+
/**
56+
* Test if a given number n is prime or not.
57+
*
58+
* @param {number} n The number to check for primality
59+
* @param {number} numberOfIterations The number of times to apply Fermat's Little Theorem
60+
* @returns True if prime, false otherwise
61+
*/
62+
const fermatPrimeCheck = (n, numberOfIterations) => {
63+
// first check for corner cases
64+
<<<<<<< HEAD
65+
if (n <= 1 || n === 4) return false
66+
=======
67+
if (n <= 1 || n == 4) return false
68+
>>>>>>> 951c7258323a057041c0d128880982ddab303ee5
69+
if (n <= 3) return true // 2 and 3 are included here
70+
71+
for (let i = 0; i < numberOfIterations; i++) {
72+
// pick a random number between 2 and n - 2
73+
<<<<<<< HEAD
74+
const randomNumber = Math.floor(Math.random() * (n - 1 - 2) + 2)
75+
=======
76+
let randomNumber = Math.floor(Math.random() * (n - 1 - 2) + 2)
77+
>>>>>>> 951c7258323a057041c0d128880982ddab303ee5
78+
79+
// if a^(n - 1) % n is different than 1, n is composite
80+
if (modularExponentiation(randomNumber, n - 1, n) !== 1) {
81+
return false
82+
}
83+
}
84+
85+
// if we arrived here without finding a Fermat Witness, this is almost guaranteed
86+
// to be a prime number (or a Carmichael number, if you are unlucky)
87+
return true
88+
}
89+
90+
export { modularExponentiation, fermatPrimeCheck }

0 commit comments

Comments
 (0)