在Nullable Floats上添加时的好奇行为

时间:2014-08-28 14:51:31

标签: c#

我在使用可添加的可浮动浮点数时发现了一些非常奇怪的东西。请使用以下代码:

float? a = 2.1f;
float? b = 3.8f;
float? c = 0.2f;
float? result = 
(a == null ? 0 : a)
+ (b == null ? 0 : b)
+ (c == null ? 0 : c);
float? result2 = 
(a == null ? 0 : a.Value)
+ (b == null ? 0 : b.Value)
+ (c == null ? 0 : c.Value);

result6.099999,而result26.1。我很幸运能够偶然发现这一点,因为如果我更改abc的值,行为通常会显示正确。其他算术运算符或其他可空值类型也可能发生这种情况,但这是我能够重现的情况。我不明白为什么floatfloat?的隐式强制转换在第一种情况下无效。我或许可以理解,如果条件的另一边是int,它是否试图获得0值,但这似乎不是正在发生的事情。鉴于result仅对某些浮动值组合显示不正确,我假设这是多次转换的某种舍入问题(可能是由于装箱/拆箱或其他原因)。

有什么想法吗?

1 个答案:

答案 0 :(得分:4)

请参阅@EricLippert的评论。

  允许

任何更改结果 - 让我强调一下   允许再次包括月相在内的任何   更改是否以32位精度或更高精度计算浮点数   准确性。始终允许处理器出于任何原因   决定突然开始以80位或者80位进行浮点运算   128位或任何它选择的东西,只要它大于或等于   32位精度。看到   (.1f+.2f==.3f) != (.1f+.2f).Equals(.3f) Why?   了解更多详情。

     

在这种情况下询问特别是导致处理器决定   在一种情况下使用更高的精度而在另一种情   游戏。它可能是任何东西。如果您需要 中的准确计算   十进制数字然后使用恰当命名的decimal类型。如果您需要   在浮点数中可重复的计算然后C#有两种机制   强制处理器回到32位。 (1)显式转换为(float)   不必要地,或(2)将结果存储在float数组元素中   引用类型的浮点字段。

此处的行为与Nullable类型无关。这是一个浮动的问题,从来都不是精确的,并且在处理器的突发奇想中以不同的精度计算。

一般来说,这可以归结为如果准确性很重要,最好的办法是使用float之外的其他东西(或使用@EricLippert描述的技术强制处理器使用32位精度)。

answer from Eric Lippert on linked question也有助于了解正在发生的事情。