Task
Write a program/function that when given 3 positive integers \$a, b\$ and \$m\$ as input outputs a positive integer \$x\$ such that \$a^x\equiv b\ (\text{mod}\ m)\$ or that no such \$x\$ exists.
A reference implementation can be found here.
Constraints
You can expect \$a\$ and \$b\$ to be less than \$m\$.
Scoring
This is code-golf so shortest bytes wins.
Sample Testcases
# a, b, m -> x
10, 10, 50 -> 1
10, 100, 200 -> 2
10, 1, 127 -> 42
35, 541, 1438 -> 83
35, 541, 1438 -> 1519
1816, 2629, 3077 -> 223
3306, 4124, 5359 -> 1923
346, 406, 430 -> None
749430, 2427332, 2500918 -> 8025683
3442727916, 3990620294, 6638635157 -> 5731137125
Note: in the third testcase the solution cannot be 0 since the solution has to be a positive number
16 Answers 16
C (gcc), (削除) 59 (削除ここまで) (削除) 53 (削除ここまで) 51 bytes
Saved 6 bytes thanks to the man himself Arnauld!!!
Saved 2 bytes thanks Dominic van Essen!!!
p;x;f(a,b,m){for(p=a,x=1;p-b&&++x<m;)p=p*a%m;x%=m;}
Inputs positive integers \$a,b,m\$ with \$a,b<m\$.
Outputs a positive integer \$x\$ such that \$a^x\equiv b\ (\text{mod}\ m)\$ or \0ドル\$ if no such \$x\$ exists.
-
\$\begingroup\$ 57 bytes without the
p=at the end, if it's Ok to outputmfor 'no solution exists'. \$\endgroup\$Dominic van Essen– Dominic van Essen2020年07月03日 11:23:08 +00:00Commented Jul 3, 2020 at 11:23 -
2\$\begingroup\$ @DominicvanEssen Sure, but the kicker's that it's a positive integer and it's not a solution. It requires extra work outside of the function to deduce what the output actually means. \$\endgroup\$Noodle9– Noodle92020年07月03日 12:44:56 +00:00Commented Jul 3, 2020 at 12:44
-
1
-
1\$\begingroup\$ @Dominic van Essen And we're there! Very nice - thanks! :D \$\endgroup\$Noodle9– Noodle92020年07月04日 11:22:06 +00:00Commented Jul 4, 2020 at 11:22
-
1\$\begingroup\$ @Floris Yes, it's part of the syntax of a
forloop.. \$\endgroup\$Noodle9– Noodle92020年07月17日 13:11:53 +00:00Commented Jul 17, 2020 at 13:11
Python 2, (削除) 55 (削除ここまで) 51 bytes
def f(a,b,m,x=1):a**x%m==b<exit(x);x<m<f(a,b,m,x+1)
A recursive function that simply tests all exponents from \1ドル\$ to \$m\$. Returns through exit code: a positive exponent \$x\$, or \0ドル\$ if no such \$x\$ exists.
JavaScript (Node.js), (削除) 38 (削除ここまで) 33 bytes
Expects (a,m)(b) as 3 BigInts. Throws RangeError if there's no solution.
(a,m,x=m)=>g=b=>a**--x%m-b?g(b):x
JavaScript (Node.js), 39 bytes
Expects (a,m)(b) as 3 BigInts. Returns false if there's no solution.
NB: This version always returns the smallest solution.
(a,m,x=0n)=>g=b=>a**++x%m-b?x<m&&g(b):x
05AB1E, (削除) 10 (削除ここまで) 7 bytes
Lm1%3k>
Inputs in the order \$m,a,b\$; outputs 0 if no \$x\$ is found.
Try it online or verify all test cases.
Explanation:
L # Push a list of values `x` in the range [1, (implicit) input `m`]
m # Take the (implicit) input `a` to the power of each of these `x`
1% # Take each modulo the first input `m`
3k # Get the 0-based index of the first occurrence of the third input `b`
# (-1 if there are none)
> # And increase it by 1 to make it a 1-based index
# (after which it is output implicitly as result)
APL (Dyalog Extended), 23 bytes
{⍺(×ばつ⍳⍨)(×ばつ⊢)⌂traj⍵}
Dyalog APL can't handle large integers, so a modulo should be performed after each iteration.
How it works
{⍺(×ばつ⍳⍨)(×ばつ⊢)⌂traj⍵} ⍝ dop; ⍵ ⍺ ⍺⍺ ← a b m
( )⌂traj ⍝ Collect all iterations until duplicate is found
⍵ ⍝ starting from a:
×ばつ⊢ ⍝ Multiply a
⍺⍺| ⍝ Modulo m
⍺( ⍳⍨) ⍝ Find the 1-based index of b in the result,
×ばつ ⍝ changing to 0 if not found
MathGolf, 8 bytes
_╒k▬\%=)
Port of my 05AB1E answer, so also:
Inputs in the order \$m,a,b\$; outputs 0 if no \$x\$ is found.
Explanation:
_ # Duplicate the first (implicit) input `m`
╒ # Pop one and push a list in the range [1, `m`]
k # Push the second input `a`
▬ # For each value `x` in the list, take `a` to the power `x`
\ # Swap so the originally duplicated `m` is at the top of the stack
% # Take modulo-`m` on each value in the list
= # Get the first 0-based index of the value that equals the third (implicit)
# input `b` (-1 if there are none)
) # And increase it by 1 to make it a 1-based index
# (after which the entire stack joined together is output implicitly as result)
R+gmp, (削除) 47 (削除ここまで) 46 bytes
Or only 37 bytes by requiring input in the form of bigz big integer.
function(a,b,m)match(T,as.bigz(a)^(1:m)%%m==b)
-
\$\begingroup\$ arguably, you can just use ordinary integers and save yourself the call to
as.bigz\$\endgroup\$JDL– JDL2020年07月06日 12:01:29 +00:00Commented Jul 6, 2020 at 12:01 -
\$\begingroup\$ and it's more efficient to use
which(...)rather thanmatch(T,...)(you will get NA if there isn't one) \$\endgroup\$JDL– JDL2020年07月06日 12:02:04 +00:00Commented Jul 6, 2020 at 12:02 -
\$\begingroup\$ @JDL Unfortunately, without the
bigzbig integer, it fails by going out of the integer range for all except the first (smallest) two test cases. \$\endgroup\$Dominic van Essen– Dominic van Essen2020年07月06日 12:04:02 +00:00Commented Jul 6, 2020 at 12:04 -
\$\begingroup\$ @JDL and the reason that I ended-up using
match(T,...)instead ofwhich(...)is because many discrete logarithms have more-than-one solution (for instance, the fourth test case), sowhichneeds an extra[1]at the end to only output one of them, which makes it longer. \$\endgroup\$Dominic van Essen– Dominic van Essen2020年07月06日 12:06:05 +00:00Commented Jul 6, 2020 at 12:06 -
\$\begingroup\$
a*1would turnainto a double-precision — is that big enough? \$\endgroup\$JDL– JDL2020年07月07日 08:15:18 +00:00Commented Jul 7, 2020 at 8:15
Ruby, 41 bytes
->a,b,m,x=0{(a**x+=1)%m==b&&x||x<m&&redo}
The logic is straightforward: increment the exponent \$x\$ and return it if it satisfies the required equation, otherwise repeat while \$x\$ is less than \$m\$. Outputs the smallest solution for \$x\$, or false if no solution exists.
Java 8, 97 bytes
(a,b,m)->{for(int x=0;x++<m;)if(a.modPow(b.valueOf(x),b.valueOf(m)).equals(b))return x;return-1;}
\$a\$ and \$b\$ are both java.math.BigInteger; \$m\$ and the output \$x\$ are both int.
Outputs -1 if no \$x\$ is found.
Explanation:
(a,b,m)->{ // Method with 2 BigInteger & integer parameters and integer return
for(int x=0;x++<m;) // Loop `x` in the range (0,m]:
if(a.modPow(b.valueOf(x),b.valueOf(m))
// If `a` to the power `x`, modulo `m`
.equals(b)) // equals `b`:
return x; // Return `x` as result
return-1;} // If the loop has ended without result, return -1 instead
Brachylog, 19 bytes
Takes in a list of [A,M,B], output is either X or false. The [3306, 5359, 4124] test case times out on TIO, but returns the correct result locally. First Brachylog answer, so probably not the best solution. :-)
bhM>.>0&h;.^;M%~t?∧
How it works
bhM>.>0&h;.^;M%~t?∧
bhM set the second item to M
>.>0 output must be between M and 0
&h input's first item (A)
;.^ A^output
;M% A^output mod M
~t? must unify with the tail from the input (B)
∧ return the output
Haskell, 42 bytes
(a#m)b=last0ドル:[x|x<-[1..m],mod(a^x-b)m==0]
The function (a # m) b returns a positive integer x such that a ^ x == b (mod m). If no such x exists, it returns 0. This is done by the brute force method.
bc, (削除) 58 (削除ここまで) 50 bytes
define f(a,b,m){for(;x<m;)if(a^++x%m==b)return(x)}
This just tries the integers from 1 to m, and outputs the first one
which satisfies being a discrete log. Otherwise, the function returns
0 (default return value).
-
1\$\begingroup\$ 53 bytes by syntax guesswork... \$\endgroup\$Dominic van Essen– Dominic van Essen2020年07月04日 11:26:45 +00:00Commented Jul 4, 2020 at 11:26
-
1\$\begingroup\$ @DominicvanEssenThanks. And we can even omit the
x=0in that case. \$\endgroup\$Abigail– Abigail2020年07月04日 11:57:27 +00:00Commented Jul 4, 2020 at 11:57
R, 61 bytes
function(a,b,m){for(i in c(1:m,0))if((T=(a*T)%%m)==b)break;i}
The base form of R doesn't support arbitrary-precision arithmetic (see my other 'R+gmp' answer for a solution using the 'gmp' library that allows this).
But, pleasingly, the step-by-step calculation of (a^x)mod m comes-out at only 14 bytes longer than the brute-force approach, and it's much faster.
Charcoal, 14 bytes
NθI⊕⌕%XN...·1θθN
Try it online! Link is to verbose version of code. Takes input in the order m, a, b and outputs 0 if there is no solution. Explanation:
Nθ Store `m`
...·1θ Range from 1 to `m` inclusive
XN Take powers of `a`
% θ Reduce modulo `m`
⌕ N Find index of `b`
⊕ Convert to 1-indexing
I Cast to string
Implicitly print
Retina, 84 bytes
\d+
*
"$+"{`,(?=(_+))((_+),)+
,$.1*3ドル$&
)`^(_+),1円+
1,ドル
L$`.*(,_+)(,_+)+$(?<=1円)
$#2
Try it online! Sadly no test suite as this uses "$+", and I can't figure out how to emulate that with multiple sets of inputs (Retina just crashes when I try). Takes input in the order m, a, b and produces no output if there is no solution. Explanation:
\d+
*
Convert to unary.
"$+"{`
)`
Repeat m times...
,(?=(_+))((_+),)+
,$.1*3ドル$&
... multiply the second number by the second last number and insert it between the first two numbers...
^(_+),1円+
1,ドル
... and reduce it modulo m.
L$`.*(,_+)(,_+)+$(?<=1円)
$#2
Count the position of the power matching b starting from the end.
Explore related questions
See similar questions with these tags.
MultiplicativeOrderreference.wolfram.com/language/ref/MultiplicativeOrder.html \$\endgroup\$2**53-1please? \$\endgroup\$