红宝石从23 + 9.23 = 32.230000000000004

问题描述:

看似不稳定的结果我收到了非常有趣的,看起来不稳定的Ruby结果。到底是怎么回事?红宝石从23 + 9.23 = 32.230000000000004

这是正确的!

>> 23+9.22 
=> 32.22 

这不是!

>> 23+9.23 
=> 32.230000000000004 

所有尾随零都来自哪里?到底是怎么回事?

+0

这就是你得到处理浮游物。在例如相同的情况下蟒蛇。 – 2012-07-31 21:31:39

+3

在大多数语言中都是一样的。查看http://stackoverflow.com/questions/2100490/floating-point-inaccuracy-examples – 2012-07-31 21:35:00

+0

我认为这是一段时间以来,这个常年最喜欢的想法.. – 2012-07-31 22:28:16

puts "%.30f" % 9.23 
#=> 9.230000000000000426325641456060 
由于基地-2(数字计算机内部表示)和基10(你是用什么来处理,并输入到文本编辑器或IRB)之间的差异

,你不能代表9.23 恰好为作为浮点值。这不是特定于Ruby,而是几乎所有的编程语言。

例如,9.23在内部表示为两个大国的总和,是这样的:

01001.00111010111... 
||||| ||||||||||+-> 1 * 1/2048 \    
||||| |||||||||+--> 1 * 1/1024 \   
||||| ||||||||+---> 1 * 1/512 \   
||||| |||||||+----> 0 * 1/256  \  
||||| ||||||+-----> 1 * 1/128  \  
||||| |||||+------> 0 * 1/64   fraction = 0.22998046875 
||||| ||||+-------> 1 * 1/32  / 
||||| |||+--------> 1 * 1/16 /  
||||| ||+---------> 1 * 1/8 /  
||||| |+----------> 0 * 1/4 /  
||||| +-----------> 0 * 1/2 /  
||||| 
||||+-------------> 1 * 1  \ 
|||+--------------> 0 * 2  \ 
||+---------------> 0 * 4   integer = 9 
|+----------------> 1 * 8  /
+-----------------> 0 * 16 /

欲了解更多信息,请阅读What Every Computer Scientist Should Know About Floating Point ArithmeticIEEE 754 description on Wikipedia

你的解决方法,当精度是非常重要的(如货币)是:

  1. 跟踪最小可用单位对你的计算(例如便士),只转换为十进制显示。例如:

    result = 2300 + 923   # $23.00 + $9.23 
    puts "%.2f" % (result/100.0) # Ensure output rounded to two decimal places 
    #=> 32.23 
    
  2. 使用图书馆像BigDecimal跟踪的准确精度为你,并设置数据库来使用固定精度的数据类型一样DECIMAL or NUMERIC

  3. 接受数值通常会“足够接近”,并且在向用户显示时总是使用格式化选项。

    result = 23 + 9.27 #=> 32.269999999999996 
    puts "%g" % result #=> 32.27 
    puts "%.3f" % result #=> 32.270 
    puts "%.1f" % result #=> 32.3 
    
+1

每当有人使用WECSSKAFPA链接时,都应该颁发帽子。我亲自指出过100次。我总是可以使用moar hatz。 – 2016-10-07 13:08:37

这不是Ruby的问题。这是一个在计算机中表示浮点数的已知问题。

如果您正在进行金融或货币处理,那么您希望远离浮点数来表示您的金额。