使用长双后缀L

时间:2017-06-28 12:22:28

标签: gcc floating-point

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)
...

我的问题是:
为什么这些值定义为long double,后缀为L,然后再投放回double

2。 问题:

为什么__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_MAXDBL_MIN宏定义,而没有编译器特定的重定向到带有下划线的版本。此外,最小正双精度值DBL_MIN和最大双精度值DBL_MAX比我的Linux gcc编译器的值稍微大一点(刚好与上面gcc v4.8.5中定义的宏相比): / p>

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

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

2 个答案:

答案 0 :(得分:5)

指定十进制的二进制浮点数有微妙的问题。

  

为什么将值定义为带有后缀L的long double,然后再将其转换为double?

对于典型的binary64,最大有限值约为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

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

微妙的转换差异的另一个来源,我希望这就是为什么&#39; L&#39;已添加double计算受处理器浮点单元的影响,该单元可能没有完全符合IEEE标准。更糟糕的结果可能是1.797...e+308常量转换为无穷大由于分钟转换错误导致double&#34; 使用双数学。通过转换为long double,这些long double转换错误非常小。然后将long double结果转换为double轮到期望的数字。

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

我希望以下 gcc VS 都不符合兼容的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的定义。 &#34; ...最小负整数,使得提升到该幂的10在标准化浮点数的范围内&#34;非整数答案在-307和-308之间,因此范围内的最小整数是-307。

  

观察部分

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

答案 1 :(得分:1)

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

This网站概述了IEEE 754浮点数。

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

因此,对于最大标准化值,我们的指数为2 ^ 1023。尾数的最大值刚好低于2(1.111等,点后52 1 1s,二进制),即~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。