2

“完全精确”是指正确的结果不会与我使用 C# 程序计算的结果不同的情况。

我已经通过在 C# 和 C++ 下运行相同的测试来检查这一点(不使用 cout.precision())。我确信我的程序在 C# 和 C++ 下的 2 个变体在相同的测试中表现相似。

C# 上的示例代码。

double a;
//...code...
Console.WriteLine(a.ToString(CultureInfo.InvariantCulture));

相同,但在 C++ 上。

double a;
//...code...
cout << a << endl;

实际上,我没有 cout.precision() 的 C++ 程序失败,而只有 Console.WriteLine() 的 C# 通过了。

我知道发生这种情况是因为我的 C++ 程序以某种方式(可能是魔法)截断了数字并且精度丢失了。但是通过所有测试是否意味着 C# 总是以全精度打印一个双精度变量?

4

3 回答 3

5

如果你用“R”格式说明符格式化你的双精度,你会得到一个“往返”表示。有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx#RFormatString。用法:

string s = someDoubleValue.ToString("R");

如果未指定格式说明符,则默认格式说明符是“G”(通用),它“将数字转换为最紧凑的定点或科学记数法,具体取决于数字的类型以及是否存在精度说明符。” 有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx#GFormatString。如果未提供精度说明符,则double获得 15 位精度,因此使用“G”可能会丢失精度。

于 2012-10-02T20:30:21.503 回答
3

C++ 和 C# 都将浮点数存储为二进制分数。double并非所有以 2 为基数的 64 位表示的数字都以 10 为基数具有相当长的表示。从 a 转换为 15 位小数时,必然会经常发生一些舍入。

您看到差异的原因是两种语言在打印时将基数 2 转换为基数 10 的默认精度选择不同。(您可以通过打印来自定义选择,输出精度将在您想要的地方四舍五入。)

于 2012-10-02T20:29:57.393 回答
1

双精度值的精确十进制表示可以有几十个位置,所以这方面的答案是“否”。有一种往返格式可以保证足够的精度,以在有限数字十进制字符串和有限数字二进制双精度之间提供一对一的对应关系(我不知道它如何处理 NaN 和无穷大),但 ToString 不使用除非您指定该格式(“R”),否则在这方面的答案是否定的。

事实上,如果你使用这个重载,你会得到一个根据“G”格式说明符格式化的结果(参见Double.ToString Method (IFormatProvider))。

有关所有标准说明符的信息,请参阅标准数字格式字符串

Jon Skeet 有一个类可以将双精度数转换为其(可能很长)精确的十进制表示形式;相关文章在这里:http ://csharpindepth.com/Articles/General/FloatingPoint.aspx ;课程本身在这里:http ://www.yoda.arachsys.com/csharp/DoubleConverter.cs

于 2012-10-02T20:32:49.913 回答