プロジェクトオイラー
http://projecteuler.net/index.php?section=problems&id=210
これにもやはり数値計算上のトラップが。
この問題は、おおざっぱに言うと、円の内側にある格子点の個数を数える。
例えば、xy平面を考えて、中心が原点で半径rが10だとする。そのとき第1象限におけるy=7上の格子点の数は、√(100-49) = 7.14…だから、7つ。y=8なら、√(100-64) = 6だから、円周上の格子点は数えないので、5つ。これをまとめると、数学的には、
[√(r2 - y2 - 0.5)]
個とすればよい。
しかし、IEEE754の倍精度は15.6〜16桁程度しか精度がないので、整数が大きくなってくると0.5を引く手が使えなくなってくる。0.5を引いても値が変わらないのだ。例えば、半径が109で、y=8×108上の格子点の個数は、
from math import sqrtdef num_of_lattice_points(r, y):
return int(sqrt(r * r - y * y - 0.5))R = 10 ** 9
Y = 8 * 10 ** 8
print num_of_lattice_points(R, Y) # 600000000
となって、正しい答えより1個多くなってしまう。この場合、もう一度整数計算に戻って確認する必要がある。あるいは、sqrtの計算も整数計算にするか。
この問題は、このトラップが使えるギリギリの半径が与えられていた。