小数の比較をするには?

解決


かんとく  2010-08-06 03:11:41  No: 38931

お世話になっております。

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;


Delphi大好き  2010-08-06 04:02:48  No: 38932

直接小数点を比較すると、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;


tor  2010-08-06 04:03:34  No: 38933

計算機の中では数値を2進数で表しますが、2.1などの値は2進数で正確に表現できないため誤差が出ます。
「浮動小数点 丸め誤差」などで検索すれば詳しい解説が見つかると思います。

小数の比較では「=」を使わず、常に大小で比較するか誤差を見込むのが鉄則。
例えば小数点以下10桁程度の誤差を許すとしたら
CompareValue(r, 2.1, 1e-10) = 0 としてみてはどうでしょう。


tor  2010-08-06 04:09:37  No: 38934

補足すると、最初のコード例の場合
r はRealと宣言しているのでDouble相当(有効桁数15前後)の精度があります。
一方、比較式の右辺の 2.1 は定数式なのでExtended型となり、有効桁数は19桁前後です。
精度が異なるため、同じ2.1という値でも内部表現が異なり、違う値となります。


スパムちゃんXR  2010-08-06 06:09:25  No: 38935

少数は、有効桁数によっていくつか、型があるので、その性じゃない?

Delphiって、小数部を返す変数がありましたよね?
だったら、小数部を取得して、その桁数だけ10倍する。
それを、Roundなりして、整数にして・・・、いや、Integerにキャストするだけでもokかな?

そうやって、整数型として、比較する関数を作っちゃえばいいんじゃない?
そうすれば、有効桁数の誤差もなくなると思いますよ。


どら  2010-08-06 17:34:16  No: 38936

RealではなくCurrencyにしては?


はる  2010-08-06 17:37:30  No: 38937

浮動小数点型(double/float)では、一致検出は困難と思います。
どうしても小数点での一致をしたいのであれば、Currency型は
どうですか。
Currency型は小数点以下4桁しかとれませんが、
c1,c2:currency; としておいて、c1:=2.1 c2:=2.1 としても
一致します。


かんとく  2010-08-06 19:36:27  No: 38938

たくさんのご回答、ありがとうございます。

r:real;

r:Currency;

にしただけで、結果がtrueになりました。
小数点以下4桁あれば、十分なので、この方法でいきます。

ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加