I am trying to compute discrete logarithms modulo p (in a naive way). I have three approaches
LogMod1[a_, b_, p_] := Block[{j = 0},
While[PowerMod[a, j, p] != b && j < p, j++];
j];
LogMod2[a_, b_, p_] := Block[{j = 0, aa = 1},
While[aa != b && j < p, j++; aa = Mod[a aa, p]];
j];
LogMod3[a_, b_, p_] := Block[{j = 0},
NestWhile[(j++; Mod[a #, p]) &, 1, (# != b) &, 1, p];
j];
all of which roughly give the same performance
p = NextPrime[10^5]; a = PrimitiveRoot[p]; b = PowerMod[a, -1, p];
{Timing[LogMod1[a, b, p]], Timing[LogMod2[a, b, p]],
Timing[LogMod3[a, b, p]]}
{{0.094508, 100001}, {0.116498, 100001}, {0.144977, 100001}}
Interestingly, the first approach is the fastest, although the loop starts from scratch in every round. If I do the same in another scripted language, like python, all of this will be much faster. Am I doing something wrong?
PS: I know that the internal command MultiplicativeOrder[a, p, {b}] will do it about 10 times faster, but I'd like to understand why my approach is so slow. Also, I know that there are better algorithms for solving DLP, but again, this is not my question.