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

时间:2012-09-27 19:55:44

标签: c# floating-point equality

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

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

现在,由于float的范围远大于整数(但精度不足以在边缘处唯一地呈现整数),如果对此问题的回答< em>还解决了上述x的哪些值可以保证,如果可以保证的话。


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


这将失败,“不等于:16777217”(cast float - &gt; int):

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

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

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

5 个答案:

答案 0 :(得分:13)

是的,无论int是什么价值,比较都将是真实的。

int将转换为float进行转化,第一次转换为float将始终提供与第二次转化相同的结果。

考虑:

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

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

如果您将float转换回int进行比较,那就是另一回事了。


另请注意,即使转换为int的特定float值始终会产生相同的float值,但这并不意味着float值具有对于int值是唯一的。有int个值(float)x == (float)(x+1)true

答案 1 :(得分: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 - &gt;浮动和浮动 - &gt; int转换是一种双射。

注意:实验代码实际上没有测试边缘情况int.MaxValue,因为Parallel.For的参数是独占的,但我分别测试了该值并且它也通过了测试。

答案 2 :(得分: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;
}

然后双方的精确度损失可能不相等。结果可能是错误的。

答案 3 :(得分: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);
}

答案 4 :(得分:0)

我对浮点运算的理解是它们由CPU处理,它们只能决定你的精度。因此,没有确定的值,浮动失去精度。

我曾经认为x86架构保证了最低限度,但我被证明是错误的。