正如我们所知,IEEE浮点数可以存储所有整数的精确表示和两次幂的倒数的整数倍,例如1/2或3/4,只要数字保持在浮点类型。
但是,浮点解析器通常会保证解析这些数字的十进制表示的确切结果吗?
例如,如果我在C程序中使用0.75
作为double
文字,编译器是否会保证编译的代码包含3/4的精确表示,或者是否存在风险它会产生0.7的一些不精确表示和0.05的一些不精确表示的总和
或者,同样地,如果我使用3e4
作为double
文字,可能确切的3乘以2 ^(4 * ln(10)/ ln(2))的不精确表示或者类似的数学?
在这个问题上,FP解析器通常需要遵循哪些标准,还是通常完全留给实现?如果是后者,是否有人知道像GCC或glibc这样重要的实现实际上是如何工作的?
我主要只是要求好奇而不是因为我想依赖这种行为;但有时候,如果知道值只能来自文字来源,则可以保证FP等式比较有效。
答案 0 :(得分:4)
C标准允许浮点常数是最接近文字常量的精确值的可表示值,或者是紧邻最近值的更大或更小的可表示值,根据C 2011 6.4.4.2 3.一些C实现做得更好。现代实现应该做得更好,因为已发布的算法可以正确地进行转换。
但是,C标准还提供了十六进制浮点常量,这使编译器可以很容易地正确进行转换。十六进制浮点常量的基本形式为0x hhh 。 hhh p eee ,其中 hhh 是十六进制数字并且 eee 是十进制指数,可能有一个符号。 (如果它们为零,则可以省略“。”一侧的十六进制数字,如果省略右边的数字,则可以省略句点。)指数是2的幂。
如果C实现中浮点数的基数为2的幂,则C标准要求正确舍入十六进制浮点常数。如果无法准确表示十六进制常量,则建议生成诊断消息。
例如,0x3p-2
应该是.75。
答案 1 :(得分:2)
通常无法保证在抽象语法树中获取源代码中十进制表示的最近浮点数。诸如C99之类的语言标准可以指定它必须在一个ULP内(即,不是最近的,而是最近的两个中的一个)。实际上,编译器可能会使用主机的strtof()
,strtod()
,...函数,这些函数同样没有被指定为返回最接近的数字,实际上是sometimes do not)。
一个ULP内约束意味着浮点数的精确十进制表示应转换为该数字。但是,许多解释器(如Ruby或Tcl)都带有own strtod()
,以防主机没有。{3}} strtod()
。这种实施方式很糟糕,并且可能会导致几个ULP错误的结果。
如果您需要通过实现自己的转换函数来解决这个问题,那么基于大整数的简单但正确的函数的大纲就在Exploring Binary blog上。
总结一下:对于指定在一个ULP内进行十进制到浮点转换的语言,只要您使用高质量的编译器实现,就可以使用精确的表示。对于没有这种规范的解释型语言,要么调用主机{{1}},在这种情况下你应该没问题,或者使用可怕的实现,在这种情况下你不是。