整数演算に浮動小数点を使用することを考えている場合は、注意が必要です。
私は通常、可能な限り FP 計算を避けるようにしています。
浮動小数点演算は正確ではありません。何が(int)(Math.log(65536)/Math.log(2))
評価されるかを確実に知ることはできません。たとえば、Math.ceil(Math.log(1<<29) / Math.log(2))
私の PC では 30 ですが、数学的には正確に 29 になるはずです。(int)(Math.log(x)/Math.log(2))
失敗する x の値は見つかりませんでした (「危険な」値が 32 個しかないため)。どのPCでも同じです。
ここでの通常のトリックは、丸めの際に「イプシロン」を使用することです。Like(int)(Math.log(x)/Math.log(2)+1e-10)
は決して失敗してはなりません。この「イプシロン」の選択は簡単な作業ではありません。
より一般的なタスクを使用したより多くのデモンストレーション - 実装しようとしていますint log(int x, int base)
:
テストコード:
static int pow(int base, int power) {
int result = 1;
for (int i = 0; i < power; i++)
result *= base;
return result;
}
private static void test(int base, int pow) {
int x = pow(base, pow);
if (pow != log(x, base))
System.out.println(String.format("error at %d^%d", base, pow));
if(pow!=0 && (pow-1) != log(x-1, base))
System.out.println(String.format("error at %d^%d-1", base, pow));
}
public static void main(String[] args) {
for (int base = 2; base < 500; base++) {
int maxPow = (int) (Math.log(Integer.MAX_VALUE) / Math.log(base));
for (int pow = 0; pow <= maxPow; pow++) {
test(base, pow);
}
}
}
対数の最も単純な実装を使用すると、
static int log(int x, int base)
{
return (int) (Math.log(x) / Math.log(base));
}
これは次のように表示されます:
error at 3^5
error at 3^10
error at 3^13
error at 3^15
error at 3^17
error at 9^5
error at 10^3
error at 10^6
error at 10^9
error at 11^7
error at 12^7
...
エラーを完全に取り除くには、1e-11 と 1e-14 の間のイプシロンを追加する必要がありました。テストの前にこれを言うことができましたか?私は絶対にできませんでした。