Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C语言中实数舍入的不一致性#_C#_.net - Fatal编程技术网

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"