पायथन में मॉड्यूलर गुणक व्युत्क्रम फ़ंक्शन


110

क्या कुछ मानक पायथन मॉड्यूल में मॉड्यूलर गुणक व्युत्क्रम की गणना करने के लिए एक फ़ंक्शन होता है किसी संख्या के की , अर्थात एक संख्या y = invmod(x, p)ऐसी x*y == 1 (mod p)? Google इस पर कोई अच्छा संकेत नहीं देता है।

बेशक, कोई भी घर से बने 10-लाइनर के साथ आ सकता है विस्तारित यूक्लिडियन एल्गोरिथ्म के है , लेकिन पहिया को क्यों मजबूत किया जाए।

उदाहरण के लिए, जावा के BigIntegerहै modInverseविधि। क्या पायथन में भी कुछ ऐसा ही नहीं है?


18
पायथन 3.8 में (इस साल के अंत में जारी होने के कारण), आप इसके लिए अंतर्निहित powफ़ंक्शन का उपयोग करने में सक्षम होंगे y = pow(x, -1, p):। Bugs.python.org/issue36027 देखें । यह केवल मानक पुस्तकालय में प्रदर्शित होने वाले समाधान से पूछे गए सवाल से 8.5 साल लग गए!
मार्क डिकिन्सन

4
मैं देखता हूं कि @MarkDickinson ने इस बात का उल्लेख करने के लिए मामूली उपेक्षा की कि आंख इस बहुत उपयोगी वृद्धि के लेखक हैं, इसलिए मैं लूंगा। इस काम के लिए धन्यवाद, निशान, यह बहुत अच्छा लग रहा है!
डॉन हैच

जवाबों:


128

हो सकता है कि किसी को यह उपयोगी लगे ( विकीबूक से ):

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

1
मुझे इस एल्गोरिथ्म का उपयोग करते हुए नकारात्मक संख्याओं के साथ समस्या हो रही थी। modinv (-3, 11) ने काम नहीं किया। मैंने इस pdf के पृष्ठ दो पर कार्यान्वयन के साथ egcd को बदलकर इसे ठीक किया: anh.cs.luc.edu/331/notes/xgcd.pdf आशा है कि मदद करता है!
Qaz

@Qaz इसे सकारात्मक बनाने के लिए आप बस -3 modulo 11 को कम कर सकते हैं, इस मामले में modinv (-3, 11) == modinv (-3 + 11, 11) == modinv (8, 11)। शायद यही है कि आपके पीडीएफ में एल्गोरिदम कुछ बिंदु पर क्या होता है।
थॉमस

1
यदि आप उपयोग कर रहे हैं sympy, तो x, _, g = sympy.numbers.igcdex(a, m)चाल है।
लिन

59

यदि आपका मापांक प्रधान है (आप इसे कहते हैं p) तो आप बस गणना कर सकते हैं:

y = x**(p-2) mod p  # Pseudocode

या अजगर में उचित:

y = pow(x, p-2, p)

यहाँ कोई है जिसने पायथन में कुछ संख्या सिद्धांत क्षमताओं को लागू किया है: 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

1
Naive घातांक समय की वजह से समय और (स्मृति) की सीमा के कारण कोई विकल्प नहीं है, जैसे कि p का कोई बड़ा मूल्य 1000000007 है।
dorserg

16
मॉड्यूलर घातांक अधिकांश N * 2 गुणन के साथ किया जाता है जहां N घातांक में बिट्स की संख्या होती है। 2 ** 63-1 के मापांक का उपयोग करके प्रॉम्प्ट पर गणना की जा सकती है और तुरंत परिणाम देता है।
फकहलर

3
वाह, बहुत बढ़िया। मुझे त्वरित घातांक के बारे में पता है, मुझे अभी पता नहीं था कि pow () फ़ंक्शन तीसरा तर्क ले सकता है जो इसे मॉड्यूलर घातांक में बदल देता है।
डोरसेगर

5
यही कारण है कि आप पायथन का सही उपयोग कर रहे हैं? क्योंकि यह बहुत बढ़िया है :-)
फकहलर 25:11

2
वैसे यह काम करता है क्योंकि Fermat से थोड़ा प्रमेय pow (x, m-1, m) 1 होना चाहिए। इसलिए (pow (x, m-2, m) * x)% m == 1. तो pow (x,) m-2, m) x (mod m) का विलोम है।
पियोत्र डबकोव्स्की

21

आप gmpy मॉड्यूल को भी देखना चाहेंगे । यह पायथन और GMP बहु-परिशुद्धता पुस्तकालय के बीच एक इंटरफ़ेस है। gmpy एक इनवर्टर फ़ंक्शन प्रदान करता है जो वास्तव में आपकी आवश्यकता है:

>>> import gmpy
>>> gmpy.invert(1234567, 1000000007)
mpz(989145189)

अद्यतन उत्तर

जैसा कि @hyh ने उल्लेख किया है, gmpy.invert()यदि प्रतिलोम मौजूद नहीं है , तो रिटर्न 0 है। यह जीएमपी के 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)एक त्रुटि को बढ़ाने के बजाय पाया ...
h__

@ क्यों आप इसे gmpy के मुख पृष्ठ पर एक समस्या के रूप में रिपोर्ट कर सकते हैं? मुद्दों की रिपोर्ट होने पर इसकी हमेशा सराहना की जाती है।
केसवह

