18

x == y問題が発生する可能性があることは「誰もが知っています」が、xyは浮動小数点値ですが、この質問はもう少し具体的です。

int x = random.Next(SOME_UPPER_LIMIT);
float r = x;
// Is the following ALWAYS true?    
r == x

ここで、 float の範囲は整数の範囲よりもはるかに大きいため (ただし、エッジで整数を一意に提示するには精度が不十分です)、この質問への回答で、上記のどの値が保証されるかについてx言及されているとよいでしょう。 、それが保証できる場合。


現在、私のコードこの仮定を行っています(xの値が比較的小さい場合)-噛まれないようにしたいと思います:)


これは「等しくない: 16777217」で失敗します (float をキャスト -> int):

for (int i = 0; i < int.MaxValue; i++) {
   float f = i;
   if ((int)f != i) throw new Exception("not equal " + i);
}

この類似のコードは失敗しません (int -> float のみ)。ただし、変換の損失により、同じ整数に「等しい」可能性があるいくつかの float があり、サイレント バグを表している可能性があります。

for (int i = 0; i < int.MaxValue; i++) {
   float f = i;
   if (f != i) throw new Exception("not equal " + i);
}
4

5 に答える 5

13

はい、値が何であれ、比較は常に真になりますint

int変換floatを行うために に変換され、最初の への変換floatは常に 2 番目の変換と同じ結果になります。

検討:

int x = [any integer value];
float y = x;
float z = x;

yとの値zは常に同じです。変換で精度が失われる場合、両方の変換で正確に同じ方法で精度が失われます。

floatback to intto を比較に変換する場合、それは別の問題です。


intまた、変換された特定の値がfloat常に同じ値になる場合でも、その値がその値に対して一意でなければfloatならないという意味ではありません。になる値があります。floatintint(float)x == (float)(x+1)true

于 2012-09-27T20:07:24.983 に答える
5

次の実験は、答えは、等式が真でないエッジ ケースがないことであることがわかります。

    static void Main(string[] args)
    {
        Parallel.For(int.MinValue, int.MaxValue, (x) =>
        {
            float r = x;
            // Is the following ALWAYS true?    
            bool equal = r == x;
            if (!equal) Console.WriteLine("Unequal: " + x);                
        });

        Console.WriteLine("Done");
        Console.ReadKey();

        return;
}

変換が合理的であるように思われる

float f = i;

if ((int)f != i)

同じルールに従う必要があります。これは、int -> float および float -> int 変換が全単射であることを証明しています。

注: Parallel.For のtoパラメータは排他的であるため、実験コードは実際にはエッジ ケースの int.MaxValue をテストしませんが、その値を個別にテストし、テストにも合格しました。

于 2012-09-27T20:04:47.573 に答える
5

int と float を比較する場合、int は暗黙的に float にキャストされます。これにより、同じ精度の損失が発生することが保証されるため、比較は常に真になります。暗黙のキャストを妨害したり、算術を行ったりしない限り、等式は保持されます。たとえば、次のように記述した場合:

bool AlwaysTrue(int i) {
    return i == (float)i;
}

暗黙的なキャストがあるため、常に true を返す次の関数と同等です。

bool AlwaysTrue(int i) {
    return (float)i == (float)i;
}

しかし、これを書くと:

bool SometimesTrue(int i) {
    return i == (int)(float)i;
}

その場合、暗黙的なキャストはなくなり、精度の低下は右側でのみ発生します。結果は偽である可能性があります。同様に、これを書くと:

bool SometimesTrue(int i) {
    return 1 + i == 1 + (float)i;
}

その場合、精度の損失は両側で同等ではない可能性があります。結果は偽である可能性があります。

于 2012-09-27T20:07:35.140 に答える
3

例外がスローされることなく、このコードを実行しました。

for (int x = Int16.MinValue; x < Int16.MaxValue; x++)
{
 float r = x;
 if (r != x)
 {
  throw new Exception("Failed at: " + x);
 }
}

まだ待機中です (時間がかかりすぎたため、このテストを完了しませんでした。実行中に例外がスローされることはありませんでした):

for (long x = Int64.MinValue; x < Int64.MaxValue; x++)
{
 float r = x;
 if (r != x)
 {
  throw new Exception("Failed at: " + x);
 }
}

戻って、注意して例を実行しました。これが出力でした:

[Exception: not equal 16777217 ?= 1.677722E+07 ?= 16777216]

for (int i = 0; i < int.MaxValue; i++)
{
 float f = i;
 if ((int)f != i) throw new Exception("not equal " + i + " ?= " + f + " ?= " + (int)f);
}
于 2012-09-27T20:05:07.213 に答える
0

浮動小数点算術計算についての私の理解では、それらは CPU によって処理され、精度を決定するのは CPU だけです。したがって、浮動小数点数が精度を失う明確な値はありません。

たとえば、x86 アーキテクチャでは最小値が保証されていると思っていましたが、間違っていることが証明されています。

于 2012-09-27T20:05:10.957 に答える