2013-02-10 36 views
1

我有一個用Ruby編寫的簡單程序。代碼是:在OS X上使用Ruby的奇數輸出行爲

#!/usr/bin/ruby 

# odd behavior here 
j = 1.11 
while j < 2 
    print "iteration #{j}\n" 
    j += 0.01 
end 

我正在運行它與山獅的MacBook Air。我的紅寶石的版本是:

ruby 1.9.3p327 (2012-11-10 revision 37606) [x86_64-darwin11.4.2] 

奇怪的行爲,我看到的是:

iteration 1.1 
iteration 1.11 
iteration 1.12 
iteration 1.1300000000000001 
iteration 1.1400000000000001 

現在,如果我改變J即可1.13,我得到以下resutls(我消除了一些輸出爲了簡潔起見):

iteration 1.13 
iteration 1.14 
iteration 1.15 
... 
iteration 1.36 
iteration 1.37 
iteration 1.3800000000000001 
iteration 1.3900000000000001 
iteration 1.4000000000000001 
iteration 1.4100000000000001 
iteration 1.4200000000000002 

這是怎麼回事?最初,我想也許它與j中的值存儲有關,而1.13有一些特殊的屬性。然而,從1.13開始,這個理論就開始轉變了。真正讓我感到這似乎並不一致。換句話說,似乎有點武斷(儘管我敢肯定這不是)奇怪的「0000000000」發揮作用。更糟的是,如果我將「j < 2」更改爲「j < 5」,我會遇到更奇怪的行爲。

... 
iteration 4.85999999999994 
iteration 4.86999999999994 
iteration 4.8799999999999395 
iteration 4.889999999999939 
iteration 4.899999999999939 
iteration 4.909999999999939 
iteration 4.919999999999939 
iteration 4.929999999999938 
iteration 4.939999999999938 
iteration 4.949999999999938 
iteration 4.959999999999938 
iteration 4.969999999999938 
iteration 4.979999999999937 
iteration 4.989999999999937 
iteration 4.999999999999937 

我試過用谷歌搜索這個,但說實話,我不知道從哪裏開始。我發現了一些線程,人們在to_d看到奇怪的行爲,但沒有具體回答我的問題。另外,我對Ruby的瞭解還不充分,無法完全理解發生了什麼。這是一個精確的問題,以及Ruby如何存儲數字,但我不確定在哪裏尋找。

任何在正確的方向微調都非常感謝!謝謝!

+0

相關:[浮點精度在紅寶石](http://stackoverflow.com/questions/12541907/float-precision-in-ruby) – sawa 2013-02-10 15:21:29

+1

它顯示'0.01'並不精確地存儲在Ruby中'0.01'。這是由於您標記的舍入錯誤。誤差小於'0.0000000000000001',因此它在前幾次加法中不會顯示出來,但經過幾次加法後,誤差累積,並且與1.11的舍入誤差一起達到了'0.0000000000000001'開始出現。 – sawa 2013-02-10 15:25:18

+0

@sawa謝謝!非常豐富的文章和偉大的鏈接。應該找到我自己... – galois 2013-02-10 15:33:50

回答

0

你看到下跌limits.h中定義的小量內的數字:2.2204460492503131e-16

換句話說,計算是OK,那就是認爲它是一個更精確的數量比它的顯示。這是我最好的猜測。

我查看了ruby源代碼中的sprintf.c。它似乎將花車轉換爲BigDecimal:

switch (TYPE(val)) { 
     case T_FLOAT: 
     if (FIXABLE(RFLOAT_VALUE(val))) { 
     val = LONG2FIX((long)RFLOAT_VALUE(val)); 
     goto bin_retry; 
     } 
     // THIS IS THE CONVERSION 
     val = rb_dbl2big(RFLOAT_VALUE(val)); 
     if (FIXNUM_P(val)) goto bin_retry; 
     bignum = 1; 
     break; 

這可能是奇怪顯示的原因。然而,紅寶石雙是一個C雙AFAIK,所以計算應該與它們在c中相同,除了它們看起來很奇怪。

試試這個c程序,你會明白我的意思。你應該匹配與你的紅寶石結果這無關.000 ... 1S:

#include <stdio.h> 
int main(){ 
double j; 

j = 1.1; 

while (j < 2) { 
    printf ("iteration %1.16f\n", j); 
    j += 0.01; 
    } 
} 

順便說一句,紅寶石1.8.7不出現此行爲。只是一個側面說明。

相關問題