C# C语言中实数舍入的不一致性#
我有这个测试代码:C# C语言中实数舍入的不一致性#,c#,.net,C#,.net,我有这个测试代码: class Test { static void Main() { decimal m = 1M / 6M; double d = 1.0 / 6.0; decimal notQuiteWholeM = m + m + m + m + m + m; // 1.0000000000000000000000000002M double notQuiteWholeD = d + d + d + d +
class Test
{
static void Main()
{
decimal m = 1M / 6M;
double d = 1.0 / 6.0;
decimal notQuiteWholeM = m + m + m + m + m + m; // 1.0000000000000000000000000002M
double notQuiteWholeD = d + d + d + d + d + d; // 0.99999999999999989
Console.WriteLine(notQuiteWholeM); // Prints: 1.0000000000000000000000000002
Console.WriteLine(notQuiteWholeD); // Prints: 1.
Console.WriteLine(notQuiteWholeM == 1M); // False
Console.WriteLine(notQuiteWholeD < 1.0); // Prints: True. Why?
Console.ReadKey();
}
}
A这个,为什么打印的是真的
是否有自动取整流程?如何打印正确的/计算的值
[注意:我在C#5.0中简单地找到了这个示例代码第30页:实数舍入错误]
提前感谢。我们知道,1/6=0.1666(重复),十进制
和双精度
不能表示重复的数字,它们是在分配给时计算出来的。由于它们是由不同的支持数据结构构建的,因此它们表示不同的可能数字集,在某些情况下,取整方式也不同
对于此代码:
Console.WriteLine(notQuiteWholeD < 1.0); // Prints: True. Why?
Console.WriteLine(notQuiteWholeD<1.0);//是的。为什么?
由于notQuiteWholeD
为0.999999999999 89
它打印为true
我不打算讨论双精度
和十进制
在幕后是如何工作的,但如果您感兴趣,这里有一些阅读材料
十进制
以10为基数存储Double
以基数2存储。这两个基都不能用有限表示法精确表示1/6
这解释了除了控制台.WriteLine(notQuiteWholeD)之外的所有输出。即使存储的实际值小于1,输出也会得到“1”。由于输出以10为基数,因此必须从2为基数进行转换。部分转换包括四舍五入。阅读问题的方式与阅读其他两个答案的方式不同。其要点是:C#中的
double
“round”的格式化字符串表示形式是否正确
对
内部double
以完整的IEEE-754十进制数字精度(15-17位)表示,这就是为什么:
notQuiteWholeD < 1.0 == true // because notQuiteWholeD = 0.99999999999999989
要获取完整内部表示的所有数字,可以使用:
Console.WriteLine("{0:G17}", notQuiteWholeD);
或:
在这种情况下,两者都将输出“099999999989”
前者将始终使用17位精度。后者(“往返精度”)将使用15位,如果该精度足以满足以下要求,则将使用17位:
Double.Parse(String.Format("{0:G15}", notQuiteWholeD)) == notQuiteWholeD
奖金示例:
... 当G17
和R
不同时:
Console.WriteLine("{0:G17}", 1.0000000000000699); // outputs "1.0000000000000699"
Console.WriteLine("{0:R}", 1.0000000000000699); // outputs "1.00000000000007"
1.0000000000000699(17位有效数字)可以足够精确地表示,仅使用15位有效数字即可进行往返。换句话说,1.00…07
的double
表示与1.00…0699
相同
因此,1.00…07
(15位)是一个较短的输入,以获得完全相同的内部(17位)表示。这意味着R
将其四舍五入为15位,而G17
将保留内部表示的所有数字
当意识到这一点时,也许会更清楚:
Console.WriteLine("{0:G17}", 1.00000000000007); // outputs "1.0000000000000699"
Console.WriteLine("{0:R}", 1.00000000000007); // outputs "1.00000000000007"
。。。给出完全相同的结果。请记住,即使是“大小数”也是任意精度,而不是无限精度。在某些情况下,使用任何有限表示法都会导致舍入,最多您可以控制这种情况发生的时间,而不是浮点/双精度-或.NET小数。
Double.Parse(String.Format("{0:G15}", notQuiteWholeD)) == notQuiteWholeD
Console.WriteLine("{0:G17}", 1.0000000000000699); // outputs "1.0000000000000699"
Console.WriteLine("{0:R}", 1.0000000000000699); // outputs "1.00000000000007"
Console.WriteLine("{0:G17}", 1.00000000000007); // outputs "1.0000000000000699"
Console.WriteLine("{0:R}", 1.00000000000007); // outputs "1.00000000000007"