3 回答
TA贡献1874条经验 获得超12个赞
问题是,.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
TA贡献2003条经验 获得超2个赞
Digits after decimal point
// just two decimal places
String.Format("{0:0.00}", 123.4567); // "123.46"
String.Format("{0:0.00}", 123.4); // "123.40"
String.Format("{0:0.00}", 123.0); // "123.00"
// max. two decimal places
String.Format("{0:0.##}", 123.4567); // "123.46"
String.Format("{0:0.##}", 123.4); // "123.4"
String.Format("{0:0.##}", 123.0); // "123"
// at least two digits before decimal point
String.Format("{0:00.0}", 123.4567); // "123.5"
String.Format("{0:00.0}", 23.4567); // "23.5"
String.Format("{0:00.0}", 3.4567); // "03.5"
String.Format("{0:00.0}", -3.4567); // "-03.5"
Thousands separator
String.Format("{0:0,0.0}", 12345.67); // "12,345.7"
String.Format("{0:0,0}", 12345.67); // "12,346"
Zero
Following code shows how can be formatted a zero (of double type).
String.Format("{0:0.0}", 0.0); // "0.0"
String.Format("{0:0.#}", 0.0); // "0"
String.Format("{0:#.0}", 0.0); // ".0"
String.Format("{0:#.#}", 0.0); // ""
Align numbers with spaces
String.Format("{0,10:0.0}", 123.4567); // " 123.5"
String.Format("{0,-10:0.0}", 123.4567); // "123.5 "
String.Format("{0,10:0.0}", -123.4567); // " -123.5"
String.Format("{0,-10:0.0}", -123.4567); // "-123.5 "
Custom formatting for negative numbers and zero
String.Format("{0:0.00;minus 0.00;zero}", 123.4567); // "123.46"
String.Format("{0:0.00;minus 0.00;zero}", -123.4567); // "minus 123.46"
String.Format("{0:0.00;minus 0.00;zero}", 0.0); // "zero"
Some funny examples
String.Format("{0:my number is 0.0}", 12.3); // "my number is 12.3"
String.Format("{0:0aaa.bbb0}", 12.3);
TA贡献1842条经验 获得超12个赞
尽管这个问题已经结束,但我认为值得一提的是这种暴行是如何产生的。在某种程度上,您可能会指责C#规范,该规范指出双精度数必须具有15或16位的精度(IEEE-754的结果)。进一步(第4.1.6节)指出,允许实现使用更高的精度。注意:更高,而不是更低。他们甚至允许从IEEE-754偏离:类型的表达式x * y / z,其中x * y将产生+/-INF,但将是一个有效的范围分割后,不必导致错误。此功能使编译器更容易在可以产生更好性能的体系结构中使用更高的精度。
但是我答应了“理由”。这里有一个引号(您请求在你最近的评论一个资源)从共享源代码CLI中clr/src/vm/comnumber.cpp:
“为了提供既便于显示又可往返的数字,我们使用15位数字解析该数字,然后确定它是否往返为相同的值。如果是,则将NUMBER转换为字符串,否则用17位数字重新解析并显示出来。”
换句话说:MS的CLI开发团队决定既可以双向访问又可以显示漂亮的值,这些值并不难读。是好是坏?我希望选择加入或退出。
找出任何给定数字的这种往返性的技巧是什么?转换为通用NUMBER结构(对于double的属性具有单独的字段),然后再返回,然后比较结果是否不同。如果不同,则使用精确值(与中的值6.9 - i相同),如果相同,则使用“漂亮值”。
就像您在对Andyp的评论中提到的那样,6.90...00等于6.89...9467。现在您知道为什么0.0...8818使用它了:它与有所不同0.0。
这15位数字是硬编码的,只能通过重新编译CLI,使用Mono或调用Microsoft并说服他们添加一个选项来打印完整的“精度”来更改(这不是真正的精度,但是由于缺少一个更好的词)。自己计算52位精度或使用前面提到的库可能会更容易。
编辑:如果您想用IEE-754浮点进行实验,请考虑使用此在线工具,该工具向您显示浮点的所有相关部分。
- 3 回答
- 0 关注
- 392 浏览
添加回答
举报