昨日ひどかったので考え直してみました。要するに試し割りの回数がわかればいいのです。もちろんわからないので、n前後の試し割りの回数の平均を求めます。ガウスの故事に倣って1000個ずつ取って平均します。なるべく長いスパンで見たいので、平均を取る範囲の始まりを1.2倍ずつしていきます。ただし、最初は1000から始まって2倍ずつします。32ビット整数の範囲ギリギリまで計算しましたが、計算時間は一瞬でした。
from itertools import * from math import sqrt def sieve(max_n): a = [ True ] * (max_n + 1) for p in (n for n in takewhile(lambda n: n * n <= max_n, count(2)) if a[n]): for k in xrange(p * p, max_n + 1, p): a[k] = False return [ n for n in xrange(2, max_n + 1) if a[n] ] def pows(first, last, ratio): n = first while n < last: yield n n = int(n * ratio) def mean_num_divs(first, last): a = [ len(primes) ] * (last - first) for k, (p, p_next) in enumerate(izip(primes, islice(primes, 1, None))): for l in xrange(max(first, p * p), min(last, p_next * p_next)): a[l-first] = k + 1 b = [ last ] * (last - first) for k, p in enumerate(takewhile(lambda p: p * p < last, primes)): for l in xrange((first + p - 1) / p * p, last, p): b[l-first] = min(b[l-first], k + 1) return sum(min(m, n) for m, n in izip(a, b)) / float(last - first) N = 21 * 10 ** 8 L = 1000 primes = sieve(int(sqrt(N))) gen_starts = chain(pows(1000, 10000, 2.0), pows(10000, N, 1.2)) for start in gen_starts: print start + L / 2, mean_num_divs(start, start + L)
対数軸表示してみましたが、直線に乗りませんね。
しかし、なぜか(logn)3を掛けると、かなりきれいに直線に乗ります。