きれいに書けないループ

ちょっとした疑問,兼 Euler 302 反省会。いろいろミスしたのだけど一番しょうもないやつ。

N > n * p^e となる e についてループしたい。どう書きましょう,というお話。

素直に書くと

for (long n1 = n * p; n1 < N; n1 *= p) {
  ...
}

ですが,N, p が大きいと n1 *= p で溢れるに決まってます。

それでしかたがないので

double e1 = (log(N/n)) / log(p);
long pp = p;
for (int e = 1; e < e1; e++, pp *= p) {
  ...
}

というふうな調子で書いてみましたが,これは正しく動作しませんでした。N = n * 243, p = 3 のときのように e1 の真の値が整数になる場合に,ループの回数が過剰だったり不足したりする可能性があります。

しょうがないのでむりやり直したバージョン。

double eps = 1e-10;
double e1 = (log(N/n)) / log(p) + eps;
long pp = p;
for (int e = 1; e < e1; e++, pp *= p) {
  long n1 = n * pp;
  if (n1 >= N) break;
  ...
}

今回は N = 10^18 だったので,e1 を少し大きめに見積もったせいで N を少し超えたとしても溢れないという楽観的な予想。

あまり美しくない。もっといい方法ありませんか。