java 如何准确确定双精度值是否为整数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12077731/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 07:30:35  来源:igfitidea点击:

How can I accurately determine if a double is an integer?

javafloating-point

提问by asteri

Specifically in Java, how can I determine if a doubleis an integer? To clarify, I want to know how I can determine that the double does not in fact contain any fractions or decimals.

特别是在 Java 中,如何确定 adouble是否为整数?为了澄清,我想知道如何确定 double 实际上不包含任何分数或小数。

I am concerned essentially with the nature of floating-point numbers. The methods I thought of (and the ones I found via Google) follow basically this format:

我主要关心浮点数的性质。我想到的方法(以及我通过 Google 找到的方法)基本上遵循以下格式:

double d = 1.0;
if((int)d == d) {
    //do stuff
}
else {
    // ...
}

I'm certainly no expert on floating-point numbers and how they behave, but I am under the impression that because the doublestores only an approximationof the number, the if()conditional will only enter someof the time (perhaps even a majorityof the time). But I am looking for a method which is guaranteed to work 100% of the time, regardless of how the doublevalue is stored in the system.

我当然不是浮点数及其行为方面的专家,但我的印象是,因为double存储的只是数字的近似值,所以if()条件只会进入某些时间(甚至可能是大部分时间) )。但我正在寻找一种方法,无论该double值如何存储在系统中,都可以保证 100% 的时间有效。

Is this possible? If so, how and why?

这可能吗?如果是这样,如何以及为什么?

回答by nneonneo

doublecan store an exact representation of certain values, such as small integers and (negative or positive) powers of two.

double可以存储某些值的精确表示,例如小整数和 2 的(负或正)幂。

If it does indeed store an exact integer, then ((int)d == d)works fine. And indeed, for any 32-bit integer i, (int)((double)i) == isince a double can exactly represent it.

如果它确实存储了一个精确的整数,那么((int)d == d)工作正常。事实上,对于任何 32 位整数 i,(int)((double)i) == i因为 double 可以准确地表示它。

Note that for very large numbers (greater than about 2**52 in magnitude), a double will always appear to be an integer, as it will no longer be able to store any fractional part. This has implications if you are trying to cast to a Java long, for instance.

请注意,对于非常大的数字(幅度大于约 2**52),double 将始终显示为整数,因为它将不再能够存储任何小数部分。例如,如果您尝试转换为 Java long,这会产生影响。

回答by Squidly

How about

怎么样

 if(d % 1 == 0)

This works because all integers are 0 modulo 1.

这是有效的,因为所有整数都是 0 模 1。

EditTo all those who object to this on the grounds of it being slow, I profiled it, and found it to be about 3.5 times slower than casting. Unless this is in a tight loop, I'd say this is a preferable way of working it out, because it's extremely clear what you're testing, and doesn't require any though about the semantics of integer casting.

编辑对于所有以速度慢为由反对此方法的人,我对其进行了分析,发现它比铸造慢约 3.5 倍。除非这是在一个紧密的循环中,否则我会说这是解决它的一种更可取的方法,因为它非常清楚您正在测试的内容,并且不需要任何关于整数转换语义的信息。

I profiled it by running time on javac of

我通过在 javac 上的运行时间对其进行了分析

class modulo {
    public static void main(String[] args) {
        long successes = 0;
        for(double i = 0.0; i < Integer.MAX_VALUE; i+= 0.125) {
            if(i % 1 == 0)
                successes++;
        }
        System.out.println(successes);
    }
}

VS

VS

class cast {
    public static void main(String[] args) {
        long successes = 0;
        for(double i = 0.0; i < Integer.MAX_VALUE; i+= 0.125) {
            if((int)i == i)
                successes++;
        }
        System.out.println(successes);
    }
}

Both printed 2147483647 at the end.
Modulo took 189.99s on my machine - Cast took 54.75s.

最后都打印了 2147483647。
Modulo 在我的机器上花费了 189.99 秒 - Cast 花费了 54.75 秒。

回答by jtahlborn

if(new BigDecimal(d).scale() <= 0) {
    //do stuff
}

回答by murgatroid99

Your method of using if((int)d == d)should always work for any 32-bit integer. To make it work up to 64 bits, you can use if((long)d == d, which is effectively the same except that it accounts for larger magnitude numbers. If dis greater than the maximum longvalue (or less than the minimum), then it is guaranteed to be an exact integer. A function that tests whether dis an integer can then be constructed as follows:

您的使用方法if((int)d == d)应始终适用于任何 32 位整数。要使其工作到 64 位,您可以使用if((long)d == d,它实际上是相同的,只是它考虑了更大的数量级数。如果d大于最大值long(或小于最小值),则保证它是一个精确整数。d然后可以构造一个测试是否为整数的函数,如下所示:

boolean isInteger(double d){
    if(d > Long.MAX_VALUE || d < Long.MIN_VALUE){
        return true;
    } else if((long)d == d){
        return true;
    } else {
        return false;
    }
}

If a floating point number is an integer, then it is an exact representation of that integer.

如果浮点数是整数,则它是该整数的精确表示。

回答by Thorbj?rn Ravn Andersen

Doubles are a binary fraction with a binary exponent. You cannot be certain that an integer can be exactly represented as a double, especially not if it has been calculated from other values.

双精度数是带有二进制指数的二进制分数。您不能确定一个整数是否可以准确地表示为双精度数,尤其是如果它是从其他值计算出来的。

Hence the normal way to approach this is to say that it needs to be "sufficiently close" to an integer value, where sufficiently close typically mean "within X %" (where X is rather small).

因此,解决这个问题的正常方法是说它需要“足够接近”一个整数值,其中足够接近通常意味着“在 X % 以内”(其中 X 相当小)。

I.e. if X is 1 then 1.98 and 2.02 would both be considered to be close enough to be 2. If X is 0.01 then it needs to be between 1.9998 and 2.0002 to be close enough.

即,如果 X 是 1,那么 1.98 和 2.02 都被认为足够接近为 2。如果 X 是 0.01,那么它需要在 1.9998 和 2.0002 之间才能足够接近。