私の知る限り、Delphi Win32 の通貨型はプロセッサの浮動小数点精度に依存します。このため、2 つの Currency 値を比較するときに丸めの問題が発生し、マシンによって異なる結果が返されます。
今のところ、Epsilon パラメーター = 0.009 を渡す SameValue 関数を使用しています。これは、10 進数 2 桁の精度しか必要としないためです。
この問題を回避するためのより良い方法はありますか?
私の知る限り、Delphi Win32 の通貨型はプロセッサの浮動小数点精度に依存します。このため、2 つの Currency 値を比較するときに丸めの問題が発生し、マシンによって異なる結果が返されます。
今のところ、Epsilon パラメーター = 0.009 を渡す SameValue 関数を使用しています。これは、10 進数 2 桁の精度しか必要としないためです。
この問題を回避するためのより良い方法はありますか?
Delphi の Currency 型は、1/10,000 でスケーリングされた 64 ビット整数です。つまり、最小増分は 0.0001 に相当します。浮動小数点コードと同じように、精度の問題の影響を受けません。
ただし、通貨の数値を浮動小数点型で乗算する場合、または通貨の値を除算する場合は、丸めを何らかの方法で処理する必要があります。FPU はこのメカニズムを制御します (「コントロール ワード」と呼ばれます)。Math ユニットには、このメカニズムを制御するいくつかのプロシージャが含まれています。特に SetRoundMode です。このプログラムで効果を確認できます。
{$APPTYPE CONSOLE}
uses Math;
var
x: Currency;
y: Currency;
begin
SetRoundMode(rmTruncate);
x := 1;
x := x / 6;
SetRoundMode(rmNearest);
y := 1;
y := y / 6;
Writeln(x = y); // false
Writeln(x - y); // 0.0001; i.e. 0.1666 vs 0.1667
end.
使用しているサードパーティ ライブラリがコントロール ワードを別の値に設定している可能性があります。重要な計算の開始点で明示的にコントロール ワード (丸めモード) を設定したい場合があります。
また、計算が単純な浮動小数点に変換されてから通貨に戻された場合、すべての賭けがオフになり、監査が困難になります。すべての計算が通貨であることを確認してください。
いいえ、通貨は浮動小数点型ではありません。これは固定精度の10進数であり、整数ストレージで実装されます。正確に比較することができ、たとえばDoubleのような丸めの問題はありません。したがって、Currency変数に不正確な値が表示されている場合、問題はCurrencyタイプ自体ではなく、何を入力しているかにあります。ほとんどの場合、コード内のどこかに浮動小数点計算があります。あなたはそのコードを示さないので、この質問についてこれ以上助けになるのは難しいです。ただし、一般的に、解決策は、Currency変数で不正確な比較を行うのではなく、Currency変数に格納する前に浮動小数点数を正しい精度に丸めることです。
あなたの状況が私のようなものであれば、このアプローチが役立つかもしれません。主に給与計算の仕事をしています。ビジネスに 3 つの部門があり、従業員のコストをこれら 3 つの部門間で均等に請求したい場合、丸めの問題が発生することがよくあります。
私が行っていることは、部門ごとに総費用の 3 分の 1 を請求し、請求された費用を小計 (通貨) 変数に追加するループです。しかし、ループ変数が制限に等しい場合は、端数を掛けるのではなく、総コストから小計変数を差し引き、それを最後の部門に入れます。このプロセスから得られる仕訳は常にバランスを取る必要があるため、常にうまくいっていると思います。
スレッドを参照してください:
D7 / DUnit: すべての CheckEquals(Currency, Currency) テストが突然失敗します ...
https://forums.codegear.com/thread.jspa?threadID=16288
開発ワークステーションの変更により、通貨の比較が失敗したようです。根本的な原因は見つかりませんでしたが、Windows 2000 SP4 を実行している 2 台のコンピューターで、gds32.dll (InterBase 7.5.1 または 2007) および Delphi (7 および 2009) のバージョンに関係なく、この行
TIBDataBase.Create(nil);
の値を 8087 コントロール ワードに変更し、現在 $1372 から $1272 に変更します。
そして、単体テストでのすべての通貨比較は、次のようなおかしなメッセージで失敗します
Expected: <12.34> - Found: <12.34>
gds32.dll は変更されていないため、このライブラリには、コントロール ワードを変更するサード パーティの dll への依存関係があると推測されます。
Delphi での通貨の丸めに関する問題を回避するには、小数点以下 4 桁を使用します。
これにより、非常に少量の計算を行うときに丸めの問題が発生することがなくなります。
"Been there. Done That. Written the unit tests."