Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

Fermat's theorem/prime number problem?

https://en.wikipedia.org/wiki/Fermat%27s_little_theorem

Basically, if you raise an integer to a prime number and subtract the integer, you will get a multiple of that prime number. You could then use modulus to confirm that it's a multiple of the prime number. I'm trying to use this script to list all the prime numbers up to 1000:

for i = 2, 1000 do
	if (3^i - 3) % i == 0 then
		print(i)
	end
end

For some reason, this lists composite numbers as well (6, 38, 39, 40, 44, etc). Am I doing something wrong, or does this mean that Fermat's little theorem isn't the best way to check if a number is prime?

1 comment

1

If your trying generate a list of primes, I suggest a sieve such as https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes or https://en.wikipedia.org/wiki/Sieve_of_Sundaram

1 answer

✓ Accepted answer

There are two problems with this.

Fermat's Little Theorem

If p is a prime and a is any integer not divisible by p, then a^(p - 1) - 1 is divisible by p.

That does not give you the converse: just because a^(p-1)-1 is divisible by p does not mean that p is prime. There is Fermat's primality test which involves trying this for many different values of a, which results in a high-confidence of its primality.

Floating Point

You're not going to be able to do this easily directly in Lua. Numbers in Lua do not store full integer precision. As small as 35, you have 3^35 == 3^35 - 1, which means you're not going to easily be able to apply this directly.

Thanks to properties of modular arithmetic, though, and fast-exponentiation-by-squaring, you can make this work in Lua.

First, the slow way to do exponentiation: repeated multiplication:

-- computes a^b for b an integer
function exp(a, b)
	local n = 1
	for i = 1, b do
		n = n * a
	end
	return n
end

We'll have the same problem as before. We need to use the fact that we are computing thing mod another number.

There is a nice property that (a * b) % n == (a % n) * (b % n). This means we can take % after each step, and avoid big numbers:

-- computes a^b % mod
function exp(a, b, mod)
	local n = 1
	for i = 1, b do
		n = n * a % mod
	end
	return n
end

This isn't very fast, though. We have to do 2000 multiplications to test b=2000. We can use fast exponentiation by squaring to improve this significantly.

The observation is that x ^ (2n) == (x ^ n) ^ 2. Thus we can turn 2n multiplications into 1 + n multiplications.

-- compute a^b
function fastexp(a, b)
	if b == 0 then
		return 1
	elseif b % 2 == 0 then
		-- b is even
		return fastexp(a, b / 2) ^ 2
	else
		return a * fastexp(a, (b-1)/2) ^ 2
	end
end

This is a log-time algorithm, thus b=2000 will take around 12 multiplications instead of 2000.

Of course, don't forget to add the mod in there:

-- compute a^b % mod
function fastexp(a, b, mod)
	if b == 0 then
		return 1
	elseif b % 2 == 0 then
		-- b is even
		return fastexp(a, b / 2, mod) ^ 2 % mod
	else
		return a * fastexp(a, (b-1)/2, mod) ^ 2 % mod
	end
end

Fermat's Primality Test

function trial(a, p)
	return fastexp(a, p-1, p) == 1
end

function isProbablyPrime(p, c)
	for i = 1, c or 100 do
		if not trial(math.random(2,p-1), p) then
			return false
		end
	end
	return true
end

for i = 1, 100 do
	if isProbablyPrime(i) then
		print(i)
	end
end

There are other primality tests, too. I don't think Fermat's test is considered very good.

This discussion is preserved as it was. New answers, comments, and votes are closed.