java浮点有限性检查性能

标签 java performance floating-point ieee-754

哪个更快:

private static boolean isFinite(float x) {
    return !(x != x || x == Float.POSITIVE_INFINITY || x == Float.NEGATIVE_INFINITY);
}

private static boolean isFinite(float x) {
    return Float.NEGATIVE_INFINITY < x && x < Float.POSITIVE_INFINITY;
}

我尝试了一些微基准测试,但结果似乎很可疑。

最佳答案

我希望第二个更快,因为它进行的比较较少。然而差异非常小,计时结果将很大程度上取决于您的基准测试方式。

我会选择您认为最清晰、最简单的方法,并且 JVM 可能会对此进行最佳优化。

编辑:微基准测试的问题在于测试方式会影响结果。

private static boolean isFinite1(float x) {
    return Float.NEGATIVE_INFINITY < x && x < Float.POSITIVE_INFINITY;
}

private static boolean isFinite2(float x) {
    return !(x != x || x == Float.POSITIVE_INFINITY || x == Float.NEGATIVE_INFINITY);
}


public static void main(String[] args) {
    int nums = 10000;
    int runs = 10000;
    float[] floats = new float[nums];
    for (int i = 0; i < nums; i++) {
        double d = Math.random();
        floats[i] = d < 0.01 ? Float.NaN :
                d < 0.02 ? Float.NEGATIVE_INFINITY :
                        d < 0.03 ? Float.POSITIVE_INFINITY : (float) d;
    }

    for (int n = 0; n < 10; n++) {
        {
            int count1 = 0, count2 = 0;
            long timeA = System.nanoTime();
            for (int i = 0; i < runs; i++)
                for (float f : floats)
                    if (isFinite1(f)) count1++;

            long timeB = System.nanoTime();
            for (int i = 0; i < runs; i++)
                for (float f : floats)
                    if (isFinite2(f)) count2++;

            long timeC = System.nanoTime();

            long total1 = timeB - timeA;
            long total2 = timeC - timeB;
            assert count1 == count2;

            System.out.printf("1,2: isFinite1 took %.1f ns and isFinite2 took %.1f ns on average%n", (double) total1 / runs / nums, (double) total2 / runs / nums);
        }

        {
            int count1 = 0, count2 = 0;
            long timeA = System.nanoTime();
            for (int i = 0; i < runs; i++)
                for (float f : floats)
                    if (isFinite2(f)) count1++;

            long timeB = System.nanoTime();
            for (int i = 0; i < runs; i++)
                for (float f : floats)
                    if (isFinite1(f)) count2++;

            long timeC = System.nanoTime();

            long total1 = timeB - timeA;
            long total2 = timeC - timeB;
            assert count1 == count2;

            System.out.printf("2,1: isFinite1 took %.1f ns and isFinite2 took %.1f ns on average%n", (double) total1 / runs / nums, (double) total2 / runs / nums);
        }
    }
}

打印

1,2: isFinite1 took 1.5 ns and isFinite2 took 5.1 ns on average
2,1: isFinite1 took 3.6 ns and isFinite2 took 4.4 ns on average
1,2: isFinite1 took 1.5 ns and isFinite2 took 5.1 ns on average
2,1: isFinite1 took 3.6 ns and isFinite2 took 4.4 ns on average
1,2: isFinite1 took 1.5 ns and isFinite2 took 5.2 ns on average
2,1: isFinite1 took 3.6 ns and isFinite2 took 4.4 ns on average

正如您所看到的,即使我测试这些的顺序也会产生很大的差异。

比所涉及的操作更重要的是优化分支数量以及分支预测的工作效果。 http://www.agner.org/optimize/microarchitecture.pdf

假设我将不同值的可能性提高了 25 倍,因此每个范围的可能性相同。

        floats[i] = d < 0.25 ? Float.NaN :
                d < 0.5 ? Float.NEGATIVE_INFINITY :
                d < 0.75 ? Float.POSITIVE_INFINITY : (float) d;

这一切都增加了代码通过不同路径的机会。

1,2: isFinite1 took 8.5 ns and isFinite2 took 14.2 ns on average
2,1: isFinite1 took 10.9 ns and isFinite2 took 11.5 ns on average
1,2: isFinite1 took 7.2 ns and isFinite2 took 14.4 ns on average
2,1: isFinite1 took 11.0 ns and isFinite2 took 11.5 ns on average
1,2: isFinite1 took 7.3 ns and isFinite2 took 14.2 ns on average
2,1: isFinite1 took 10.8 ns and isFinite2 took 11.5 ns on average

我再说一遍,更清晰的代码应该是您的目标! ;)

关于java浮点有限性检查性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5744044/

相关文章:

java - 每个索引中具有不同大小的二维数组的 3 维数组

c++ - 重新初始化 vector 的最快方法是什么?

python - 截断 f 字符串 float 而不舍入

ios - 随机 float 的数学方程式?

objective-c - 获取 NSString 的 floatvalue 时用点替换逗号

java - 无法从 java 文件 Intellij id 导入 proto 文件

java - 在Java中是否可以导入数组类型?

Java - 函数分析

c# - 调用空函数需要多长时间?

java - 有没有办法(例如 Eclipse 插件)从实体(JPA)自动生成 DTO?