4

众所周知,IEEE 浮点数可以存储所有整数和 2 的倒数的整数倍的精确表示,例如 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 相等比较可以保证工作。

4

2 回答 2

4

根据 C 2011 6.4.4.2 3,C 标准允许浮点常量是最接近文字常量的精确值的可表示值,或者是与最接近的值直接相邻的更大或更小的可表示值。一些 C 实现确实更好的。现代实现应该做得更好,因为已经发布了正确进行转换的算法。

但是,C 标准还提供了十六进制浮点常量,这使编译器可以轻松正确地进行转换。十六进制浮点常量的基本形式为 0x hhhhhh p eee,其中hhh是十六进制数字,eee是十进制指数,可能有符号。(“.”一侧的十六进制数字如果为零,可以省略,如果右边的数字省略,句点可以省略。)指数是2的幂。

如果浮点数的基数在 C 实现中是 2 的幂,则 C 标准要求正确舍入十六进制浮点常数。如果无法准确表示十六进制常数,它建议生成诊断消息。

例如0x3p-2应该正好是 0.75。

于 2013-01-15T13:00:07.650 回答
2

通常不能保证在抽象语法树中获得最接近源代码中十进制表示的浮点数。诸如 C99 之类的语言标准可能会指定它必须在一个 ULP 内(即,不是最接近的,而是两个最接近的之一)。在实践中,编译器可能会使用主机的strtof(), strtod(),... 函数,这些函数并没有被指定为返回最接近的数字,而且有时确实没有)。

within-one-ULP 约束意味着浮点数的精确十进制表示转换为该数字。但是,许多解释器(如 Ruby 或 Tcl)都带有自己 strtod()解释器,以防主机没有。这种实现很糟糕,并且可能会返回多个 ULP 错误的结果。

如果您需要通过实现自己的转换函数来解决这个问题,一个简单但正确的基于大整数的函数的大纲在Exploring Binary 博客上


总结一下:对于在一个 ULP 内指定十进制到浮点转换的语言,只要您使用高质量的编译器实现,您应该可以很好地进行精确表示。对于没有此类规范的解释型语言,要么strtod()调用主机,在这种情况下你应该没问题,要么使用可怕的实现,在这种情况下你不是。

于 2013-01-15T06:04:23.203 回答