2012-03-28 104 views
4

寂寂因爲浮點數的內部表現的不準確(見Wikipedia,搜索到:「用平等的測試」 ...),還有在做的時候仍然是一個驚喜:當`expr`嵌套在Tcl中時,爲什麼算術結果會有所不同?

% expr int(0.57 * 10000) 
5699 
% expr int([expr 0.57 * 10000]) 
5700 

是嵌套expr禁止?爲什麼它會改變通過的浮點值?還是它會改變浮點算法的執行順序,影響結果的順序?

更新:關於comparing floating point numbers with speed(和輔助鏈接),some basics and not so basics herethe IEEE 754-2008 standard's description的主題很好的閱讀。

回答

7

這是一個有趣的問題,因爲它觸及了一些微妙的事情。

% expr int(0.57 * 10000) 
5699 

此代碼(有沒有換人,所以它的工作原理「意料之中」)顯示,浮點數,本身就是令人驚奇的事情。特別是,0.57沒有精確的表示形式作爲IEEE雙精度浮點數(基數爲2);實際上,它的表示比精確到0.57稍低,所以當向下舍入時(這是int(...)所做的; 10000本身就是確切的),您可以下降到5699.您也會看到與其他語言相同的行爲。

% expr int([expr 0.57 * 10000]) 
5700 

現在這特別有趣。你首先看到內部計算正在完成,並且生成的float被轉換爲一個字符串(因爲實際上沒有其他方法可以做到這一點)。現在,您必須使用Tcl 8.4(或之前),默認數字渲染規則是(實際上)通過打印數字的前15個有效數字而得到的;在這種情況下,讓你5700.00000000000(當然,在右邊零的一些截斷),這就是再從頭作爲第一重新演繹雙(準確5700.0),然後是會轉換爲5700

的數量規則轉換在Tcl 8.5中改變。現在,當Tcl將浮點數轉換爲字符串時,它會產生最短的字符串,該字符串將轉換回完全相同的浮點數(即通過字符串域的旁路將在所得到的雙精度中給出相同的位模式)。這意味着你現在從來沒有看到上述兩件事之間的區別。 (如果你真的想要強制固定的小數位數,請使用format %.15g [expr 0.57 * 10000]。)

如果你正確地使用表達式,就像社區建議人們做的那樣,你也不會觀察到8.0到8.4的行爲十多年來:

$ tclsh8.4 
% expr {int([expr 0.57 * 10000])} 
5699 

這是因爲這並不強制內部expr調用的結果被解釋爲一個字符串。 (它也更快,更安全。)

+0

感謝您確認懷疑並添加了大量的知識。而且,是的,如果我有一個tcl8.4標籤,Sherlock ;-) – cfi 2012-03-28 10:57:08

相關問題