お世話になっております。
XP,Delphi2007です。
小数の比較をしようとしましたが、思うとおりになりません。
下に例を書きましたが、R:realに2.1を代入し、r=2.1かどうか比較すると、falseという結果が返ってきます。
なぜでしょうか?
rの値を適当にいろんな小数に変更しても、falseです。
rの値を整数にすると、trueになります。
(123.0のときはtrue、123.1のときはfalse)
小数の比較をして、同じ値のときにtrueになるためには、どうしたらよいのでしょうか。
よろしくお願いします。
-------------------------------------------------------
※Button1を置く。
procedure TForm1.Button1Click(Sender: TObject);
var
r:real;
begin
r:=2.1;
if r=2.1 then
begin
button1.caption:='true';
end
else
begin
button1.caption:='false';
end
end;
直接小数点を比較すると、Falseになるみたいです。
比較対象も同じ変数を作って比較したところ、
Trueになりました。
環境はvista、Delphi3です。
procedure TForm1.Button1Click(Sender: TObject);
var
r:real;
l:real;
begin
r := 2.1;
l := 2.1;
if r = l then
caption := '同じ'
else
caption := '異なる';
end;
計算機の中では数値を2進数で表しますが、2.1などの値は2進数で正確に表現できないため誤差が出ます。
「浮動小数点 丸め誤差」などで検索すれば詳しい解説が見つかると思います。
小数の比較では「=」を使わず、常に大小で比較するか誤差を見込むのが鉄則。
例えば小数点以下10桁程度の誤差を許すとしたら
CompareValue(r, 2.1, 1e-10) = 0 としてみてはどうでしょう。
補足すると、最初のコード例の場合
r はRealと宣言しているのでDouble相当(有効桁数15前後)の精度があります。
一方、比較式の右辺の 2.1 は定数式なのでExtended型となり、有効桁数は19桁前後です。
精度が異なるため、同じ2.1という値でも内部表現が異なり、違う値となります。
少数は、有効桁数によっていくつか、型があるので、その性じゃない?
Delphiって、小数部を返す変数がありましたよね?
だったら、小数部を取得して、その桁数だけ10倍する。
それを、Roundなりして、整数にして・・・、いや、Integerにキャストするだけでもokかな?
そうやって、整数型として、比較する関数を作っちゃえばいいんじゃない?
そうすれば、有効桁数の誤差もなくなると思いますよ。
RealではなくCurrencyにしては?
浮動小数点型(double/float)では、一致検出は困難と思います。
どうしても小数点での一致をしたいのであれば、Currency型は
どうですか。
Currency型は小数点以下4桁しかとれませんが、
c1,c2:currency; としておいて、c1:=2.1 c2:=2.1 としても
一致します。
たくさんのご回答、ありがとうございます。
r:real;
→
r:Currency;
にしただけで、結果がtrueになりました。
小数点以下4桁あれば、十分なので、この方法でいきます。
ありがとうございました。
ツイート | ![]() |