Below is Crystal code to generate Mersenne Primes.
It's mathematical structure is based on Prime Generator Theory (PGT).
Given an odd exponent n, it will compute the next Mp prime e.g. n = p.
The beauty of this method is you don't need to test|know a list of primes.
It will find the next Mp prime from any starting odd n exponent value.
The math guarantees the primes between n and Mp prime p don't have to be checked.
If anyone is interested, I can provide the papers explaining the math.
# Compile as: crystal build --release --mcpu native MPgenerateLL.cr
# Current Crystal: 1.14.0; LLVM 18.1.6
# Last update: 2024/11/10
require "big"
module Primes
module Utils
# Lucas-Lehmer primality test for Mersenne Prims
def mp_prime?
p = self.to_big_i
s, mp = 4.to_big_i, (1.to_big_i << p) - 1
(p-2).times { s = mp_mod(((s * s) - 2), p, mp) }
s.divisible_by? mp
end
private def mp_mod(n, p, mp)
while n > mp
n = (n >> p) + (n & mp)
end
n
end
end
end
struct Int; include Primes::Utils end
def mpgen(p, steps = 1u64)
puts "Starting Mp gen exponent = #{p}"
puts "Starting Mp gen process at step #{steps}"
r = (1.to_big_i << p) - 1
modpnk = modpn = 3.to_big_i << p
(steps-1).times { modpnk = (modpnk << 2) + modpn }
loop do
mp = modpnk + r
print "\rsteps = #{steps}"
break if (p = mp.bit_length).mp_prime?
steps += 1
modpnk = (modpnk << 2) + modpn
end
print "\rsteps = #{steps}\n"
puts "Next Mp prime = #{p}"
p
end
def tm; t = Time.monotonic; yield; Time.monotonic - t end
def mpgenerate
p = (ARGV[0].to_u64 underscore: true)
steps = ARGV.size > 1 ? (ARGV[1].to_u64 underscore: true) : 1u64
puts tm { mpgen(p, steps) }; puts
end
mpgenerate
I would like to compare it to a well done Rust version.
The Crystal version uses BigInt
s for arbitray sized integers math.
I don't know what|if the equivaltent is in Rust (native or crates).
If Rust can do the (s * s) operations faster it will be even more optimized.
As you can see, it's not much code.
I'm hoping a good|seasoned Rust programmers can optimally translate it.
Here's some Crystal test output to use as comparison references.
As shown, it shows the time it takes mp_prime?
to primality test these Mp primes.
(Times generated on 'noisy' system. Other things going on while testing.)
My Linux laptop: Lenovo Legion Slim 5, AMD Ryzen 7 8845HS, 5.1GHz, 8C|16T
β crystal-projects ./MPgenLL 86241
Starting Mp gen exponent = 86241
Starting Mp gen process at step 1
steps = 1
Next Mp prime = 86243 # M28 - 51,924 digits
00:00:31.036883127
β crystal-projects ./MPgenLL 110501
Starting Mp gen exponent = 110501
Starting Mp gen process at step 1
steps = 1
Next Mp prime = 110503 # M29 - 66,530 digits
00:00:57.786394665
β crystal-projects ./MPgenLL 132047
Starting Mp gen exponent = 132047
Starting Mp gen process at step 1
steps = 1
Next Mp prime = 132049 # M30 - 79,502 digits
00:01:29.874204215
β crystal-projects ./MPgenLL 216089
Starting Mp gen exponent = 216089
Starting Mp gen process at step 1
steps = 1
Next Mp prime = 216091 # M31 - 130,100 digits
00:03:23.980284348
β crystal-projects ./MPgenLL 756837
Starting Mp gen exponent = 756837
Starting Mp gen process at step 1
steps = 1
Next Mp prime = 756839 # M32 - 455,663 digits
00:53:11.942810881
β crystal-projects ./MPgenLL 859431
Starting Mp gen exponent = 859431
Starting Mp gen process at step 1
steps = 1
Next Mp prime = 859433 # M33 - 517,430 digits
01:11:24.882317036
β crystal-projects ./MPgenLL 1257785
Starting Mp gen exponent = 1257785
Starting Mp gen process at step 1
steps = 1
Next Mp prime = 1257787 # M34 - 757,263 digits
02:48:17.749699153
Here's a list of all the known Mp, digits sizes, et al.