2010-02-25 94 views
4

兩個,Borland公司帕斯卡爾7和Delphi 2007年已經拿到了程序STR這需要一個號碼,長度和精度,並把它轉換成一個像這樣的字符串:如何在Delphi/Borland的帕斯卡爾STR程序輪

str(9.234:5:1, s); // -> s = ' 9.2' 

如果舍入是非模糊的,那麼一切都很好,但如果不是(0.5 - >向上或向下?)就有問題:它似乎取決於BP中的浮點數據類型,但在Delphi中顯然是一致的2007年:

BP:

var 
    e: extended; 
    d: double; 
begin 
    d := 2.15; 
    e := 2.15; 
    str(d:5:1, s); { -> s = ' 2.1' } 
    str(e:5:1, s); { -> s = ' 2.2' } 
    { but: } 
    d := 2.25 
    e := 2.25 
    str(d:5:1, s); { -> s = ' 2.3' } 
    str(e:5:1, s); { -> s = ' 2.3' } 

我無法找到任何規則如何雙打四捨五入,而顯然擴展總是四捨五入。

德爾福2007年顯然總是獨立於數據類型四捨五入。

是否有人知道在BP中舍入是如何完成雙值的?

我想知道,因爲我正在移植一些使用雙打到Delphi 2007的Borland Pascal代碼,當我比較輸出時,我得到了STR過程中四捨五入造成的不一致。這些對結果無關緊要,但卻很難找出重要的差異。

+0

爲什麼試圖弄清楚它是如何工作的,當它可以改變所有的Str()調用到FloatToStr調用時出現問題? – 2010-02-25 19:03:20

+0

他無法更改BP代碼。只有將Delphi代碼更改爲FloatToStr纔會向他購買任何東西。 – 2010-02-26 09:53:33

+0

請注意,在傳遞給Str()之前,double可能會轉換爲擴展。這意味着擴展後的2.15和2.15之後的擴展可以有不同的值,因此可能會有所不同。否則,接受的答案是正確的:2.25可以精確地表示(.25是2^-2),通過擴展和雙精度來表示,而2.15不能。 – 2016-06-06 15:41:57

回答

4

d = 2.15和d = 2的情況。25是不同的:

2.15不能在浮點格式精確表示,因此它不可能說該值是如何,而不需要分析在給定的浮點格式的浮點值的二進制表示圓形;

2.25在浮點格式精確表示,和舍入結果必須是可預測的;

我已經測試其上爲浮點格式精確表示,發現STR總是向上舍入爲正值和向下爲負值一些值四捨五入。 STR不遵循「銀行家舍入」,例如:

d := 2.25; 
// d:= roundto(d, -1); banker's rounding is 2.2 
    str(d:5:1, s); { -> s = ' 2.3' } 

    d:= 2.75; 
// d:= roundto(d, -1); banker's rounding is 2.8 
    str(d:5:1, s); { -> s = ' 2.8' } 
+0

好觀察!將這與我的答案結合起來,你對發生了什麼有了一個很好的想法。 – 2010-02-25 18:21:44

2

我認爲你所看到的問題是,許多可完全用十進制表示法表示的數字只能表示爲二進制重複小數(二進制?)。所以,可能是2.15不能用雙精度表示,而2.14999999999234(或其他)與二進制表示最接近。

由於該數字的最接近的二進制表示嚴格小於2.15,因此Str函數向下舍入而不是向上。

+0

我認爲你是對的。但是,如何才能找出給定雙重價值的情況?我會試驗一下... – dummzeuch 2010-02-25 15:50:47

+0

+1我認爲你是對的。使用源盧克。 – 2010-02-25 15:54:31

+0

@dummzeuch - 如果你想要確切的數字,你不應該使用雙打,而是縮放整數。請看http://rvelthuis.de/articles/articles-floats.html,以獲取有關該主題的非常好的解釋。 – 2010-02-25 15:56:55

0

我調查了這一點,發現加0.000001會產生雙打的正確結果。

+0

我無法更改BP源代碼,我只是將其作爲參考。我已經得到的測試數據已經使用編譯好的BP程序進行處理。我想知道它是如何工作的,所以我可以(暫時)在Delphi中重現此行爲。 – dummzeuch 2010-02-25 15:48:35

1

看起來像一個浮點舍入錯誤。當您查看在Delphi中生成的彙編代碼時,可以看到爲這兩個操作調用了_Str2Ext,這兩個操作將Extended轉換爲字符串。因此,爲了做到這一點它有你的雙轉換成擴展幕後:

Project1.dpr.16: str(d:5:1, s); { -> s = ' 2.1' } 
0040E666 DD45E8   fld qword ptr [ebp-$18] 
0040E669 83C4F4   add esp,-$0c 
0040E66C DB3C24   fstp tbyte ptr [esp] 
0040E66F 9B    wait 

而且在某個地方,從雙到擴展的轉換,你失去的精確一點點,並與結束了與如果您宣佈相同數字(因爲我們閱讀它們)作爲擴展名開頭,數字略有不同。這在浮點轉換中很常見。不知道你有什麼可以做的。

0

請注意,這裏有兩個方面。

首先,您的十進制文字值可能四捨五入爲二進制浮點數。這意味着彙編代碼中輸入的數字可能與您記下的數字略有不同。如果最近的機器號稍微小一點,它可以看起來好像應該向上舍入的值被STR舍入。

其次,使用在FPU狀態字中配置的四捨五入來舍入得到的二進制浮點數,該舍入有希望未被外部庫改變。