この程度の大きさの数なら問題ありませんが、実数の計算にはどうしても誤差がつきまといます。しかし、今回の計算は誤差無しで計算することができます。
(a + b√5) / c -> (a, b, c)
と表すことにしましょう。そうすると、
(a, b, c) + (d, e, f) = (af + dc, bf + ec, cf)
となります。ただし、このあと約分が必要です。乗算は、
(a, b, c) * (d, e, f) = (ad + 5be, ae + bd, cf)
逆数は、
(a, b, c)-1 = (ac, -bc, a2 - 5b2)
これで、四則演算はできることになります。
また、整数との大きさの比較は、
(a, b, c) - (d, 0, 1) = (a - cd, b, c)
だから、(a - cd)2と5b2の比較をすればよいです。
logの計算だけはさすがにできません。
from fractions import gcd
from math import sqrt, logdef lcm(x, y):
return x * y / gcd(x, y)def f_reduce(x, y):
c = lcm(x[2], y[2])
if c != x[2]:
d = c / x[2]
return (x[0] * d, x[1] * d, x[2] * d)
else:
return xdef cancel_down(x):
c = reduce(gcd, x)
if c != 1:
return (x[0] / c, x[1] / c, x[2] / c)
else:
return xdef f_add(x, y):
x = f_reduce(x, y)
y = f_reduce(y, x)
return cancel_down( (x[0] + y[0], x[1] + y[1], x[2]) )def f_sub(x, y):
x = f_reduce(x, y)
y = f_reduce(y, x)
return cancel_down( (x[0] - y[0], x[1] - y[1], x[2]) )def f_mul(x, y):
z = (x[0] * y[0] + x[1] * y[1] * D, x[0] * y[1] + x[1] * y[0], x[2] * y[2])
return cancel_down(z)def f_inv(x):
z = (x[0] * x[2], -x[1] * x[2], x[0] * x[0] - x[1] * x[1] * D)
return cancel_down(z)def f_div(x, y):
return f_mul(x, f_inv(y))def f_value(x):
return (x[0] + x[1] * sqrt(D)) / x[2]def f_pow(x, n):
if n == 0:
return (1, 0, 1)
y = f_pow(x, n / 2)
sq = f_mul(y, y)
if n % 2 == 1:
return f_mul(x, sq)
else:
return sqdef round_sqrt(n):
x, y = 0, 1
while x != y:
x, y = y, (y + (n + y - 1) / y) / 2
return xdef f_round(x):
n = x[1] ** 2 * D
return (x[0] + round_sqrt(x[1] ** 2 * D) + x[2] / 2) / x[2]N = 4 * 10 ** 6
D = 5
a = (1, -1, 2)
b = (1, 1, 2)
f0, f1 = (1, 0, 1), (2, 0, 1)
c = f_div(f_mul(b, f_sub(f1, f_mul(f0, a))), f_sub(b, a))
m_max = int(log( (N + 0.5) / f_value(c)) / (3 * log(f_value(b))))
x = f_div(f_mul(c, f_sub(f_pow(b, 3 * m_max + 3), (1, 0, 1))),
f_sub(f_pow(b, 3), (1, 0, 1)))
print f_round(x)