mirror of
https://github.com/TheAlgorithms/JavaScript.git
synced 2025-07-18 01:05:42 +08:00

It seems you've accidentally swapped the implementation and the test file :) The overall comment describing the algorithm (VERY nice doc, by the way) is not "proper" JSdoc => only one leading asterisk. It's generally considered good style to start a comment block (both JSdoc and regular comments) with a single, short sentence. Further down, there were some git hiccups, most likely caused by merge conflicts?
84 lines
2.9 KiB
JavaScript
84 lines
2.9 KiB
JavaScript
/*
|
|
* The Fermat primality test is a probabilistic test to determine whether a number is a probable prime.
|
|
*
|
|
* It relies on Fermat's Little Theorem, which states that if p is prime and a is not divisible by p, then
|
|
*
|
|
* a^(p - 1) % p = 1
|
|
*
|
|
* However, there are certain numbers (so called Fermat Liars) that screw things up;
|
|
* if a is one of these liars the equation will hold even though p is composite.
|
|
*
|
|
* But not everything is lost! It's been proven that at least half of all integers aren't Fermat Liar (these ones called
|
|
* Fermat Witnesses). Thus, if we keep testing the primality with random integers, we can achieve higher reliability.
|
|
*
|
|
* The interesting about all of this is that since half of all integers are Fermat Witnesses, the precision gets really
|
|
* high really fast! Suppose that we make the test 50 times: the chance of getting only Fermat Liars in all runs is
|
|
*
|
|
* 1 / 2^50 = 8.8 * 10^-16 (a pretty small number)
|
|
*
|
|
* For comparison, the probability of a cosmic ray causing an error to your infalible program is around 1.4 * 10^-15. An
|
|
* order of magnitude below!
|
|
*
|
|
* You can find more about the Fermat primality test and its flaws here:
|
|
* https://en.wikipedia.org/wiki/Fermat_primality_test
|
|
*/
|
|
|
|
/**
|
|
* Faster exponentiation that capitalize on the fact that we are only interested
|
|
* in the modulus of the exponentiation.
|
|
*
|
|
* Find out more about it here: https://en.wikipedia.org/wiki/Modular_exponentiation
|
|
*
|
|
* @param {number} base
|
|
* @param {number} exponent
|
|
* @param {number} modulus
|
|
*/
|
|
const modularExponentiation = (base, exponent, modulus) => {
|
|
if (modulus === 1) return 0 // after all, any x % 1 = 0
|
|
|
|
let result = 1
|
|
base %= modulus // make sure that base < modulus
|
|
|
|
while (exponent > 0) {
|
|
// if exponent is odd, multiply the result by the base
|
|
if (exponent % 2 === 1) {
|
|
result = (result * base) % modulus
|
|
exponent--
|
|
} else {
|
|
exponent = exponent / 2 // exponent is even for sure
|
|
base = (base * base) % modulus
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
/**
|
|
* Test if a given number n is prime or not.
|
|
*
|
|
* @param {number} n The number to check for primality
|
|
* @param {number} numberOfIterations The number of times to apply Fermat's Little Theorem
|
|
* @returns True if prime, false otherwise
|
|
*/
|
|
const fermatPrimeCheck = (n, numberOfIterations) => {
|
|
// first check for corner cases
|
|
if (n <= 1 || n === 4) return false
|
|
if (n <= 3) return true // 2 and 3 are included here
|
|
|
|
for (let i = 0; i < numberOfIterations; i++) {
|
|
// pick a random number between 2 and n - 2
|
|
const randomNumber = Math.floor(Math.random() * (n - 1 - 2) + 2)
|
|
|
|
// if a^(n - 1) % n is different than 1, n is composite
|
|
if (modularExponentiation(randomNumber, n - 1, n) !== 1) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
// if we arrived here without finding a Fermat Witness, this is almost guaranteed
|
|
// to be a prime number (or a Carmichael number, if you are unlucky)
|
|
return true
|
|
}
|
|
|
|
export { modularExponentiation, fermatPrimeCheck }
|