我在倍增时面对相当奇怪的行为。
制作一个简单的控制台应用程序并尝试以下代码。
private static void Main(string[] args)
{
var b1 = 3.1 * 100D;
var a1 = 4.1 * 100D;
// put breakpoint here and observe b1 and a1 values, to me they are
// b1=310, a1=409.99999999999994
Console.WriteLine(a1);
// notice that Console.WriteLine actually returns 410
}
我怀疑这是二进制中的双重表示,但我无法解释自己是怎么可能的,您能帮我吗?
另外,如果您将a1
铸造为decimal
,它将以某种方式变为410 ...
我尝试针对C#3.0和C#7.0编译,都给出了相同的结果。我正在Visual Studio 2017中复制此内容。
编辑
(要回答"为什么310 == 3.1 * 100"部分)
这只是"偶然的" 3.1 * 100 == 310
。
碰巧的是,浮点算术的特定方式工作,3.1 * 100的结果给出了310.0000...
。如果将310转换为双重,则此数字与您获得的结果完全匹配。
在这种特殊情况下,比较将愉快地工作。
您可以使用doubleconverter.toexactstring()函数来查看jon skeet
Console.WriteLine(DoubleConverter.ToExactString(3.1 * 100));
Console.WriteLine(DoubleConverter.ToExactString(4.1 * 100));
// output :
// 310
// 409.99999999999994315658113919198513031005859375
(上一个)
在这种特殊情况下,表达式4.1 * 100D
是double
乘以double
。
4.1 * 100
(double
倍int
-> int
被隐式施放为double
)
由于未为您的变量指定任何类型,因此编译器选择将结果解释为double
。在这种特殊情况下,由于浮点算术造成的四舍五入误差(4.1没有确切的表示为double
)
如果将变量定义为decimal
,则结果是decimal
,并且不会发生舍入误差。请注意,您不能仅将var
更改为您提供的代码中的decimal
,也必须更改变量:
在这种情况下,乘法将在两种情况下都给出确切的值。
更多地在浮点数错误上:浮点数学是否损坏?
decimal a1 = 4.1 * 100D; // compilation error : no implicit cast from double to decimal
decimal a1 = 4.1M * 100; // valid, and the multiplication will be performed exactly.