一部の標準Pythonモジュールには、数値のモジュラー乗法逆数を計算する関数が含まれてy = invmod(x, p)
いx*y == 1 (mod p)
ますか?グーグルはこれについて良いヒントを与えていないようです。
もちろん、拡張ユークリッドアルゴリズムの自家製の10ライナーを思い付くことができますが、なぜ車輪を再発明するのでしょうか。
たとえば、JavaにBigInteger
はhas modInverse
メソッドがあります。Pythonには似たようなものはありませんか?
一部の標準Pythonモジュールには、数値のモジュラー乗法逆数を計算する関数が含まれてy = invmod(x, p)
いx*y == 1 (mod p)
ますか?グーグルはこれについて良いヒントを与えていないようです。
もちろん、拡張ユークリッドアルゴリズムの自家製の10ライナーを思い付くことができますが、なぜ車輪を再発明するのでしょうか。
たとえば、JavaにBigInteger
はhas modInverse
メソッドがあります。Pythonには似たようなものはありませんか?
回答:
多分誰かが(wikibooksから)これが役立つと思うでしょう:
def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)
def modinv(a, m):
g, x, y = egcd(a, m)
if g != 1:
raise Exception('modular inverse does not exist')
else:
return x % m
sympy
している場合x, _, g = sympy.numbers.igcdex(a, m)
は、トリックを行います。
係数が素数の場合(これをと呼びますp
)、単純に次のように計算できます。
y = x**(p-2) mod p # Pseudocode
またはPython固有:
y = pow(x, p-2, p)
Pythonにいくつかの数論機能を実装した人がいます:http : //www.math.umbc.edu/~campbell/Computers/Python/numbthy.html
プロンプトで行われる例はここにあります:
m = 1000000007
x = 1234567
y = pow(x,m-2,m)
y
989145189L
x*y
1221166008548163L
x*y % m
1L
また、gmpyモジュールを確認することもできます。PythonとGMPの倍精度ライブラリ間のインターフェースです。gmpyは、必要なことを正確に実行する反転関数を提供します。
>>> import gmpy
>>> gmpy.invert(1234567, 1000000007)
mpz(989145189)
回答を更新しました
@hyhで述べたgmpy.invert()
ように、逆が存在しない場合は0を返します。これは、GMPのmpz_invert()
機能の動作と一致します。gmpy.divm(a, b, m)
への一般的なソリューションを提供しa=bx (mod m)
ます。
>>> gmpy.divm(1, 1234567, 1000000007)
mpz(989145189)
>>> gmpy.divm(1, 0, 5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: not invertible
>>> gmpy.divm(1, 4, 8)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: not invertible
>>> gmpy.divm(1, 4, 9)
mpz(7)
divm()
gcd(b,m) == 1
乗算の逆が存在しない場合に解を返し、例外を発生させます。
免責事項:私はgmpyライブラリーの現在のメンテナーです。
回答2を更新
逆が存在しない場合、gmpy2は適切に例外を発生させるようになりました。
>>> import gmpy2
>>> gmpy2.invert(0,5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: invert() no inverse exists
gmpy.invert(0,5) = mpz(0)
エラーが発生する代わりに、これが見つかるまでこれはクールです...
gmpy
パッケージにはモジュラー乗算がありますか?(つまり、同じ値を持っているが(a * b)% p
?よりも速い関数)
(a * b) % p
関数で計算するだけの最も単純なアプローチは(a * b) % p
、Pythonで評価するよりも速くはありません。関数呼び出しのオーバーヘッドは、式を評価するコストよりも大きくなります。詳細については、code.google.com / p / gmpy / issues / detail?id = 61をご覧ください。
これがCodeFightsのワンライナーです。これは最短のソリューションの1つです。
MMI = lambda A, n,s=1,t=0,N=0: (n < 2 and t%N or MMI(n, A%n, t, s-A//n*t, N or n),-1)[n<1]
乗法逆数がない-1
場合に返さA
れますn
ます。
使用法:
MMI(23, 99) # returns 56
MMI(18, 24) # return -1
ソリューションは、拡張ユークリッドアルゴリズムを使用します。
シンボリック数学用のpythonモジュールであるSympyには、独自のモジュール逆関数を実装したくない場合(またはSympyをすでに使用している場合)に組み込みの逆関数があります。
from sympy import mod_inverse
mod_inverse(11, 35) # returns 16
mod_inverse(15, 35) # raises ValueError: 'inverse of 15 (mod 35) does not exist'
これはSympyのWebサイトに記載されていないようですが、docstringは次のとおりです:GithubのSympy mod_inverse docstring
ここに私のコードがあります、それはずさんなかもしれませんが、とにかく私のために働くようです。
# a is the number you want the inverse for
# b is the modulus
def mod_inverse(a, b):
r = -1
B = b
A = a
eq_set = []
full_set = []
mod_set = []
#euclid's algorithm
while r!=1 and r!=0:
r = b%a
q = b//a
eq_set = [r, b, a, q*-1]
b = a
a = r
full_set.append(eq_set)
for i in range(0, 4):
mod_set.append(full_set[-1][i])
mod_set.insert(2, 1)
counter = 0
#extended euclid's algorithm
for i in range(1, len(full_set)):
if counter%2 == 0:
mod_set[2] = full_set[-1*(i+1)][3]*mod_set[4]+mod_set[2]
mod_set[3] = full_set[-1*(i+1)][1]
elif counter%2 != 0:
mod_set[4] = full_set[-1*(i+1)][3]*mod_set[2]+mod_set[4]
mod_set[1] = full_set[-1*(i+1)][1]
counter += 1
if mod_set[3] == B:
return mod_set[2]%B
return mod_set[4]%B
上記のコードはpython3では実行されず、GCDバリアントと比較して効率が低下します。ただし、このコードは非常に透過的です。よりコンパクトなバージョンを作成するきっかけになりました。
def imod(a, n):
c = 1
while (c % a > 0):
c += n
return c // a
n == 7
。しかし、それ以外の場合は、この「アルゴリズム」の同等についてです:for i in range(2, n): if i * a % n == 1: return i
これは、外部ライブラリを使用せずにそれを行う簡潔な1行です。
# Given 0<a<b, returns the unique c such that 0<c<b and a*c == gcd(a,b) (mod b).
# In particular, if a,b are relatively prime, returns the inverse of a modulo b.
def invmod(a,b): return 0 if a==0 else 1 if b%a==0 else b - invmod(b%a,a)*b//a
これは実際には単にegcdであり、関心のある単一の係数のみを返すように効率化されていることに注意してください。
モジュラー乗法逆数を理解するには、次のような拡張ユークリッドアルゴリズムを使用することをお勧めします。
def multiplicative_inverse(a, b):
origA = a
X = 0
prevX = 1
Y = 1
prevY = 0
while b != 0:
temp = b
quotient = a/b
b = a%b
a = temp
temp = X
a = prevX - quotient * X
prevX = temp
temp = Y
Y = prevY - quotient * Y
prevY = temp
return origA + prevY
a = prevX - quotient * X
必要がX = prevX - quotient * X
あり、が返されprevX
ます。FWIW、この実装はマーツ・バホフの回答へのコメントのQaz のリンクの実装と似ています。
私はこのスレッドから別の解決策を試し、最終的にこれを使用します:
def egcd(a, b):
lastremainder, remainder = abs(a), abs(b)
x, lastx, y, lasty = 0, 1, 1, 0
while remainder:
lastremainder, (quotient, remainder) = remainder, divmod(lastremainder, remainder)
x, lastx = lastx - quotient*x, x
y, lasty = lasty - quotient*y, y
return lastremainder, lastx * (-1 if a < 0 else 1), lasty * (-1 if b < 0 else 1)
def modinv(a, m):
g, x, y = self.egcd(a, m)
if g != 1:
raise ValueError('modinv for {} does not exist'.format(a))
return x % m
return
egcdは間違った方法で使用されています
まあ、私はpythonには関数はありませんが、Cには簡単にpythonに変換できる関数があります。以下のcでは、拡張ユークリッドアルゴリズムを使用して逆modを計算しています。
int imod(int a,int n){
int c,i=1;
while(1){
c = n * i + 1;
if(c%a==0){
c = c/a;
break;
}
i++;
}
return c;}
Python関数
def imod(a,n):
i=1
while True:
c = n * i + 1;
if(c%a==0):
c = c/a
break;
i = i+1
return c
上記のC関数への参照は、次のリンクCプログラムから引用され、2つの比較的素数のモジュラー乗法逆数を見つけます。
cpython実装ソースコードから:
def invmod(a, n):
b, c = 1, 0
while n:
q, r = divmod(a, n)
a, b, c, n = n, c, b - q*c, r
# at this point a is the gcd of the original inputs
if a == 1:
return b
raise ValueError("Not invertible")
このコードの上のコメントによれば、小さな負の値を返す可能性があるため、負の値かどうかを確認し、負の値の場合はnを追加してからbを返すことができます。
上記のリンクの多くは、2017年1月23日と同様に壊れています。私はこの実装を見つけました:https : //courses.csail.mit.edu/6.857/2016/files/ffield.py
pow
関数を使用できますy = pow(x, -1, p)
。bugs.python.org/issue36027を参照してください。質問されてから標準ライブラリに表示されるソリューションまで8.5年しかかかりませんでした。