简体   繁体   English

如何快速检查 double 是否适合 float? (爪哇)

[英]How quickly check whether double fits in float? (Java)

Are there some arithmetic or bitwise operations that can check whether a double fits into a float without loss of precision.是否有一些算术或按位运算可以检查双精度是否适合浮点数而不会损失精度。

It should not only check that the double range is in the float range, but also that no mantissa bits get lost.它不仅应该检查双精度范围是否在浮点范围内,还要检查尾数位是否丢失。

Bye再见

PS: This answers the problem half way for C#: How to check if a double can fit into a float without conversion to infinity But I need a solution that works for Java. PS:这回答了 C# 的一半问题: How to check if a double can fit into a float without conversion to infinity但我需要一个适用于 Java 的解决方案。

How about this:这个怎么样:

double d = ...;
if ((double)(float)d == d) {
   System.out.println(d + " fits into float!");
}

The idea is pretty simple: We first cast to float and then back to double and check whether the result is still the same.这个想法很简单:我们首先转换为float然后返回double并检查结果是否仍然相同。 If d does not fit into float, then some precision would have been lost at the (float)d cast and thus the result would be different.如果d不适合 float,那么在(float)d转换时会丢失一些精度,因此结果会有所不同。

Strictly speaking, the cast back to double is not necessary as the comparision operator will do this cast implicitly, so (float)d == d is also fine.严格来说,转换回double是不必要的,因为比较运算符会隐式执行此转换,因此(float)d == d也可以。

If you are worried about the performance of this, because many float operations are a lot slower than comparable int operations: This is pretty much a non-issue here.如果您担心它的性能,因为许多浮点操作比可比较的 int 操作慢得多:这在这里几乎不是问题。 Conversion between float and double is extremely efficient in modern CPUs.在现代 CPU 中,float 和 double 之间的转换非常有效。 It can even be vectorized!它甚至可以被矢量化! There are the cvtpd2ps and cvtps2pd instructions in the SSE2 instruction set that perform the conversion from double to float and vice versa (4 values are converted at once). SSE2指令集中有cvtpd2pscvtps2pd指令,它们执行双浮点数和浮点数之间的转换(一次转换 4 个值)。 The instructions have a latency of 4 cycles on all Intel CPUs that support them.这些指令在支持它们的所有 Intel CPU 上都有 4 个周期的延迟。 4 cycles for 4 conversions is extremely fast. 4 次转换的 4 个周期非常快。

A straight-forward solution could look like this:一个直接的解决方案可能如下所示:

public class Scribble {
    public static void main(String[] args) {
        for (int i = 1; i <= 10; i++) {

            double d = 1d / ((double)i);
            float f = (float) d;

            boolean lossless = d == f;

            System.out.println(d + " can be converted " + (lossless ? "lossless" : "only with loss"));
        }
    }
}

it outputs:它输出:

1.0 can be converted lossless
0.5 can be converted lossless
0.3333333333333333 can be converted only with loss
0.25 can be converted lossless
0.2 can be converted only with loss
0.16666666666666666 can be converted only with loss
0.14285714285714285 can be converted only with loss
0.125 can be converted lossless
0.1111111111111111 can be converted only with loss
0.1 can be converted only with loss

edit: speed comparison shows, that method2 seems to be fastest:编辑:速度比较显示,method2 似乎最快:

 method1  |  method2  |  method3 
237094654 | 209365345 | 468025911
214129288 | 209917275 | 448695709
232093486 | 197637245 | 448153336
249210162 | 200163771 | 460200921
240685446 | 200638561 | 447061763
332890287 | 337870633 | 450452194
247054322 | 199045232 | 449442540
235533069 | 200767924 | 452743201
256274670 | 199153775 | 453373979
298277375 | 198659529 | 456672251
229360115 | 205883096 | 454198291
252680123 | 224850463 | 452860277
246047739 | 200070587 | 458091501
304270790 | 204517093 | 463688631
235058620 | 204675812 | 448639390
260565871 | 205834286 | 458372075
256008432 | 242574024 | 498943242
311210028 | 208080237 | 478777466
242014926 | 208995343 | 457901380
239893559 | 205111348 | 451616471

code:代码:

public class Scribble {

    static int size = 1024*1024*100;
    static boolean[] results = new boolean[size];
    static double[] values = new double[size];

    public static void main(String[] args) {

        // generate values
        for (int i = 0; i < size; i++)
            values[i] = 1d / ((double)i);

        long start;
        long duration;

        System.out.println(" method1  |  method2  |  method3 ");
        for (int i = 0; i < 20; i++) {
            start = System.nanoTime();
            method1(size);
            duration = System.nanoTime() - start;
            System.out.printf("%9d", duration);

            start = System.nanoTime();
            method2(size);
            duration = System.nanoTime() - start;
            System.out.printf(" | %9d", duration);

            start = System.nanoTime();
            method3(size);
            duration = System.nanoTime() - start;
            System.out.printf(" | %9d\n", duration);
        }
    }

    private static void method1(int size) {
        boolean[] results = new boolean[size];
        for (int i = 0; i < size; i++) {
            double d = values[i];
            float f = (float) d;

            boolean lossless = d == f;
            results[i] = lossless;
        }
    }

    private static void method2(int size) {
        for (int i = 0; i < size; i++) {
            double d = values[i];
            results[i] = d == (double)(float)d;
        }
    }

    private static void method3(int size) {
        for (int i = 0; i < size; i++) {
            double d = values[i];
            results[i] = Double.compare(d, (float) d) == 0;
        }
    }
}

Similarly to casting the number to float and back to double and checking for equality ( == ), Double.compare() can also be used:类似于将数字转换为float并返回到double float数并检查相等性 ( == ),也可以使用Double.compare()

double d = 2/3.0;

// 0 means OK, d fits into float
if (Double.compare(d, (float) d) == 0)
    System.out.println("OK, fits into float.");

Moreover, since comparing a float to double will implicitly cast the float to double , we can simply write:此外,由于比较一floatdouble将隐式转换的floatdouble ,我们可以简单的写:

if ((float) d == d)
    System.out.println("OK, fits into float.");

If you want to know if your double value fits the MAX and MIN range of float yout can´t use cast like (float)d == d because d may fits the float ranges but not necessary has the same decimals after cast.如果您想知道您的 double 值是否适合浮点数的 MAX 和 MIN 范围,则不能使用(float)d == d类的强制转换,因为 d 可能适合浮点数范围,但在强制转换后不必具有相同的小数。

In than case you must compare with Float.MAX_VALUE and Float.MIN_VALUE在这种情况下,您必须与Float.MAX_VALUEFloat.MIN_VALUE进行比较

return d <= Float.MAX_VALUE && d >= Float.MIN_VALUE;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM