简体   繁体   中英

Solving linear equation with large numbers

I have equation of form a+b*n1=c+d*n2 , where a,b,c,d are known numbers with around 1000 digits and I need to solve n1.

I tried:

i=1
while True:
    a=(a+b)%d
    if(a==c):
        break
    i+=1
print(i)

, but this method is too slow for numbers this big. Is there some better method to use in this kind of situations?

You want to find x such that x = a (mod b) and x = c (mod d) . For then, n1 = (x - a) / b and n2 = (x - c) / d .

If b and d are coprime, then the existence of x is guaranteed by the Chinese Remainder Theorem -- and a solution can be found using the Extended Euclidean Algorithm.

If b and d aren't coprime (that is, if gcd(b, d) != 1 ), then (noting that a = c (mod gcd(b, d)) ), we can subtract a % gcd(b, d) from both sides, and divide through by gcd(b, d) to reduce to a problem as above.

Putting it into code

Here's code that finds n1 and n2 using this method:

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):
    return egcd(a, m)[1] % m

def solve(a, b, c, d):
    gcd = egcd(b, d)[0]
    if gcd != 1:
        if a % gcd != c % gcd:
            raise ValueError('no solution')
        a, c = a - a % gcd, c - c % gcd
        a //= gcd
        b //= gcd
        c //= gcd
        d //= gcd
    x = a * d * modinv(d, b) + c * b * modinv(b, d)
    return (x - a) // b, (x - c) // d

And here's some test code that runs 1000 random trials of 1000-digit inputs:

import sys
sys.setrecursionlimit(10000)

import random

digit = '0123456789'

def rn(k):
    return int(''.join(random.choice(digit) for _ in xrange(k)), 10)

k = 1000

for _ in xrange(1000):
    a, b, c, d, = rn(k), rn(k), rn(k), rn(k)
    print a, b, c, d
    try:
        n1, n2 = solve(a, b, c, d)
    except ValueError, exn:
        print 'no solution'
        print
        continue
    if a + b * n1 != c + d * n2:
        raise AssertionError('failed!')
    print 'found solution:', n1, n2
    print

(Note, the recursion limit has to be increased because the egcd function which implements the Extended Euclidean algorithm is recursive, and running it on 1000 digit numbers can require a quite deep stack).

Also note, that this checks the result when a solution is returned. But when a != c (mod gcd(b, d)) and the exception is raised signalling no result, no check is done. So you need to think through if this can fail to find results when solutions do exist.

This runs (1000 trials) in around 7-8 seconds on my machine, so it performs reasonably well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM