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

得到的结果符合下表:

注:表中的 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。

参考链接:

java.lang.Math in JDK API docs: http://java.sun.com/javase/6/docs/api/java/lang/Math.html

其他:

TODO 为了补全文档,待合适的某个时间考虑单精度的float型。