【问题标题】:Apparent imprecision when incrementing and displaying double values [duplicate]递增和显示双精度值时明显不精确[重复]
【发布时间】:2012-05-24 07:01:26
【问题描述】:

可能重复:
Retain precision with Doubles in java
Moving decimal places over in a double

课程不言自明。如果你执行这段代码,double 值似乎有些溢出,但并非所有值都发生这种情况,此外,如果你直接打印数字,输出就可以了。

public class test {
    public static void main(String[] args){

        for (double f=1.36; f<1.40; f+=0.01) System.out.println(f); 
             //Prints 1.36
             //       1.37
             //       1.3800000000000001   ???????
             //       1.3900000000000001   ???????

            System.out.println(1.36); //Prints 1.36
            System.out.println(1.37); //Prints 1.37
            System.out.println(1.38); //Prints 1.38
            System.out.println(1.39); //Prints 1.39
    }
}

有人能解释一下吗?如果这是一个错误,那么在代码中修复它的最佳方法是什么?有什么神奇的解决方法吗?

【问题讨论】:

  • 即使是 JEval 也不能正确处理像“1400*0.001”这样的操作(这就是我跟踪错误的方式),因此我不认为投票否定是个愚蠢的问题跨度>
  • @user1352530 从输出完全符合指定的意义上说,它得到了妥善处理(至于否决票,这可能是因为这个问题可能每天被问一次,所以稍微搜索一下你可能会有发现了一些东西,比如我在上面发布的链接,它位于 Java FAQ)。
  • 糟糕.. 抱歉,如果是这样。我真的在寻找,但似乎还不够。如果您不知道是错误还是您做得不好并且如果是数字问题,则很难查询该主题,因为我看到 jEval 也失败并且不知道是否有人有耐心去尝试任何像我一样失败的数字,尽管这并不常见(真的 7 年来从未见过)。
  • 不是我,但是如果您在这里搜索双精度或浮点数,您会发现很多人提出的问题,他们还发现浮点数不能代表其范围内的每个数字。跨度>

标签: java double


【解决方案1】:

如果您像这样格式化打印输出,您将看不到所有这些小数位:

System.out.printf("%.2f",yourVariable);

【讨论】:

  • 谢谢,但我的 var 来自像 2.333333333333 这样的字符串,我不知道 maxDecimals,所以我无法限制/舍入它们并格式化
  • 不用担心这适用于所有十进制长度。
  • 我的意思是,如果我没记错的话,你的解决方案会四舍五入到小数点后 2 位,如果我在 var 中的值为 1.300000000001 = 1.30,这是完美的,但如果 var 保持 1.34565667777,则不是这样,因为那时我松开所有精度
【解决方案2】:

试试

for (int i= 136; i <= 140; i++) 
    System.out.println(i / 100.0);

打印

1.36
1.37
1.38
1.39
1.4

当您打印出双精度时,它会补偿表示错误,因此您看不到它。当您对浮点值执行多个算术运算时,您可能会增加舍入误差,这会变得很明显(需要纠正很多)

【讨论】:

  • 我打算通过 aix (answerer) 链接学习基础,但老实说,我无法理解最流行的编程语言如何无法安全透明地处理任何计算器都可以执行的基本操作..对于 JEval 来说,就更不用说了,它就像其中之一。谢谢你!
  • 它使用en.wikipedia.org/wiki/IEEE_754-2008 浮动算法,每个主要的编程语言和 CPU 都支持。计算器通常会隐藏更多数字并做其他事情来减少明显的舍入误差。 Java 只使用您的 CPU 支持的 float 和 double 类型。显着更改功能会增加开销并使其与其他语言不一致。
  • 哇,我简直不敢相信。今天我了解到,2012 年的计算机没有解决基本 14*0.1 (1.4000000000000001) 并将其存储在 var 中的最佳方法 :)
  • @user1352530 -- 这是错误的思考方式。相反,请考虑一个事实,即在十进制数字中,您不能用有限的数字表示 1/3——即答案是 0.33333...(永远重复)。在二进制算术中,1/10 是一个重复的小数——你需要无限多的位来存储确切的值——这就是生活中的事实。我们在计算中通过格式化输出以供人类消费来处理这个问题。
  • 但是我的 5 欧元(也是二进制)计算器至少是 Java 无法替代的吗?打印 14*0.1 应该是微不足道的。我不想格式化,因为如果我四舍五入,我需要限制允许的最大小数。然后,如果我放低三分,我会丢失大部分数字以获得更大的数字,但如果我放高,像 0.1 之类的东西就足以搞砸了,
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多