[0, 2*10^12] の入力範囲の double 値の Java での高速な平方根の実装を探しています。この範囲内の任意の値の場合、精度は小数点以下 5 桁までにする必要があります。Math.sqrt()
つまり、結果は小数点以下 5 桁以降のメソッドとは異なる場合があります。ただし、この方法は よりもはるかに高速である必要がありますMath.sqrt()
。
何か案は?ありがとう!
[0, 2*10^12] の入力範囲の double 値の Java での高速な平方根の実装を探しています。この範囲内の任意の値の場合、精度は小数点以下 5 桁までにする必要があります。Math.sqrt()
つまり、結果は小数点以下 5 桁以降のメソッドとは異なる場合があります。ただし、この方法は よりもはるかに高速である必要がありますMath.sqrt()
。
何か案は?ありがとう!
コードをウォームアップする時間を与えたら。Math.sqrt() はかなり高速です
static double[] values = new double[500 * 1000];
public static void main(String... args) {
for (int i = 0; i < values.length; i++) values[i] = i;
for (int j = 0; j < 5; j++) {
long start = System.nanoTime();
for (int i = 1; i < values.length; i++) {
values[i] = Math.sqrt(values[i]);
}
long time = System.nanoTime() - start;
System.out.printf("Took %d ns to Math.sqrt on average%n", time / values.length);
}
}
版画
Took 20 ns to Math.sqrt on average
Took 22 ns to Math.sqrt on average
Took 9 ns to Math.sqrt on average
Took 9 ns to Math.sqrt on average
Took 9 ns to Math.sqrt on average
(これが間違っていることを証明するベンチマークがなければ) 純粋な Java実装がMath.sqrt()
. Oracle JRE 実装とOpenJDK 実装はどちらもネイティブ実装です。
これを試して
double d = 289358932.0;
double sqrt = Double.longBitsToDouble( ( ( Double.doubleToLongBits( d )-(1l<<52) )>>1 ) + ( 1l<<61 ) );
ベンチマークはしていませんが、もっと速いと思います。精度はあまり良くありませんが、試してみて、ニーズに合っているかどうかを確認してください。式の最後にバイアス項を追加a
して、より正確にすることができると思います。
編集:ニュートン法を1ラウンドまたは2ラウンド通過させることで、精度を大幅に向上させることができます
double better = (sqrt + d/sqrt)/2.0;
double evenbetter = (better + d/better)/2.0;
2 番目のパスでは、平方根のほぼ正確な値が得られます。
sqrt 17022.533813476562
better 17010.557763511835
evenbetter 17010.553547724947
Math.sqrt() 17010.553547724423