Parsing 精确浮点数的编译器解析

Parsing 精确浮点数的编译器解析,parsing,floating-point,floating-accuracy,Parsing,Floating Point,Floating Accuracy,如我们所知,IEEE浮点数可以存储所有整数的精确表示和二次幂的倒数的整数倍,如1/2或3/4,只要这些数字保持在浮点类型的范围内 然而,浮点解析器通常能保证解析这些数字的十进制表示的精确结果吗 例如,如果我在C程序中使用0.75作为double文本,编译器会保证编译后的代码包含3/4的精确表示,还是会有产生某些不精确表示0.7和某些不精确表示0.05之和的风险 或者,同样地,如果我使用3e4作为double文本,那么精确的3是否可以乘以2^(4*ln(10)/ln(2))的不精确表示或类似的数学

如我们所知,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相等比较可以保证工作。

通常无法保证在抽象语法树中获得与源代码中十进制表示形式最接近的浮点数。C99之类的语言标准可能会规定它必须在一个ULP内(即,不是最近的,而是两个最近的ULP中的一个)。实际上,编译器可能使用主机的
strof()
strod()
,…函数,这些函数也没有指定为返回最接近的数字,事实上也是如此)


“一个ULP内”约束意味着应将浮点数的精确十进制表示形式转换为该数字。但是,许多解释器(如Ruby或Tcl)都带有
strod()
,以防主机没有解释器。该实现非常糟糕,可能返回多个ULP错误的结果

如果您需要通过实现自己的转换函数来解决这个问题,那么基于大整数的简单但正确的函数的大纲就在下面



总而言之:对于一种在一个ULP内指定十进制到浮点转换的语言,只要使用高质量的编译器实现,就应该可以精确表示。对于没有此类规范的解释性语言,要么调用主机
strod()
,在这种情况下,您应该可以处理,要么使用了一个可怕的实现,在这种情况下,您不会。根据C 2011 6.4.4.2.3,C标准允许浮点常量为最接近文字常量精确值的可表示值,或紧邻最接近值的较大或较小的可表示值。有些C实现做得更好。现代实现应该做得更好,因为已经发布了正确进行转换的算法

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

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


例如,
0x3p-2
应该精确到.75。

请注意,我主要感兴趣的不是结果在不精确时如何舍入,而是可以精确表示的数字是否被解析为其精确表示。@Dolda2000是的,我对这个问题进行了重新解释,但在最后一次编辑之后,我希望你最初问题的答案也在那里。顺便说一句,“0.7的某些不精确表示和0.05的某些不精确表示之和”正是“可怕的实现”错误的原因,也许不是0.75,但肯定是0.75e30。“在一个ULP内约束意味着浮点数的精确十进制表示应该转换为该数字。”--是吗?从技术上讲,上面的数字和下面的数字(精确地)不都在精确结果的一个ULP内吗?@Dolda2000我的意思是严格的。但实际上在C99中,措辞是最近的可表示值,或与最近的可表示值相邻的较大或较小的可表示值,以实现定义的方式选择它使用了更多的单词,但对于精确值,与我的公式具有相同的模糊性。如果你特别询问C,你可能希望将你的问题标记为
C
(在这种情况下,我非常确定答案在理论上是否定的,在实践中是肯定的。)NEMO:我没有特别地询问C。不过我只是用它作为一个例子。好答案。你知道在任何C++规范中是否出现了相似的语言?还是与最近值相邻的较大或更小的可表示值?“--那么,我认为标准没有明确提到具有实际精确表示的值,并且它实际上并不要求它们精确表示?为了记录在案,我尝试给GCC(带有
-Wall
)常量
0x19238192839183983p-10
,但它没有发出警告,表明它可以