IT Notes‎ > ‎Java‎ > ‎Java Language‎ > ‎

Java 浮点数的取整问题

执行附件中的 Java 程序:
public class What021 {
    public static void main(String[] args) {
        double[] array = new double[] { 0.0, 4.0, 4.1, 4.5, 4.7 };
        for (double d : array) {
            printNumber(d);
            d = -d;
            printNumber(d);
        }
    }

    private static void printNumber(double d) {
        System.out.println("(int)" + d + ": " + (int) d);
        System.out.println("(long)" + d + ": " + (long) d);
        System.out.println("Math.round(" + d + "): " + Math.round(d));
        System.out.println("Math.ceil(" + d + "): " + Math.ceil(d));
        System.out.println("Math.floor(" + d + "): " + Math.floor(d));
    }

}

得到的结果符合下表:
 返回值类型 计算式  -4.7  -4.5  -4.1  -4.0 -0.0 +0.0 4.0 4.1  4.5  4.7
 int (int)x -4  -4
-4   -4 4
 long (long)x
-4  -4
-4   -4 4
 long Math.round(x)
-5   -4
-4   -4 4 5
 double Math.ceil(x)-4.0 -4.0 -4.0  -4.0-0.0 0.0  4.05.0 5.0 5.0 
 double Math.floor(x)-5.0 -5.0 -5.0  -4.0-0.0 0.0  4.04.0 4.0 4.0 
注:表中的 x 的类型是 double,计算 Math.round(x) 实际上是调用的 public static long java.lang.Math.round(double) 方法。

可见对 double 类型的数字求近似值,应使用 Math.round(double) 方法,不能直接使用强制转型(cast to int or long)。
对于 cast(cast 成 int 或者 long),它的操作方式可以认为是先取绝对值,再舍去小数部分,最后添上符号。
对于 Math.ceil(x)函数,就是大于或者等于这个数的所有整数组成的集合中的最小值。
对于 Math.floor(x)函数,就是小于或者等于这个数的所有整数组成的集合中的最大值。
直观地说,把两个相邻整数之间的空隙看成一个格子,不妨设这两个相邻整数为 m, m+1,则小点的 m 是所谓的地板(floor),大点的 m+1 则是所谓的天花板(ceil)。对于任意实数,它总是落在某个这样的格子中(m < x < m+1),或者落在某个板上(x==m or x==m+1)。我们定义如下法则:
ceil(x) = m+1, floor(x) = m, if m < x < m+1
ceil(x) = floor(x) = x, if m = x

对于 Math.round(x),查 JDK 源码有:
public static long round(double a) {
    return (long)floor(a + 0.5d);
}
可见,它是先给要作四舍五入操作的数字加上0.5,再 cast 成 long 类型。不过有一点要注意的是 round(4.5) = 5, 而 round(-4.5) = -4,因为4.5+0.5=5, (-4.5)+0.5=4.0。

参考链接:

其他:
TODO 为了补全文档,待合适的某个时间考虑单精度的float型。
ċ
What021.java
(1k)
Iridium Cao,
Jul 13, 2008, 4:13 PM
Comments