2016-09-30 21 views
4
rate : Currency; 
mod1 : Currency; 
mod2 : Currency; 
mod_rate : Currency; 

rate := 29.90; 
mod1 := 0.95; 
mod2 := 1.39; 

mod_rate := rate * mod1 * mod2; 

この計算を電卓で実行すると、値は39.45295になります。 DelphiのCurrencyデータ型は4小数点までしか正確でないため、内部的に値を丸めます。私のテストではBankerの丸めを使用してmod_rateに39.4530という値が含まれるようになっていますが、この特定のケースでは39.4529に切り捨てられます。Delphiは乗算時に通貨をどのように丸めますか

私はこれらの計算を40,000持っており、上記以外はすべて正しいです。ここで切り上げ例です:

rate := 32.25; 
mod1 := 0.90; 
mod2 := 1.15; 

これは電卓に33.37875に等しく、バンカーの丸めによるとデルファイが何をするかである、33.3788に行くだろう。

デルファイがここで何をしているのか、誰かが明かにすることができますか?

+0

私の推測では、39.4595は浮動小数点では正確に表現できません。丸めには問題はありませんが、表現力はありません。通貨ではなく小数点の演算を使用します。 –

+0

通貨は固定小数点データ型です。 2つの通貨を掛け合わせてもフロートが発生しない限り。 – Chet

+0

@Chet: '通貨'の値は内部的には小数点以下を削除するために10000を掛けた64ビットの整数として格納されますが、 '通貨 'の値で実行される算術はそれらの整数の浮動小数点演算命令を使用します。 –

答えて

8

Currency通貨自体が64ビットの整数値であっても、拡張精度でfpuで計算されます。

問題は、丸め誤差ではなく浮動小数点バイナリ表現で問題があります。​​

39.45295 = + 39.45294 99999 99999 99845 67899 95771 03240 88111 51981 35375 97656 25

拡張精度値は、したがって、39.45295以下である: 現在地39.45295の浮動小数点表現を見ることができます下に丸めます。

これらの種類のエラーを回避するために、代わりに10進数学ライブラリを使用します。

mod_rate := rate * mod1 * mod2; 
0041D566 DF2D20584200  fild qword ptr [$00425820] 
0041D56C DF2D28584200  fild qword ptr [$00425828] 
0041D572 DEC9    fmulp st(1) 
0041D574 DF2D30584200  fild qword ptr [$00425830] 
0041D57A DEC9    fmulp st(1) 
0041D57C D835C4D54100  fdiv dword ptr [$0041d5c4] 
0041D582 DF3D38584200  fistp qword ptr [$00425838] 
0041D588 9B    wait 

fmulpfdivを拡張精度で行われる:


は浮動小数点演算がcurrency計算のために、FPUで実行されることを確認するために、ここで分解されます。 整数演算を使用した場合、命令はfimulfidivになります。

+0

私はこの回答を受け入れる準備ができています。あなたは、Delphiが通貨を浮動小数点として処理することを示すいくつかの文書を引用できますか? – Chet

+0

ええ、私は、それを投稿していただきありがとうございます、検証するためにアセンブリを分析するつもりだった。 – Chet

+0

801/2(両方の通貨)が400.5になります。この(http://pages.cs.wisc.edu/~rkennedy/exact-float?number=400.5)によれば、浮動小数点で正確に表現できます。それでも、それは401に丸められます。私はそれがまだFPの問題であると確信していますが、それは迷惑です。 – Chet

関連する問題