The first one, bc, takes a number n as argument and returns the exponent b and odd factor c such that n == 2bc. The underline has to be present on the left, but never on the right. Mathematica has some very sophisticated constructs, and this is one of them. You could define a function f[{a_,b_}], which would take one argument which is a list of two elements - but you could refer to the components a and b on the right hand side of the definition.
A Module is a construct that lets you define local variables. They are defined as a list in the first argument, and whatever the module computes is the second argument.
Sequential actions are indicated by statement terminators (semicolons). The last thing computed in the module is the list {b,c}, and that will be returned.
The While function has two arguments. The first is the condition, and the second is the action.
If you want integer division, you have to use the Quotient function.
bc[n_] := Module[ {b = 0, c = n},
While[ Mod[c,2] == 0, b++; c = Quotient[c,2] ];
{b, c}
]
The next function tries step 3 of your textbook algorithm. If n is certifiably not prime (cnp) it returns True, otherwise False.
The syntax for If is If[condition, then-action, else-action].
The algorithm is
Initialize the power to a and the product to 1.
While the exponent is nonzero
{
If the low-order bit of the exponent c is 1, multiply the power into
the product.
Square the power and shift off the low-order bit of the exponent.
If the squaring produced -1 (mod n), return False.
If it produced 1, then we have a square root of 1 other than 1 or -1,
so return True.
}
Now square the product b-1 times. If any square is -1 (mod n), return False,
but if it's 1, return True.
At the end, if we have either 1 or -1 (mod n), then return(False), otherwise
return True.
And here's the Mathematica code:
cnp[n_, a_, b_, c_] := Module[{ex = c, pr = 1, po = a, twos = b},
While[ex > 0,
If[ Mod[ex, 2] == 1, pr = Mod[pr * po, n], ];
po = Mod[po * po, n];
ex = Quotient[ex, 2];
If[ po == n-1, Return[False],];
If[ po == 1, Return[True], ];
];
If[ pr == n - 1, Return[False], ];
If[pr == 1, Return[False], ];
While[twos > 1,
pr = Mod[pr*pr, n];
twos--;
If[ pr == n - 1, Return[False],];
If[pr == 1, Return[True],];
];
If[ (pr == 1) || pr == n-1,Return[False],Return[True]];
]
Now probablyprime is easy. Specify the number n to test and the number of
trials to do.
probablyprime[n_,ntrials_] := Module[
{bcres = bc[n - 1]},
For[i = 0, i < ntrials, i++,
If[cnp[n, Random[Integer,{2, n - 2}],First[bcres],Last[bcres]],Return[False],]
];
Return[True]
]
Now if you input to MathematicaWith a little modification we can make the function show us what it's doing:
probablyprime1[n_,ntrials_] := Module[
{bcres = bc[n - 1], a},
For[i = 0, i < ntrials, i++,
a = Random[Integer, {2, n-2}];
Print["Trying ", a];
If[cnp[n, a ,First[bcres],Last[bcres]],Return[False],]
];
Return[True]
]
with results like this:
probablyprime1[1111111111111111111, 20] Trying 815863354527691421 Trying 52387242841935937 Trying 211783923785200936 Trying 834816113346351625 Trying 1101383424989427154 Trying 792994771316060541 Trying 1098213212338499285 Trying 248230583861041812 Trying 186850293519980942 Trying 850654053640527681 Trying 666888673440624253 Trying 197099378035149258 Trying 151919387204106385 Trying 514500642065846973 Trying 504152880762141267 Trying 492512123277809370 Trying 712823375202928580 Trying 399155884802181009 Trying 647765321150763977 Trying 723569789019027366 True