Java 如何实施;“快速平方根逆”;在爪哇?

Java 如何实施;“快速平方根逆”;在爪哇?,java,floating-point,square-root,Java,Floating Point,Square Root,我听说过“快速平方根逆”,我想把它放在我的Java程序中(只是为了研究目的,所以忽略关于本机库速度更快的任何内容) 我在看代码,C代码直接将float转换成int,使用一些C指针魔法。如果您试图在Java中使用强制转换来实现这一点,那么它是行不通的:Java会截断浮点(正如您所期望的那样),并且您无法获得原语的指针(就像在C中一样)。 那么您是如何做到这一点的呢?请记住,在使用此工具之前,要对代码进行基准测试。 如果事实证明您不需要它,或者您正在使用的CPU架构速度较慢,那么最好不要在项目中使用

我听说过“快速平方根逆”,我想把它放在我的Java程序中(只是为了研究目的,所以忽略关于本机库速度更快的任何内容)

我在看代码,C代码直接将
float
转换成
int
,使用一些C指针魔法。如果您试图在Java中使用强制转换来实现这一点,那么它是行不通的:Java会截断浮点(正如您所期望的那样),并且您无法获得原语的指针(就像在C中一样)。 那么您是如何做到这一点的呢?

请记住,在使用此工具之前,要对代码进行基准测试。 如果事实证明您不需要它,或者您正在使用的CPU架构速度较慢,那么最好不要在项目中使用这种迟钝的代码


Java库有一种从浮点数到原始位的方法

正如在java文档中看到的
java.lang.Float
(),我们有
floatToIntBits
函数,以及
intBitsToFloat

这意味着我们可以用Java编写“快速平方根逆”,如下所示:

public static float invSqrt(float x) {
    float xhalf = 0.5f * x;
    int i = Float.floatToIntBits(x);
    i = 0x5f3759df - (i >> 1);
    x = Float.intBitsToFloat(i);
    x *= (1.5f - xhalf * x * x);
    return x;
}
以下是双打的版本:

public static double invSqrt(double x) {
    double xhalf = 0.5d * x;
    long i = Double.doubleToLongBits(x);
    i = 0x5fe6ec85e7de30daL - (i >> 1);
    x = Double.longBitsToDouble(i);
    x *= (1.5d - xhalf * x * x);
    return x;
}
来源:

,即使是双精度的1也可以返回0.9983227945440889作为1的平方根

为了提高准确性,您可以使用我制作的此版本:

public static double Q_rsqrt(double number){
    double x = number;
    double xhalf = 0.5d*x;
    long i = Double.doubleToLongBits(x);
    i = 0x5fe6ec85e7de30daL - (i>>1);
    x = Double.longBitsToDouble(i);
    for(int it = 0; it < 4; it++){
        x = x*(1.5d - xhalf*x*x);
    }
    x *= number;
    return x;
}
公共静态双Q_rsqrt(双倍数字){
双x=数字;
双xhalf=0.5d*x;
长i=双倍。双倍到长位(x);
i=0x5fe6ec85e7de30daL-(i>>1);
x=双精度。长比特双精度(i);
for(int it=0;it<4;it++){
x=x*(1.5d-xhalf*x*x);
}
x*=数字;
返回x;
}

您可以根据需要编辑for循环终止之前的时间,但4次似乎可以使其降至双精度的最大精度。如果你想获得完美的精确度(或者如果你不想被长串的小数困扰),请使用这个版本。

我不明白为什么,但循环会起作用,解决了奇怪值的问题
0.998…
。Thanks@56ka循环中的线是牛顿方法的迭代。通过增加3次迭代,它以大量操作为代价提高了精度。事实上,现在我更仔细地看了看,这个计算sqrt不是在反向sqrt中吗?显然,1.0的问题在于它们是相同的,但是如果我仍然将4.0添加到代码中,它会给我2。invSqrtAnyone知道0x5fe6ec85e7de30daL从0x5f3759df的推导吗?@micycle这些特定常数的推导随着时间的推移而丢失,而这些实际上并不是最佳常数,只是著名的常数。您可以在某处找到最佳常数搜索代码。