【问题标题】:Java Doubles are not good at math [closed]Java Doubles 不擅长数学 [关闭]
【发布时间】:2011-07-20 01:37:53
【问题描述】:

我目前正在用 java 编写一个计算器程序。这是我的第一个java程序,我习惯了c++。

我注意到 java 中的双精度与 c++ 中的双精度完全不同。 在 java 和 c++ 中试试这个
4.1*3
那/.1

应该是
12.3 然后 123,c++ 给出了这个结果,但是 java 给出了
12.299999999999999 和 122.99999999999999

我怎样才能像在 c++ 中使用双打一样进行数学运算,我知道在程序中使用 12.299999999999999 与 12.3 相比没有任何区别,但是当用户阅读数字时,这非常难看。我已经研究过 BigDecimal 类,但我不能用那个类做三角函数和对数等等

【问题讨论】:

  • 真的,你很可能在 C++ 中遇到同样的问题。这不是 java 的问题,而是 IEEE 双打的工作方式。如果它恰好在 C++ 中为您工作,那么您很幸运。阅读en.wikipedia.org/wiki/Floating_point 的“IEEE 754:现代计算机中的浮点”部分。也许您缺少的只是输出格式,但这并不能解决您将遇到的问题,除非您首先了解获得 12.29999999999 而不是 12.3 的原因。
  • 我知道在 C++ 中你可以设置双输出的精度。我确信你可以在 Java 中做一些事情。
  • 每位计算机科学家都应该知道的浮点运算知识cr.yp.to/2005-590/goldberg.pdf

标签: java c++ math calculator double-precision


【解决方案1】:

数学是一样的;显示是不同的,因为大多数 C/C++ 显示格式会舍入数字以避免最低有效位的不精确。

【讨论】:

    【解决方案2】:

    老兄, Java Doubles 不擅长数学,它们速度慢,但与 Java 的 double(小型)(或任何其他 64 位 IEEE 754)一样精确。 BigDecimal 甚至更慢。

    (不知道老兄是否坚持)

    【讨论】:

    • +1 只是因为我认为 -1 不合理。
    • 实际上 Java 数学并不严格遵循 64 位 IEEE 754,这就是我们有 StrictMath 包的原因。
    • Fredrik, -- 没问题,但我也看不出有什么理由。
    • @Voo,如果你需要strictfp,你可以随时使用,java.lang.Math通常也会重定向StrictMath。
    【解决方案3】:

    你看过java.lang.StrictMath吗?从 javadocs 我得到的印象是它可能更接近 C,但我没有做太多的数学运算,也不能确定。

    否则我同意 geekosaur:输出可能是唯一的问题,java.text.NumberFormat 可能会有所帮助。

    【讨论】:

    • StrictMath 强制 IEEE 754 甚至在没有严格实现它的处理器(电话等)上。
    • StrictMath 不一定更精确,它总是相同的定义结果。 (在这里也没什么区别。)
    【解决方案4】:

    每个算术模型都代表着精度、空间和速度之间的权衡。

    浮点,不管是什么语言都会牺牲一些精度来节省空间和提高速度。

    定点是一种不同的权衡,任意精度算术是另一种权衡。

    如果您想要任意精度的复杂计算,您需要一个专用的数学库,例如 Apache commons-mathapfloat

    【讨论】:

      【解决方案5】:

      那么,为什么这是不精确的?4.1 已经不能精确地表示为二进制数(无论是定点数还是浮点数),所以它被四舍五入到下一个 @987654322 @ 价值。将其乘以 3 不会改变不可表示性的事实,但会放大错误,因此它现在是一个不同于从十进制 12.3 转换得到的二进制值。因此,当您再次将其转换为十进制时,您会得到带有很多 9 的数字。

      当它乘以 10 时,您只需将误差再次放大 10。(再次除以 0.1 会引入更多误差,因为 0.1 也不能完全表示。)

      您的 C++ 程序可能使用了完全相同的操作。 Java 中显示不同的原因是它显示了从字符串中重现数字所需的所有数字,而您的 C++ 输出函数以某种方式对其进行了舍入。 (由于您没有显示输出代码,我们无法确定您在那里做了什么。)

      当输出数字供人类用户消化时,使用NumberFormat(在java.text中)或Formatter(在java.util中)。

      【讨论】:

        【解决方案6】:

        我注意到 java 中的双精度与 c++ 中的双精度完全不同。

        事实上,Java 将使用与 C++ 完全相同的双精度表示,并且算法将(很可能)在内部产生完全相同的值。

        这里的根本问题是二进制浮点数表示和十进制表示之间没有精确的一对一映射。像12.3 这样的数字不能精确地表示为二进制浮点数。这是数学上的不可能。

        要了解这一点(并且您应该),请阅读"What Every Computer Scientist Should Know About Floating-Point Arithmetic"

        您观察到的差异是由于将双精度值转换为数字以进行输出的格式代码的差异。在 Java 案例中,代码给出了它可以实现的实际双精度的最准确的十进制表示。在 C++ 的情况下,它会将最低有效数字四舍五入......这给出了您期望的数字,但不是最准确的十进制表示。

        这两种方法都是错误的。他们只是不同。如果您希望 Java 显示四舍五入到特定位数的数字,您可以使用 Java 格式化程序类之一来实现。

        另一种方法是使用 BigDecimal 类在 Java 中完成所有计算器算术运算。这将为您提供精确的数字,以您在高中学习的十进制算术的限制为模;例如你不能用十进制精确表示像 1/3 这样的分数。缺点是BigDecimal 算法比浮点数慢很多数量级,而且 API 使用起来更麻烦。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-04
          • 1970-01-01
          • 2013-10-19
          • 2012-08-18
          • 2011-03-26
          • 1970-01-01
          相关资源
          最近更新 更多