我目前正在用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以及
答案 0 :(得分:8)
数学是一样的;显示不同,因为大多数C / C ++显示格式都是数字,以避免最低有效位的不精确。
答案 1 :(得分:7)
那么,为什么这不精确呢?:4.1
已经不能精确表示为二进制数(无论是固定点还是浮点数),所以它舍入到下一个double
值。12.3
将此乘以3不会改变不可表示的事实,但会放大错误,因此它现在是一个不同的二进制值,而不是从十进制0.1
转换得到的。因此,当你再次将它转换为十进制时,你得到的是带有很多9的数字。
当它与10相乘时,您只需将误差再次放大10.(再次除以0.1会引入更多错误,因为NumberFormat
也不能完全表示。)
您的C ++程序可能使用了完全相同的操作。在Java中显示不同的原因是它显示了从字符串中重现数字所需的所有数字,而您的C ++输出函数以某种方式对其进行舍入。 (由于您没有显示输出代码,我们无法确定您在那里做了什么。)
输出人类用户要摘要的数字时,请使用Formatter
(在java.text中)或{{1}}(在java.util中)。
答案 2 :(得分:4)
我注意到java中的双打完全不像c ++中的双打。
事实上,Java将使用与C ++完全相同的双精度表示,并且算术(很可能)在内部生成完全相同的值。
这里的基本问题是二进制浮点数表示和十进制表示之间没有精确的1对1映射。诸如12.3
之类的数字不能精确地表示为二进制浮点数。这是一种数学上的不可能性。
要理解这一点(你应该),请阅读"What Every Computer Scientist Should Know About Floating-Point Arithmetic"。
您正在观察的差异将是由于格式代码的差异导致将double值转换为输出的数字。在Java情况下,代码提供了它可以实现的实际双精度的最准确的十进制表示。在C ++的情况下,它将最低有效数字四舍五入...这给出了您期望的数字,但不是最准确的十进制数字。
两种方法都不对。他们只是不同。如果希望Java将数字显示为舍入到一定数量的数字,则可以使用其中一个Java格式化程序类来执行此操作。
另一种方法是使用BigDecimal
类在Java中完成所有计算器算术运算。这将为您提供精确的数字,模拟您在高中学到的十进制算术的局限性;例如你不能用十进制精确表示1/3的分数。缺点是BigDecimal
算术比浮点慢许多个数量级,并且API使用起来比较麻烦。
答案 3 :(得分:1)
The Dude, Java双打并不擅长数学,它们很慢,但与Java的双(小的)(或任何其他64位IEEE 754)一样精确。 BigDecimal甚至更慢。
(如果Dude遵守,那就不知道了)
答案 4 :(得分:1)
每个算术模型都代表精度,空间和速度之间的权衡。
浮点,无论语言牺牲了一些精度,节省空间和增加速度。
固定点是一种不同的权衡,任意精度算术是另一种。
如果您想要复杂的任意精度计算,您需要一个专用的数学库,如Apache commons-math或apfloat。
答案 5 :(得分:0)
你看过java.lang.StrictMath
了吗?从javadocs我得到的印象是,它可能更接近C,但我没有做太多的数学,也无法确定。
否则我同意geekosaur:输出可能是唯一的问题,java.text.NumberFormat
可能会有所帮助。