#! /usr/bin/env python
# C++ Fibonacci challenge
# 10.02.2012 cmiN
# exponentiere a matricei Q fibonacci
# in timp logaritmic folosind numere mari
from decimal import getcontext, Decimal as D
class CFib:
"""
Clasa pentru a calcula CMMDCul a 2 numere din seria Fibonacci.
Se stie ca cmmdc(fib(a), fib(b)) e acelasi lucru cu fib(cmmdc(a, b))
unde fib(x) este al x-lea numar din serie. Acesta poate fi calculat
foarte rapid cu ridicarea unei matrice 2x2 specifice folosind
ridicare la putere in logN.
Totusi avem nevoie si de numere mari (decimal) ;].
"""
def __init__(self, a, b):
# setam precizia in zecimale
getcontext().prec = 7000 # nici al 30k-lea nu depaseste
self.a = a
self.b = b
self.qmat = ((1, 1),
(1, 0))
self.res = ((D(1), D(0)), # I2
(D(0), D(1)))
def cmmdc(self, a, b):
""" Euclid cu impartiri. """
while b != 0:
t = a
a = b
b = t % b
return a
def multiply(self, op=False):
if op: # op e True cand inmultim noua matrice Q cu rezultatul
mat = self.res # doar o referinta / un sinonim catre un obiect
else: # si False cand ridicam la patrat si retinem matricea Q
mat = self.qmat
# prea lenes sa bag 3 foruri
e1 = mat[0][0] * self.qmat[0][0] + mat[0][1] * self.qmat[1][0]
e2 = mat[0][0] * self.qmat[0][1] + mat[0][1] * self.qmat[1][1]
e3 = mat[1][0] * self.qmat[0][0] + mat[1][1] * self.qmat[1][0]
e4 = mat[1][0] * self.qmat[0][1] + mat[1][1] * self.qmat[1][1]
# modificam rezultatul cu noile valori
mat = ((e1, e2),
(e3, e4))
if op:
self.res = mat
else:
self.qmat = mat
def process(self):
""" Functia principala. """
nr = self.cmmdc(self.a, self.b)
#print nr # debug
# acum ridicam pe res la nr
while nr > 0:
if nr % 2: # putere impara
self.multiply(True) # inmultim cu rezultatul
self.multiply() # multiplicam qmat
nr /= 2
def get(self):
return str(self.res[0][1]) # (Q^n)[0][1] == F(n)
def main():
(a, b) = raw_input("Introdu 2 numere: ").split()
obj = CFib(int(a), int(b))
obj.process()
print "\nOutput:", obj.get()
if __name__ == "__main__":
main()
IyEgL3Vzci9iaW4vZW52IHB5dGhvbgojIEMrKyBGaWJvbmFjY2kgY2hhbGxlbmdlCiMgMTAuMDIuMjAxMiBjbWlOCiMgZXhwb25lbnRpZXJlIGEgbWF0cmljZWkgUSBmaWJvbmFjY2kKIyBpbiB0aW1wIGxvZ2FyaXRtaWMgZm9sb3NpbmQgbnVtZXJlIG1hcmkKCgpmcm9tIGRlY2ltYWwgaW1wb3J0IGdldGNvbnRleHQsIERlY2ltYWwgYXMgRAoKCmNsYXNzIENGaWI6CiAgICAiIiIKICAgIENsYXNhIHBlbnRydSBhIGNhbGN1bGEgQ01NREN1bCBhIDIgbnVtZXJlIGRpbiBzZXJpYSBGaWJvbmFjY2kuCiAgICBTZSBzdGllIGNhIGNtbWRjKGZpYihhKSwgZmliKGIpKSBlIGFjZWxhc2kgbHVjcnUgY3UgZmliKGNtbWRjKGEsIGIpKQogICAgdW5kZSBmaWIoeCkgZXN0ZSBhbCB4LWxlYSBudW1hciBkaW4gc2VyaWUuIEFjZXN0YSBwb2F0ZSBmaSBjYWxjdWxhdAogICAgZm9hcnRlIHJhcGlkIGN1IHJpZGljYXJlYSB1bmVpIG1hdHJpY2UgMngyIHNwZWNpZmljZSBmb2xvc2luZAogICAgcmlkaWNhcmUgbGEgcHV0ZXJlIGluIGxvZ04uCiAgICBUb3R1c2kgYXZlbSBuZXZvaWUgc2kgZGUgbnVtZXJlIG1hcmkgKGRlY2ltYWwpIDtdLgogICAgIiIiCiAgICAKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBhLCBiKToKICAgICAgICAjIHNldGFtIHByZWNpemlhIGluIHplY2ltYWxlCiAgICAgICAgZ2V0Y29udGV4dCgpLnByZWMgPSA3MDAwICMgbmljaSBhbCAzMGstbGVhIG51IGRlcGFzZXN0ZQogICAgICAgIHNlbGYuYSA9IGEKICAgICAgICBzZWxmLmIgPSBiCiAgICAgICAgc2VsZi5xbWF0ID0gKCgxLCAxKSwKICAgICAgICAgICAgICAgICAgICAgKDEsIDApKQogICAgICAgIHNlbGYucmVzID0gKChEKDEpLCBEKDApKSwgIyBJMgogICAgICAgICAgICAgICAgICAgIChEKDApLCBEKDEpKSkKCiAgICBkZWYgY21tZGMoc2VsZiwgYSwgYik6CiAgICAgICAgIiIiIEV1Y2xpZCBjdSBpbXBhcnRpcmkuICIiIgogICAgICAgIHdoaWxlIGIgIT0gMDoKICAgICAgICAgICAgdCA9IGEKICAgICAgICAgICAgYSA9IGIKICAgICAgICAgICAgYiA9IHQgJSBiCiAgICAgICAgcmV0dXJuIGEKCiAgICBkZWYgbXVsdGlwbHkoc2VsZiwgb3A9RmFsc2UpOgogICAgICAgIGlmIG9wOiAjIG9wIGUgVHJ1ZSBjYW5kIGlubXVsdGltIG5vdWEgbWF0cmljZSBRIGN1IHJlenVsdGF0dWwKICAgICAgICAgICAgbWF0ID0gc2VsZi5yZXMgIyBkb2FyIG8gcmVmZXJpbnRhIC8gdW4gc2lub25pbSBjYXRyZSB1biBvYmllY3QKICAgICAgICBlbHNlOiAjIHNpIEZhbHNlIGNhbmQgcmlkaWNhbSBsYSBwYXRyYXQgc2kgcmV0aW5lbSBtYXRyaWNlYSBRCiAgICAgICAgICAgIG1hdCA9IHNlbGYucW1hdAogICAgICAgICMgcHJlYSBsZW5lcyBzYSBiYWcgMyBmb3J1cmkKICAgICAgICBlMSA9IG1hdFswXVswXSAqIHNlbGYucW1hdFswXVswXSArIG1hdFswXVsxXSAqIHNlbGYucW1hdFsxXVswXQogICAgICAgIGUyID0gbWF0WzBdWzBdICogc2VsZi5xbWF0WzBdWzFdICsgbWF0WzBdWzFdICogc2VsZi5xbWF0WzFdWzFdCiAgICAgICAgZTMgPSBtYXRbMV1bMF0gKiBzZWxmLnFtYXRbMF1bMF0gKyBtYXRbMV1bMV0gKiBzZWxmLnFtYXRbMV1bMF0KICAgICAgICBlNCA9IG1hdFsxXVswXSAqIHNlbGYucW1hdFswXVsxXSArIG1hdFsxXVsxXSAqIHNlbGYucW1hdFsxXVsxXQogICAgICAgICMgbW9kaWZpY2FtIHJlenVsdGF0dWwgY3Ugbm9pbGUgdmFsb3JpCiAgICAgICAgbWF0ID0gKChlMSwgZTIpLAogICAgICAgICAgICAgICAoZTMsIGU0KSkKICAgICAgICBpZiBvcDoKICAgICAgICAgICAgc2VsZi5yZXMgPSBtYXQKICAgICAgICBlbHNlOgogICAgICAgICAgICBzZWxmLnFtYXQgPSBtYXQKCiAgICBkZWYgcHJvY2VzcyhzZWxmKToKICAgICAgICAiIiIgRnVuY3RpYSBwcmluY2lwYWxhLiAiIiIKICAgICAgICBuciA9IHNlbGYuY21tZGMoc2VsZi5hLCBzZWxmLmIpCiAgICAgICAgI3ByaW50IG5yICMgZGVidWcKICAgICAgICAjIGFjdW0gcmlkaWNhbSBwZSByZXMgbGEgbnIKICAgICAgICB3aGlsZSBuciA+IDA6CiAgICAgICAgICAgIGlmIG5yICUgMjogIyBwdXRlcmUgaW1wYXJhCiAgICAgICAgICAgICAgICBzZWxmLm11bHRpcGx5KFRydWUpICMgaW5tdWx0aW0gY3UgcmV6dWx0YXR1bAogICAgICAgICAgICBzZWxmLm11bHRpcGx5KCkgIyBtdWx0aXBsaWNhbSBxbWF0CiAgICAgICAgICAgIG5yIC89IDIKCiAgICBkZWYgZ2V0KHNlbGYpOgogICAgICAgIHJldHVybiBzdHIoc2VsZi5yZXNbMF1bMV0pICMgKFFebilbMF1bMV0gPT0gRihuKQogICAgICAgIAoKZGVmIG1haW4oKToKICAgIChhLCBiKSA9IHJhd19pbnB1dCgiSW50cm9kdSAyIG51bWVyZTogIikuc3BsaXQoKQogICAgb2JqID0gQ0ZpYihpbnQoYSksIGludChiKSkKICAgIG9iai5wcm9jZXNzKCkKICAgIHByaW50ICJcbk91dHB1dDoiLCBvYmouZ2V0KCkKCgppZiBfX25hbWVfXyA9PSAiX19tYWluX18iOgogICAgbWFpbigpCg==