Miller–Rabin primality test: Difference between revisions

Content added Content deleted
(Improved D entry)
(→‎{{header|Ada}}: Added long integer version)
Line 22: Line 22:


=={{header|Ada}}==
=={{header|Ada}}==

===ordinary integers===

It's easy to get overflows doing exponential calculations. Therefore I implemented my own function for that.
It's easy to get overflows doing exponential calculations. Therefore I implemented my own function for that.


For Number types >= 2**64 you may have to use an external library.
For Number types >= 2**64 you may have to use an external library -- see below.
<lang Ada>with Ada.Text_IO;
<lang Ada>with Ada.Text_IO;
with Ada.Numerics.Discrete_Random;
with Ada.Numerics.Discrete_Random;
Line 113: Line 116:
Enter the count of loops: 20
Enter the count of loops: 20
What is it? COMPOSITE</pre>
What is it? COMPOSITE</pre>

===using an external library to handle big integers===

Using the big integer implementation from a cryptographic library [https://github.com/cforler/Ada-Crypto-Library/].

<lang Ada>with Ada.Text_IO, Crypto.Types.Big_Numbers, Ada.Numerics.Discrete_Random;

procedure Miller_Rabin is

Bound: constant Positive := 160; -- can be any multiple of 32

package LN is new Crypto.Types.Big_Numbers (2048);
use type LN.Big_Unsigned; -- all computations "mod 2**Bound"

function "+"(S: String) return LN.Big_Unsigned
renames LN.Utils.To_Big_Unsigned;

function Is_Prime (N : LN.Big_Unsigned; K : Positive := 10) return Boolean is

subtype Mod_32 is Crypto.Types.Mod_Type;
use type Mod_32;
package R_32 is new Ada.Numerics.Discrete_Random (Mod_32);
Generator : R_32.Generator;

function Random return LN.Big_Unsigned is
X: LN.Big_Unsigned := LN.Big_Unsigned_Zero;
begin
for I in 1 .. Bound/32 loop
X := (X * 2**16) * 2**16;
X := X + R_32.Random(Generator);
end loop;
return X;
end Random;

D: LN.Big_Unsigned := N - LN.Big_Unsigned_One;
S: Natural := 0;
A, X: LN.Big_Unsigned;
begin
-- exclude 2 and even numbers
if N = 2 then
return True;
elsif N mod 2 = LN.Big_Unsigned_Zero then
return False;
else

-- write N-1 as 2**S * D, with odd D
while D mod 2 = LN.Big_Unsigned_Zero loop
D := D / 2;
S := S + 1;
end loop;

-- initialize RNG
R_32.Reset (Generator);

-- run the real test
for Loops in 1 .. K loop
loop
A := Random;
exit when (A > 1) and (A < (N - 1));
end loop;
X := LN.Mod_Utils.Pow(A, D, N); -- X := (Random**D) mod N
if X /= 1 and X /= N - 1 then
Inner:
for R in 1 .. S - 1 loop
X := LN.Mod_Utils.Pow(X, LN.Big_Unsigned_Two, N);
if X = 1 then
return False;
end if;
exit Inner when X = N - 1;
end loop Inner;
if X /= N - 1 then
return False;
end if;
end if;
end loop;
end if;

return True;
end Is_Prime;

S: constant String :=
"4547337172376300111955330758342147474062293202868155909489";
T: constant String :=
"4547337172376300111955330758342147474062293202868155909393";

K: constant Positive := 10;

begin
Ada.Text_IO.Put_Line("Prime(" & S & ")=" & Boolean'Image(Is_Prime(+S, K)));
Ada.Text_IO.Put_Line("Prime(" & T & ")=" & Boolean'Image(Is_Prime(+T, K)));
end Miller_Rabin;</lang>

Output:
<pre>Prime(4547337172376300111955330758342147474062293202868155909489)=TRUE
Prime(4547337172376300111955330758342147474062293202868155909393)=FALSE</pre>

Using the built-in Miller-Rabin test from the same library:

<lang Ada>with Ada.Text_IO, Crypto.Types.Big_Numbers, Ada.Numerics.Discrete_Random;

procedure Miller_Rabin is

Bound: constant Positive := 160; -- can be any multiple of 32

package LN is new Crypto.Types.Big_Numbers (2048);
use type LN.Big_Unsigned; -- all computations "mod 2**Bound"

function "+"(S: String) return LN.Big_Unsigned
renames LN.Utils.To_Big_Unsigned;

S: constant String :=
"4547337172376300111955330758342147474062293202868155909489";
T: constant String :=
"4547337172376300111955330758342147474062293202868155909393";

K: constant Positive := 10;


begin
Ada.Text_IO.Put_Line("Prime(" & S & ")="
& Boolean'Image (LN.Mod_Utils.Passed_Miller_Rabin_Test(+S, K)));
Ada.Text_IO.Put_Line("Prime(" & T & ")="
& Boolean'Image (LN.Mod_Utils.Passed_Miller_Rabin_Test(+T, K)));
end Miller_Rabin;</lang>

The output is the same.


=={{header|ALGOL 68}}==
=={{header|ALGOL 68}}==