@@ -134,21 +134,21 @@ lcm(abc::AbstractArray{<:Real}) = reduce(lcm, abc; init=one(eltype(abc)))
134
134
function gcd (abc:: AbstractArray{<:Integer} )
135
135
a = zero (eltype (abc))
136
136
for b in abc
137
- a = gcd (a,b)
137
+ a = gcd (a, b)
138
138
if a == 1
139
139
return a
140
140
end
141
141
end
142
142
return a
143
143
end
144
144
145
- # return (gcd(a,b),x, y) such that ax+by == gcd(a,b)
145
+ # return (gcd(a, b), x, y) such that ax+by == gcd(a, b)
146
146
"""
147
- gcdx(x,y )
147
+ gcdx(a, b )
148
148
149
- Computes the greatest common (positive) divisor of `x ` and `y ` and their Bézout
149
+ Computes the greatest common (positive) divisor of `a ` and `b ` and their Bézout
150
150
coefficients, i.e. the integer coefficients `u` and `v` that satisfy
151
- ``ux+vy = d = gcd(x,y )``. ``gcdx(x,y )`` returns ``(d,u, v)``.
151
+ ``ua+vb = d = gcd(a, b )``. ``gcdx(a, b )`` returns ``(d, u, v)``.
152
152
153
153
The arguments may be integer and rational numbers.
154
154
@@ -175,8 +175,8 @@ julia> gcdx(240, 46)
175
175
their `typemax`, and the identity then holds only via the unsigned
176
176
integers' modulo arithmetic.
177
177
"""
178
- function gcdx (a:: U , b:: V ) where {U <: Integer , V <: Integer }
179
- T = promote_type (U, V )
178
+ function gcdx (a:: Integer , b:: Integer )
179
+ T = promote_type (typeof (a), typeof (b) )
180
180
# a0, b0 = a, b
181
181
s0, s1 = oneunit (T), zero (T)
182
182
t0, t1 = s1, s0
@@ -197,11 +197,11 @@ gcdx(a::T, b::T) where T<:Real = throw(MethodError(gcdx, (a,b)))
197
197
# multiplicative inverse of n mod m, error if none
198
198
199
199
"""
200
- invmod(x, m)
200
+ invmod(n, m)
201
201
202
- Take the inverse of `x ` modulo `m`: `y` such that ``x y = 1 \\ pmod m``,
203
- with ``div(x,y ) = 0``. This is undefined for ``m = 0``, or if
204
- ``gcd(x ,m) \\ neq 1``.
202
+ Take the inverse of `n ` modulo `m`: `y` such that ``n y = 1 \\ pmod m``,
203
+ and ``div(y,m ) = 0``. This will throw an error if ``m = 0``, or if
204
+ ``gcd(n ,m) \\ neq 1``.
205
205
206
206
# Examples
207
207
```jldoctest
@@ -216,14 +216,24 @@ julia> invmod(5,6)
216
216
```
217
217
"""
218
218
function invmod (n:: Integer , m:: Integer )
219
+ iszero (m) && throw (DomainError (m, " `m` must not be 0." ))
220
+ if n isa Signed
221
+ # work around inconsistencies in gcdx
222
+ # https://github.com/JuliaLang/julia/issues/33781
223
+ T = promote_type (typeof (n), typeof (m))
224
+ n == typemin (typeof (n)) && m == typeof (n)(- 1 ) && return T (0 )
225
+ n == typeof (n)(- 1 ) && m == typemin (typeof (n)) && return T (- 1 )
226
+ end
219
227
g, x, y = gcdx (n, m)
220
228
g != 1 && throw (DomainError ((n, m), " Greatest common divisor is $g ." ))
221
- m == 0 && throw (DomainError (m, " `m` must not be 0." ))
222
229
# Note that m might be negative here.
223
- # For unsigned T, x might be close to typemax; add m to force a wrap-around.
224
- r = mod (x + m, m)
225
- # The postcondition is: mod(r * n, m) == mod(T(1), m) && div(r, m) == 0
226
- r
230
+ if n isa Unsigned && hastypemax (typeof (n)) && x > typemax (n)>> 1
231
+ # x might have wrapped if it would have been negative
232
+ # adding back m forces a correction
233
+ x += m
234
+ end
235
+ # The postcondition is: mod(result * n, m) == mod(T(1), m) && div(result, m) == 0
236
+ return mod (x, m)
227
237
end
228
238
229
239
# ^ for any x supporting *
0 commit comments