10个问题的力量

时间:2015-07-29 13:40:44

标签: java

我遇到了愚蠢的问题,从未见过它。

我正在尝试为一些需要增加10倍的数学计算做一个非常简单的任务。

首先,我写了一个非常简单的增长循环,但是我不理解,获得的值越高,得到的结果越不精确。

我想知道为什么会这样?以及如何解决它?

我的测试代码:

public class PowerOfTen {

    private int lineCounter = 1;

    public static void main(String[] args) {
        PowerOfTen powerOfTen = new PowerOfTen();

        powerOfTen.growingOfTenMethodOne();
        powerOfTen.growingOfTenMethodTwo();
    }

    public void growingOfTenMethodOne() {

        double MAX_VALUE = 1e50;
        lineCounter = 1;

        for (double i = 1; i < MAX_VALUE; i = i * 10) {
            System.out.printf("%03d%1s%f\n", lineCounter, " | ", i);
            lineCounter++;
        }
    }

    public void growingOfTenMethodTwo() {

        double MAX_VALUE = 50;
        lineCounter = 1;

        for (double i = 0; i < MAX_VALUE; i++) {
            System.out.printf("%03d%1s%f\n", lineCounter, " | ", Math.pow(10, i));
            lineCounter++;
        }
    }

}

两种方法都有效,并且假设返回正确的结果,但是在这两种方法中都会给出一些不准确的结果,如下面的示例所示。

方法1: 第24,26,27,28,31,32,33行未返回正确的结果

022 | 1000000000000000000000.000000
023 | 10000000000000000000000.000000
024 | 99999999999999990000000.000000
025 | 1000000000000000000000000.000000
026 | 9999999999999999000000000.000000
027 | 99999999999999990000000000.000000
028 | 999999999999999900000000000.000000
029 | 10000000000000000000000000000.000000
030 | 100000000000000000000000000000.000000
031 | 999999999999999900000000000000.000000
032 | 9999999999999999000000000000000.000000
033 | 99999999999999990000000000000000.000000

方法2: 第24,30行没有返回正确的结果

022 | 1000000000000000000000.000000
023 | 10000000000000000000000.000000
024 | 99999999999999990000000.000000
025 | 1000000000000000000000000.000000
026 | 10000000000000000000000000.000000
027 | 100000000000000000000000000.000000
028 | 1000000000000000000000000000.000000
029 | 10000000000000000000000000000.000000
030 | 100000000000000010000000000000.000000
031 | 1000000000000000000000000000000.000000
032 | 10000000000000000000000000000000.000000
033 | 100000000000000000000000000000000.000000

4 个答案:

答案 0 :(得分:6)

这不是一个&#34;愚蠢的问题&#34 ;;它是计算机科学的核心问题之一......处理数字的正确表示是一项非平凡的任务。

例如,您可能希望开始阅读here

任何编程&#34;编程&#34;应该明白这实际意味着什么;以及它如何影响您的应用程序/解决方案。

答案 1 :(得分:4)

这是因为从双精度浮点格式转换为十进制格式。就像有十进制的周期性数字一样,有些数字是二进制的周期性的,但不是十进制的。

这些案例是二进制的。

答案 2 :(得分:3)

Java浮点double 始终是IEEE754 64位浮点类型。

方法1。

浮点数双可以精确表示整数,最高可达到第42次幂。因此,一旦超过9,007,199,254,740,992,就会出现不准确的情况。 (这是一个常见的误解,浮点总是会引入不准确性:在您的特定情况下,计算对于循环的前几次迭代将是精确的。)

方法2。

如果两个参数是浮点,则

Math.pow(x, y)实现为exp(y log x)。这将引入数值精度问题,因为浮点双精度仅精确到约15个有效数字。

答案 3 :(得分:0)

这一切都归结为Java规范。

在Java中,整数使用32位来表示其值。 FLOAT 使用24位尾数,因此大于2 ^ 23的整数将截断其最低有效位。例如33554435(或0x200003)将被截断为大约33554432 +/- 4. DOUBLE 使用53位尾数,因此将能够表示32位整数而不会丢失数据。

检查this article,以非常简单的方式解释所有内容。