Java双打不擅长数学

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

我注意到java中的双打完全不像c ++中的双打。 在java和c ++中尝试这个
4.1 * 3
那/ 0.1

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

我怎么能像在c ++中使用双打一样进行数学运算,我知道你在程序中使用12.299999999999999的任何东西都不会与12.3相比没有区别,但是当用户正在阅读数字时,这非常难看。 我已经查看了BigDecimal类,但是我不能对该类执行trig和logarithms等等

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

那么,为什么这不精确呢?4.1已经无法精确表示为二进制数(无论是固定点还是浮点数),因此它会四舍五入到下一个double值。 将此乘以3并不会改变不可表示性的事实,但会放大错误,因此它现在是一个不同的二进制值,而不是从十进制12.3转换得到的。 因此,当再次将其转换为十进制时,您会获得具有大量九的数字。

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

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

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

我注意到java中的双打完全不像c ++中的双打。

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

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

要理解这一点(和你应该),请阅读“每个计算机科学家应该知道的关于浮点运算的内容” 。

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

这两种方法都不对。 他们只是不同。 如果希望Java将数字显示为四舍五入到一定数量的数字,则可以使用其中一个Java格式化程序类来完成此操作。

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

Dude, Java Doubles不擅长数学 ,它们很慢,但与Java的双(小的)(或任何其他64位IEEE 754)一样精确。 BigDecimal甚至更慢。

(如果Dude住在那么dunno)

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

浮点,无论语言牺牲了一些精度,以节省空间和增加速度。

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

如果你想要复杂的任意精度计算,你需要一个专用的数学库,如Apache commons-math或apfloat 。

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

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