Delphiと.NETでは実数の条件比較の内部処理に違いがあるのでしょうか?

とあるシステムの移植で計算した結果をもとに一定の値ごとに分類してグラフを描画する処理があるのですが同じように条件を書いたのに一部の値がDelphiと.NETで結果が異なってしまいます。
例えば
float n = 3.55;
if(n < 3.6){…}
のときに内部処理の仕様の違いによってDelphiだとnが3.6と見なされてfalseになって、.NETだと普通に「3.55<3.6」と比較されてtrueになるということがあるのでしょうか?
過去に似たような事例等がありましたらご教授をお願いします。

回答の条件
  • 1人1回まで
  • 13歳以上
  • 登録:2016/02/21 22:42:48
  • 終了:2016/02/28 22:45:04

回答(1件)

id:a-kuma3 No.1

a-kuma3回答回数4325ベストアンサー獲得回数17732016/02/22 01:23:30

ポイント100pt

質問では、

float n = 3.55;
if(n < 3.6){…}

とありますが、n は 3.55 ではなく計算で求められた値だと思います。
(多分)C# で、質問にある通り float なのでしょう。
Delphi の方は、実数の型は REAL でしょうか。

C# の float は IEEE 754 でいうところの Single Format です。
2進数での指数形式で、仮数部の桁数は 2進数で 23bit です。

Delphi の REAL は IEEE 754 でいうところの Double Format です。
こちらも 2進数での指数形式で、仮数部の桁数は 2進数で 52bit あります。

比較している Delphi と C# のプログラムでは、精度が違う実数型で計算しているために桁落ちが発生していて、比較している値(こちらは、定数か?)と近いところでは誤差が生じているのだと思います。
C# の方を、計算過程も含めて全て double で計算すれば同じ結果になると思います。
質問の文面にあるような、3.55 と 3.6 の比較であれば、float でも double でも同じ判定結果になります。


以下、C のプログラムですが float と double で、0.01 を 100回足したときの比較です。

#include <stdio.h>

void test_float() {
    float d = 0.01f;
    float n = 0.0f;
    for (int i = 0 ; i < 100 ; ++i) {
        n += d;
    }
    if (n < 1.0) {
        printf("float: n (%f) < 1.0\n", n);
    } else {
        printf("float: n (%f) >= 1.0\n", n);
    }
}

void test_double() {
    double d = 0.01;
    double n = 0.0;
    for (int i = 0 ; i < 100 ; ++i) {
        n += d;
    }
    if (n < 1.0) {
        printf("double: n (%f) < 1.0\n", n);
    } else {
        printf("double: n (%f) >= 1.0\n", n);
    }
}

int main(void) {
    test_float();
    test_double();
    return 0;
}

試してみると分かりますが、同じ結果にはなりません。
http://ideone.com/HG6j4I



以下、参考 URL。
C#
https://msdn.microsoft.com/en-us/library/b1e65aza.aspx
https://msdn.microsoft.com/en-us/library/678hzkk9.aspx

IEEE 754
https://docs.oracle.com/cd/E19422-01/819-3693/ncg_math.html#pgfId-344
https://docs.oracle.com/cd/E19422-01/819-3693/ncg_math.html#pgfId-610

Delphi
http://docwiki.embarcadero.com/RADStudio/XE8/ja/%E5%8D%98%E7%B4%94%E5%9E%8B#.E5.AE.9F.E6.95.B0.E5.9E.8B

  • id:cx20
    実数の内部形式については、殆どのプログラミング言語で IEEE 754 の規格が用いられており精度も決まっているので、Delphiだからといって、3.55→3.6として取り扱われることは考えにくいです。

    推測ですが、旧システムは小数第2位で四捨五入していたが、新システムに移植した際、四捨五入の処理が抜けしまった為、計算結果が変わってしまった、とかではないでしょうか?

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません