C#中的"(float)integer == integer"是否保证相等?

18 c# floating-point equality

虽然"我们都知道" x == y可能有问题,但在哪里xy是浮点值,这个问题更具体一些:

int x = random.Next(SOME_UPPER_LIMIT);
float r = x;
// Is the following ALWAYS true?    
r == x
Run Code Online (Sandbox Code Playgroud)

现在,因为float 的范围远大于整数的范围(但是精度不足以在边缘处唯一地呈现整数),如果对这个问题的回答解决x了上述哪些值可以保证的话会很好. ,如果它可以得到保证.


目前我的代码正在做出这个假设(对于相对较小的x值) - 我想确保我不会被咬掉:)


这将失败,"不等于:16777217"(cast float - > int):

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

这个类似的代码不会失败(只有int - > float); 但是,由于转换中的丢失,有几个浮点数可以"等于"相同的整数,并且可能代表一个无声的错误:

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

Guf*_*ffa 13

是的,无论价值多少,比较都将是真实的int.

int将被转换为一个float来进行转换,并且所述第一转换float将总是产生相同的结果作为第二个转换.

考虑:

int x = [any integer value];
float y = x;
float z = x;
Run Code Online (Sandbox Code Playgroud)

yz将始终相同.如果转换失去精度,则两次转换都将以完全相同的方式失去精度.

如果你将float返回转换为int比较,那就是另一回事了.


另请注意,即使int转换为特定值的值float始终产生相同的float值,也不意味着该float值必须对该值唯一int.有int值,其中(float)x == (float)(x+1)true.


Eri*_* J. 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;
}
Run Code Online (Sandbox Code Playgroud)

转换似乎是合理的

float f = i;
Run Code Online (Sandbox Code Playgroud)

if ((int)f != i)
Run Code Online (Sandbox Code Playgroud)

应遵循相同的规则.这证明int - > float和float - > int转换是一个双射.

注:实验代码实际上并不测试边缘情况int.MaxValue因为的Parallel.For的,以参数是排他的,但我单独测试的价值,同时也通过了测试.


Cra*_*ney 5

比较int和float时,int被隐式地转换为float.这确保了相同的精度损失,因此比较将始终为真.只要你不打扰隐式演员或算术,就应该保持平等.例如,如果你这样写:

bool AlwaysTrue(int i) {
    return i == (float)i;
}
Run Code Online (Sandbox Code Playgroud)

有一个隐式转换,所以它等效于这个函数应该总是返回true:

bool AlwaysTrue(int i) {
    return (float)i == (float)i;
}
Run Code Online (Sandbox Code Playgroud)

但如果你这样写:

bool SometimesTrue(int i) {
    return i == (int)(float)i;
}
Run Code Online (Sandbox Code Playgroud)

然后没有更多的隐式演员表,精确度的损失只发生在右侧.结果可能是错误的.同样,如果你这样写:

bool SometimesTrue(int i) {
    return 1 + i == 1 + (float)i;
}
Run Code Online (Sandbox Code Playgroud)

那么精确度的损失可能在双方都不相同.结果可能是错误的.