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

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

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

现在,因为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); } 

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

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

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

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

考虑:

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

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

如果你将float转换回int到比较,那是另一回事。


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

比较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; } 

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

以下实验表明,答案是你没有那种不等式的边缘情况

  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) 

应遵循相同的规则。 这certificate了int – > float和float – > int转换是一个双射。

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

我运行此代码时没有抛出exception:

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

还在等待(没有完成这个测试,因为它花了太长时间,但在运行时从未抛出exception):

 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); } 

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

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