2011-08-15 18 views
4

下面的Perl代碼浮點數轉換爲錯誤整數的Perl轉換成int錯誤的,但只有特定數量

use strict; 

my $zahl =297607.22000; 
$zahl=$zahl * 100; 
print "$zahl\n"; 
my $text=sprintf ("%017d",$zahl); 
print $text; 

的這個輸出是:

29760722 
00000000029760721 

的事情是,你可以改變給定的號碼爲其他號碼,它的工作原理。

任何想法這裏有什麼問題或Perl只是做錯了嗎?

感謝您的幫助!

回答

8

這與常見問題(Why am I getting long decimals)有關。 $zahl未被正確舍入,它被舍入到下一個較小的整數。

+0

爲什麼在這兩個例子中四捨五入? – Mat

+0

@Mat:因爲int向零舍入,最接近297607.22000的浮點數表示恰好是297607.21999999997 – ysth

+0

@ysth:我知道這是一個舍入問題。我不明白的是爲什麼不同的規則適用於第一個'print'語句和'sprintf'中的四捨五入。 – Mat

2

當您將浮點乘法乘以100時,結果將類似29760721.9999999963。然後,當您將%d轉換爲整數時,這會被截斷爲29760721

嘗試sprintf('%.10f', $zahl),你應該可以看到這個。

+2

它根本不是圓形的。它只是被截斷了。 –

+0

@brian謝謝 - 我已經在回答中更正了這一點。 – mikej

1

您必須非常小心浮點數並將它們視爲固定點。由於可能發生在內建中的各種轉換,可能有時整數轉換與另一轉換不完全相同。看來,這種情況多次與x.22號:

use strict; 

my $n = 0; 
for (0 .. 10_000_000) { 
    my $float = 100 * "$_.22"; 

    my $str = "$float"; 
    my $int = int $float; 

    if ($str ne $int) { 
     $n++; 
     #say "$float, $str, $int"; 
    } 
} 

say "n = $n"; 

這在我的系統上打印

n = 76269 

仔細看一下Perl源代碼將需要查看確切的轉換差異。

我會建議如果你打算使用定點數字,將它們全部轉換爲整數(使用一個通用的轉換函數,最好將源數字看作字符串),然後在它們之下使用它們將禁用浮點數的use integer;編譯指示。

+4

看看perl源代碼並不會告訴你爲什麼X.22 * 100的最接近的浮點表示小於它;它只是。 – ysth

+1

事實上,它甚至與Perl沒有關係。它是浮點數的一個屬性,所有使用它的語言都會顯示相同的行爲。 – ikegami

2

22/100是二進制的週期數,就像1/3是十進制的週期數。這將需要無限存儲來完全將其存儲在浮點數中。

$ perl -e'$_="297607.22000"; $_*=100; printf "%.20f\n", $_' 
29760721.99999999627470970154 

intsprintf %d截斷小數,所以你最終29760721. printsprintf %f輪,這樣你就可以得到想要的結果。

$ perl -e'$_="297607.22000"; $_*=100; printf "%017.0f\n", $_' 
00000000029760722 
+0

你有'int'既截斷又舍入。它只是截斷。 – cjm

+0

@cjm,Typo。 'print'需要更好的PR代理! (雙關打算)修復之前,我什至發現你的消息:) – ikegami