BTW, क्या इस gmpyपैकेज में एक मॉड्यूलर गुणन है ? (अर्थात कुछ कार्य जिनका मान समान है, लेकिन उससे अधिक तेज़ है (a * b)% p?)
h__

यह पहले प्रस्तावित किया गया है और मैं विभिन्न तरीकों के साथ प्रयोग कर रहा हूं। (a * b) % pकिसी फ़ंक्शन में गणना करने का सबसे सरल तरीका केवल (a * b) % pपायथन में मूल्यांकन करने से तेज़ नहीं है । एक फ़ंक्शन कॉल के लिए ओवरहेड अभिव्यक्ति का मूल्यांकन करने की लागत से अधिक है। अधिक विवरण के लिए code.google.com/p/gmpy/issues/detail?id=61 देखें ।
केसवह

2
बड़ी बात यह है कि यह नॉन-प्राइम मोडुलि के लिए भी काम करता है।
सिनकेडोचे

13

3.8 अजगर पाउ ​​() फ़ंक्शन के रूप में एक मापांक और एक नकारात्मक पूर्णांक ले सकते हैं। देखें यहाँ । यह कैसे उपयोग करने के लिए उनके मामले है

>>> pow(38, -1, 97)
23
>>> 23 * 38 % 97 == 1
True

8

यहाँ CodeFights के लिए एक-लाइनर है ; यह सबसे छोटे समाधानों में से एक है:

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

समाधान विस्तारित यूक्लिडियन एल्गोरिथ्म का उपयोग करता है ।


6

सिम्पी , प्रतीकात्मक गणित के लिए एक अजगर मॉड्यूल, एक अंतर्निहित मॉड्यूलर उलटा कार्य है यदि आप अपना खुद का कार्यान्वयन नहीं करना चाहते हैं (या यदि आप पहले से ही सिम्पी का उपयोग कर रहे हैं):

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'

यह सिम्पी की वेबसाइट पर प्रलेखित नहीं लगता है, लेकिन यहाँ डॉकस्ट्रिंग है : सिथाई mod_inverse डॉकस्ट्रिंग गीथब पर


2

यहाँ मेरा कोड है, यह टेढ़ा हो सकता है लेकिन यह मेरे लिए वैसे भी काम करता है।

# 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

2

उपरोक्त कोड python3 में नहीं चलेगा और GCD वेरिएंट की तुलना में कम कुशल है। हालाँकि, यह कोड बहुत पारदर्शी है। इसने मुझे और अधिक कॉम्पैक्ट संस्करण बनाने के लिए प्रेरित किया:

def imod(a, n):
 c = 1
 while (c % a > 0):
     c += n
 return c // a

1
यह बच्चों को समझाने के लिए ठीक है, और कब n == 7। लेकिन अन्यथा यह इस "एल्गोरिथ्म" के बराबर है:for i in range(2, n): if i * a % n == 1: return i
टॉमस गैंडर

2

यहां एक संक्षिप्त 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 है, ब्याज के केवल गुणांक को वापस करने के लिए सुव्यवस्थित।


1

इस तरह से विस्तारित यूक्लिडियन एल्गोरिथ्म का उपयोग करने की सलाह देने वाले मॉड्यूलर गुणन व्युत्क्रम का पता लगाने के लिए:

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। एफडब्ल्यूआईडब्ल्यू, यह कार्यान्वयन माजर्ट बखॉफ के जवाब में टिप्पणी में काज़ की कड़ी के समान है ।
PM 2Ring

1

मैं इस धागे से विभिन्न समाधानों की कोशिश करता हूं और अंत में मैं इसका उपयोग करता हूं:

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

Python में Modular_inverse


1
यह कोड अमान्य है। returnजैसे एलसीडी गलत तरीके से
लगाया जाता है

0

खैर, मेरे पास अजगर में कोई फ़ंक्शन नहीं है, लेकिन मेरे पास सी में एक फ़ंक्शन है जिसे आप आसानी से अजगर में बदल सकते हैं, नीचे सी फ़ंक्शन में विस्तारित यूक्लिडियन एल्गोरिथ्म का उपयोग उलटा मॉड की गणना करने के लिए किया जाता है।

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;}

पायथन फंक्शन

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

उपरोक्त सी फ़ंक्शन का संदर्भ निम्न लिंक सी प्रोग्राम से लिया गया है जो दो सापेक्ष प्रधान संख्याओं के मॉड्यूलर गुणक व्युत्क्रम को खोजने के लिए है।


0

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 वापस लौटने से पहले नकारात्मक जोड़ें।


"इसलिए आप संभावित रूप से जाँच कर सकते हैं कि यदि ऋणात्मक है और ख वापस करने से पहले नकारात्मक जोड़ते हैं"। दुर्भाग्य से n उस बिंदु पर 0 है। (आपको n का मूल मान सहेजना और उपयोग करना होगा।)
डॉन हैच

-2

ऊपर दिए गए कई लिंक 1/23/2017 के लिए टूट गए हैं। मुझे यह कार्यान्वयन मिला: https://courses.csail.mit.edu/6.857/2016/files/ffield.py


लिंक से बचें केवल उत्तर। जैसा कि आपने अपने ईमेल में कहा था, लिंक टूट सकते हैं।
जेफ

उस मॉड्यूल के लेखक एमिन मार्टिनियन ने इसे pypi.python.org/pypi/pyfinite/1.5
Dan D.
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.