本当に必要なのは
ceil(12 * log2(/* something */))
次に、12個の値のみのテーブルを使用して機能する非常に単純なO(1)計算があります。
frexp()を使用して、値を指数と仮数に分割します。(これはほんの少しの操作なので、数サイクルかかります。)
2.0の12番目の根(2で割った値)の累乗の事前計算されたリストで仮数を調べます。これは、最大4つの比較で実行できます。
結果は、12 *(指数-1)+最小ルートのインデックス>=仮数です。
追加するために編集:
2の12乗根の累乗が適度に均等に分散されるため、実際にはさらに優れた解決策があります。[0.5、1.0)(frexpによって返される仮数の範囲)を17の等間隔のサブ範囲に分割すると、各サブ範囲は2つの可能な戻り値のいずれかに分類されます。したがって、各サブ範囲をルートのベクトルへのインデックスに関連付ける場合は、ターゲット(その範囲内)を単一のルートと比較するだけで済みます。
私が首尾一貫した英語を書くには遅すぎるので、あなたはコードに落ち着く必要があります:
int Ceil12TimesLog2(double x) {
int exp;
double mantissa = std::frexp(x, &exp) * 2;
int idx = indexes[int((mantissa - 1.0) * 17)];
return 12 * (exp - 1) + (mantissa <= roots[idx] ? idx : idx + 1);
}
// Here are the reference tables.
double roots[12] = {
0x1.0000000000000p+0,
0x1.0f38f92d97963p+0,
0x1.1f59ac3c7d6c0p+0,
0x1.306fe0a31b715p+0,
0x1.428a2f98d728bp+0,
0x1.55b8108f0ec5ep+0,
0x1.6a09e667f3bccp+0,
0x1.7f910d768cfb0p+0,
0x1.965fea53d6e3dp+0,
0x1.ae89f995ad3adp+0,
0x1.c823e074ec129p+0,
0x1.e3437e7101344p+0
};
int indexes[17] = { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11 };
これを試してみたところ、OPのループを使用して、合計計算時間が約0.5秒(log2fの場合)から約0.15秒に短縮されました。参照テーブルの合計サイズは164バイトです。