固定点数格式说明符舍入双精度浮点数?

4

我对IEEE 754有相当了解,因此这不是那种“为什么将数字a和数字b相加会导致...”类型的问题。

相反,我想问一下我是否正确理解了定点数格式说明符,因为它对某些双精度值的行为不符合我的预期。

例如:

double d = 0x3FffffFFFFfffe * (1.0 / 0x3FffffFFFFffff);
Console.WriteLine(d.ToString("R"));
Console.WriteLine(d.ToString("G20"));
Console.WriteLine(d.ToString("F20"));

无论是 "R" 还是 "G" 格式说明符都会输出正确的值:0.99999999999999989,但是 "F" 格式说明符总是四舍五入到 1.0,无论我告诉它包括多少个小数位。即使我告诉它打印最大数量的99个小数位("F99"),它仍然只输出“1.”后面跟着99个零。

所以我的理解是否有误?能否有人指出规范中相关的部分,或者这种行为是否有问题?(这对我来说不是致命的问题,我只是想知道。)

这里 是我查看的内容,但我没有看到任何解释。

(这是 .Net4.0 版本)

1个回答

0

用户"w.b"链接到另一个问题,我怀疑该问题有可能提供了最佳答案...尽管在细节和文档方面存在一些模糊性。(不幸的是,该评论已被删除。)

链接的问题是C#中输出双精度数的格式化

简而言之,除非使用GR说明符,否则在自定义格式化之前,输出总是缩减为15个小数位。任何人都能够在该问题中提供的最佳文档是此MSDN页面。细节和措辞并不像我希望的那样清晰明了,但正如我所说,我认为这是我能找到的最好的答案。


两个链接中有些不太清楚的注释。1)数学运算是在二进制下进行的,因此需要将十进制转换为二进制,再将结果转换回十进制,这会影响结果的四舍五入。2)可以使用PC微处理器内部的浮点硬件或在C#编译器中模拟来执行数学运算。因此,有时候你会得到不同的答案,这取决于你是使用调试文件夹中的可执行文件还是使用发布文件夹中的可执行文件。 - jdweng
@jdweng 你提到的最后一部分不是JIT的实现细节吗?无论如何,如果你能提供任何关于这方面的规范或其他文档的链接,我都很想阅读。 :) - AnorZaken
如果我的记忆没有出错,规范允许在更高的精度下执行中间计算。换句话说,只要值仍然在CPU寄存器中,它就可以具有比规定精度更高的精度。(如果写回到内存中,则额外的精度将丢失。)这并不总是理想的,因此您可以使用强制转换语法将其截断为相同类型以消除额外的精度。换句话说,这段代码:float x = /*some calculation*/; bool isIdentical = x == (float)x;可能不会像人们期望的那样始终返回true...(如果我记得规范正确的话)。 - AnorZaken
调试编译可以更好地显示变量,但执行速度较慢。PC中的芯片非常复杂,在调试期间无法访问芯片中的所有连接。编译器在调试期间模拟连接。与芯片中的浮点单元的连接是其中之一,有时会进行模拟(或部分模拟)。例如,在发布可执行文件中,处理器中的下溢、上溢、除以零都是异常情况。在调试期间,您可能不希望发生异常,而是要检查状态寄存器。 - jdweng

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接