一尘不染

格式化双打以在C#中输出

c#

运行与.NET中的双重乘法是否中断相关的快速实验并阅读了几篇有关C#字符串格式的文章,我认为是这样的:

{
    double i = 10 * 0.69;
    Console.WriteLine(i);
    Console.WriteLine(String.Format("  {0:F20}", i));
    Console.WriteLine(String.Format("+ {0:F20}", 6.9 - i));
    Console.WriteLine(String.Format("= {0:F20}", 6.9));
}

将与此C代码的C#等效:

{
    double i = 10 * 0.69;

    printf ( "%f\n", i );
    printf ( "  %.20f\n", i );
    printf ( "+ %.20f\n", 6.9 - i );
    printf ( "= %.20f\n", 6.9 );
}

但是,C#会产生输出:

6.9
  6.90000000000000000000
+ 0.00000000000000088818
= 6.90000000000000000000

尽管我在调试器中显示的值等于6.89999999999999946709(而不是6.9)。

与C相比,后者显示了格式要求的精度:

6.900000                          
  6.89999999999999946709          
+ 0.00000000000000088818          
= 6.90000000000000035527

这是怎么回事?

(Microsoft .NET Framework版本3.51 SP1 / Visual Studio C#2008 Express Edition)


我有数值计算方面的经验,并且在各种平台上实现间隔算术(一种用于估计由于复杂数值系统中的精度限制而导致的误差的技术)的经验。为了获得奖励,请不要尝试说明存储精度-
在这种情况下,这是64位双精度ULP的区别。

为了获得赏金,我想知道.Net如何(或是否)可以将C格式的double格式化为所需的精度。


阅读 231

收藏
2020-05-19

共1个答案

一尘不染

问题是,.NET始终会 应用格式 之前 四舍五入double为15位有效的十进制数字,而不管您的格式要求的精度和二进制数的确切十进制值如何。
__

我猜想Visual Studio调试器有其自己的格式/显示例程,这些例程直接访问内部二进制数,因此C#代码,C代码和调试器之间存在差异。

没有内置的函数可以访问a的确切十进制值double,也无法double将a
格式化为特定的小数位数,但是您可以自己完成此工作,方法是将内部二进制数拆开并重建为十进制值的字符串表示形式。

另外,您可以使用Jon
Skeet的DoubleConverter(从他的“二进制浮点和.NET”文章链接到)。该ToExactString方法具有返回a的精确十进制值的方法double。您可以轻松地对此进行修改,以将输出舍入为特定精度。

double i = 10 * 0.69;
Console.WriteLine(DoubleConverter.ToExactString(i));
Console.WriteLine(DoubleConverter.ToExactString(6.9 - i));
Console.WriteLine(DoubleConverter.ToExactString(6.9));

// 6.89999999999999946709294817992486059665679931640625
// 0.00000000000000088817841970012523233890533447265625
// 6.9000000000000003552713678800500929355621337890625
2020-05-19