用长双后缀 L 定义的浮点限制(双精度)



1. 问题:

我对 gcc v4.8.5 Linux 中的DBL_MAXDBL_MIN定义有疑问。
它们在limit.h中定义为:

#define DBL_MAX     __DBL_MAX__
#define DBL_MIN     __DBL_MIN__

其中__DBL_MIN____DBL_MAX__特定于编译器,可通过以下方式获取:

$ gcc -dM -E - < /dev/null
...
#define __DBL_MAX__ ((double)1.79769313486231570815e+308L)
#define __DBL_MIN__ ((double)2.22507385850720138309e-308L)
...

我的问题是:
为什么将值定义为带有后缀Llong double,然后转换回double

阿拉伯数字。 问题:

为什么__DBL_MIN_10_EXP__-307定义,但最小指数却-308,因为它在上面DBL_MIN宏中使用?在最大指数的情况下,它是用308定义的,我可以理解它,因为它被DBL_MAX宏使用。

#define __DBL_MAX_10_EXP__ 308
#define __DBL_MIN_10_EXP__ (-307)

不是问题的一部分,只是我所做的观察:

顺便说一下,将Windows与Visual Studio 2015一起使用,只有定义的DBL_MAX宏和DBL_MIN宏,而无需编译器特定的重定向到带有下划线的版本。此外,最小正双精度值DBL_MIN和最大双精度值DBL_MAX比我的 Linux gcc 编译器的值大一点(仅与上面 gcc v4.8.5 中定义的宏相比):

#define DBL_MAX        1.7976931348623158e+308
#define DBL_MIN        2.2250738585072014e–308

此外,Microsoft编译器将long double限制设置为double的值,似乎不支持真正的long double实现。

在十进制中指定二进制浮点数存在细微的问题。

为什么这些值被定义为带有后缀 L 的长双精度,然后转换回双精度?

对于典型的二进制64,最大有限值约为1.795e+308或完全

179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368

转换为唯一double所需的位数可能多达DBL_DECIMAL_DIG(通常为 17 位,至少 10 位)。 无论如何,使用指数表示法当然是清楚的,但不会过于精确。

/*
1 2345678901234567 */          // Sorted 
1.79769313486231550856124...   // DBL_MAX next smallest for reference
1.79769313486231570814527...   // Exact
1.79769313486231570815e+308L   // gcc
1.7976931348623158e+308        // VS (just a hair closer to exact than "next largerst")
1.7976931348623159077293....   // DBL_MAX next largest if not limited by range

各种编译器可能无法完全按预期转换此字符串。 有时会忽略一些最低有效数字 - 尽管这是由编译器控制的。

微妙转换差异的另一个来源,我希望这就是添加"L"的原因double计算受到处理器浮点单元的影响,该浮点单元可能不完全符合IEEE标准。 更糟糕的结果可能是,由于使用双精度数学的分钟转换错误,1.797...e+308常数转换为无穷大,即"代码到double"。 通过转换为long double,这些long double转换错误非常小。 然后将long double的结果转换为double轮到希望的数字。

简而言之,强制L数学可以确保常数不会无意中成为无穷大

我希望以下内容与gccVS都不匹配,足以满足兼容的 IEEE 754 标准 FPU。

#define __DBL_MAX__ 1.7976931348623157e+308

回归double的演员阵容就是要让DBL_MAX成为double。 这将满足许多代码的期望,即DBL_MAXdouble而不是long double。 不过,我没有看到任何规范需要这样做。

为什么DBL_MIN_10_EXP定义为 -307,而最小指数是 -308?

那就是遵守DBL_MIN_10_EXP的定义。 "...最小负整数,使得 10 提高到该幂在规范化浮点数范围内" 非整数答案介于 -307 和 -308 之间,因此范围内的最小整数为 -307。

观察部分

尽管 VS 将long double视为不同的类型,但使用与double相同的编码,因此使用L没有数字优势。

我不知道为什么使用L后缀。

此站点概述了 IEEE 754 浮点数。

指数为 11 位,偏移量为 1023。但是,0 和 2047 的指数是为特殊数字保留的。因此,这意味着指数可以从 2046-1023=1023 到 1-1023=-1022 变化。

因此,对于最大归一化值,我们的指数为 2^1023。尾数的最大值略低于 2(1.111 等,点后有 52 个 1,二进制),即 ~2*2^1023 = ~1.79e308。

对于最小归一化值,我们的指数为 2^-1022。最小尾数正好是 1,给我们的值为 1*2^-1022 = ~2.22e-308。目前为止,一切都好。

DBL_MIN_10_EXP 和 DBL_MAX_10_EXP 是归一化的 10 的最小/最大指数。对于最大值 1e308 小于 ~1.79e308,因此值为 308。对于最小值,1e-308 太小 - 它低于 ~2.22e-308。1e-307 大于 ~2.22e-308,因此值为 -307。

最新更新