6

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

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

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

我当然不是浮点数及其行为方面的专家,但我的印象是,因为double存储的只是数字的近似值,所以if()条件只会在某些时候输入(甚至在大多数情况下) )。但我正在寻找一种保证 100% 工作的方法,无论double值如何存储在系统中。

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

4

5 回答 5

10

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

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

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

于 2012-08-22T16:48:30.627 回答
2

怎么样

 if(d % 1 == 0)

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

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

我通过在 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

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);
    }
}

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

于 2012-08-22T16:47:47.733 回答
2
if(new BigDecimal(d).scale() <= 0) {
    //do stuff
}
于 2012-08-22T16:56:21.643 回答
1

您的使用方法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;
    }
}

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

于 2012-08-22T16:49:57.567 回答
-2

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

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

即,如果 X 为 1,则 1.98 和 2.02 都将被视为足够接近 2。如果 X 为 0.01,则它需要介于 1.9998 和 2.0002 之间才能足够接近。

于 2012-08-22T17:55:45.760 回答