Java:Math.sqrt()的32位fp实现

Java:Math.sqrt()的32位fp实现,java,performance,math,32-bit,Java,Performance,Math,32 Bit,标准的Math.sqrt()方法在Java中似乎已经相当快了,但它有一个固有的缺点,即它总是涉及64位操作,这在处理32位浮点值时只会降低速度。使用使用float作为参数、仅执行32位操作并返回float作为结果的自定义方法是否可以做得更好 我看到: 它只是强化了Math.sqrt()通常很难击败的概念。我还看到: 这向我展示了一系列有趣的C++/ASM攻击,我太无知了,无法直接移植到Java。虽然sqrt14作为JNI调用的一部分可能很有趣 我还研究了ApacheCommonsFastMa

标准的
Math.sqrt()
方法在Java中似乎已经相当快了,但它有一个固有的缺点,即它总是涉及64位操作,这在处理32位
浮点值时只会降低速度。使用使用
float
作为参数、仅执行32位操作并返回
float
作为结果的自定义方法是否可以做得更好

我看到:

它只是强化了Math.sqrt()通常很难击败的概念。我还看到:

这向我展示了一系列有趣的C++/ASM攻击,我太无知了,无法直接移植到Java。虽然sqrt14作为JNI调用的一部分可能很有趣

我还研究了ApacheCommonsFastMath,但该库似乎默认为标准的Math.sqrt(),因此没有帮助。然后是Yeppp!:


但我还没有为此烦恼。

正如你似乎知道的JNI:

只需从C的标准库
math.h
double sqrt(double)
float sqrt(float)
编写一个最小包装器,并比较性能


提示:除非执行大量的平方根运算,否则您不会感觉到有什么不同,然后使用SIMD指令同时执行多个SQRT的性能优势很可能会主导效果。您需要从Java获得一个浮点值的内存对齐数组,若您使用Java标准库,这可能非常困难。

对于32位值,您不需要任何东西来加速
sqrt
。HotSpot JVM会自动为您执行此操作

JIT编译器足够聪明,可以识别
f2d->Math.sqrt()->d2f
模式,并用更快的
sqrtss
CPU指令代替
sqrtsd

基准:

@State(Scope.Benchmark)
public class Sqrt {
    double d = Math.random();
    float f = (float) d;

    @Benchmark
    public double sqrtD() {
        return Math.sqrt(d);
    }

    @Benchmark
    public float sqrtF() {
        return (float) Math.sqrt(f);
    }
}
结果是:

Benchmark    Mode  Cnt       Score      Error   Units
Sqrt.sqrtD  thrpt    5  145501,072 ± 2211,666  ops/ms
Sqrt.sqrtF  thrpt    5  223657,110 ± 2268,735  ops/ms

我不太确定您是否能获得希望获得的速度优势“64位操作……在处理32位浮点值时除了降低速度外什么都不做”是一个谬误。一般来说,浮点运算总是以FPU的精度执行,开销来自于将
float
操作数扩大和缩小到
double
,以适应FPU。@EJP对于
sqrtsd
vs
sqrtss
,这是正确的,但从Java的角度来看,您当然无法控制它。至于像你描述的那样工作的老式FPU,它基本上是过时的(并且在某些Intel原子中严重受损)有趣!每天学习新的东西。