问题描述
<float.h>
中Apple clang version 12.0.0 (clang-1200.0.32.2)
中的常量似乎没有道理。
DBL_MIN_EXP
是-1021
,而DBL_MAX_EXP
是1024
。但是,这与wikipedia says,“指数范围从−1022到+1023,...”不匹配。
另外,DBL_MIN_EXP
与DBL_MIN
不一致,而2.2250738585072014e-308
等于2⁻¹⁰²²
,有时写成0x1.0000000000000p-1022
。因此,我们的指数小于最小值-1021
。
同样,DBL_MIN_10_EXP
是-307
,考虑到DBL_MIN
的指数为e-308
,这是没有意义的。
在实际代码中使用时,DBL_MAX_EXP
的双1024
值溢出。例如,ldexp(1.0,1024)
给出inf
。
这是我的C代码:
#include <float.h>
#include <stdio.h>
#include <math.h>
#define SHOW_DOUBLE(s) printf("%.17lg \t%s\n",s,#s);
#define SHOW_INT(s) printf("%d \t%s\n",#s);
int
main()
{
SHOW_DOUBLE(DBL_MAX);
SHOW_DOUBLE(DBL_MIN);
SHOW_DOUBLE(DBL_EPSILON);
SHOW_INT(DBL_MAX_EXP);
SHOW_INT(DBL_MAX_10_EXP);
SHOW_INT(DBL_MIN_EXP);
SHOW_INT(DBL_MIN_10_EXP);
SHOW_INT(DBL_DIG);
SHOW_INT(DBL_MANT_DIG);
SHOW_INT(FLT_RADIX);
SHOW_INT(FLT_ROUNDS);
printf("%lf\n",ldexp(1.0,1024));
return 0;
}
这是输出:
1.7976931348623157e+308 DBL_MAX
2.2250738585072014e-308 DBL_MIN
2.2204460492503131e-16 DBL_EPSILON
1024 DBL_MAX_EXP
308 DBL_MAX_10_EXP
-1021 DBL_MIN_EXP
-307 DBL_MIN_10_EXP
15 DBL_DIG
53 DBL_MANT_DIG
2 FLT_RADIX
1 FLT_ROUNDS
inf
解决方法
一对一是规格的一部分。从 5.2.4.2.2浮动类型的特征
...
- 最小负整数,以使FLT_RADIX升至小于幂为归一化浮点数emin
- FLT_MIN_EXP
- DBL_MIN_EXP
- LDBL_MIN_EXP
...
- 最大整数,以使FLT_RADIX提高到一个小于的幂,即幂是可表示的有限浮点数emax
- FLT_MAX_EXP
- DBL_MAX_EXP
- LDBL_MAX_EXP
强调小于是我的
,我问了自己同样的问题,并意识到这是因为 IEEE 754 和 C 使用两个不同的 normalized forms:
- IEEE 754 使用介于 1(含)和 2(不含)之间的有效数来表示普通数字:
x = sign × significand × 2指数,编码为 S|E|F 其中 sign = (−1)S ; 有效数 =
- 1.F if Emin ≤ E ≤ Emax(正常数),
- 0 如果 E = Emin − 1 且 F = 0(零),
- 0.F if E = Emin − 1 and F ≠ 0(次正规数),
- ∞ 如果 E = Emax + 1 且 F = 0(无穷大),
- NaN if E = Emax + 1 and F ≠ 0(不是数字);
指数 = max(E,Emin) − 指数偏差 .
- C 使用介于 0.5(含)和 1(不含)之间的significand'作为普通数字:
x = sign' × significand' × 2指数',编码为 S|E|F 其中 sign' = (−1)S ; significand' =
- 0.1F 如果 Emin ≤ E ≤ E max(正常数),
- 0 如果 E = Emin − 1 且 F = 0(零),
- 0.0F 如果 E = Emin − 1 且 F ≠ 0(次正规数),
- ∞ 如果 E = Emax + 1 且 F = 0(无穷大),
- NaN if E = Emax + 1 and F ≠ 0(不是数字);
exponent′ = max(E + 1,Emin + 1) − exponent偏见。
因为 x = sign × significand × 2指数 = sign' × significand' × 2exponent',IEEE 754规范化形式和C规范化形式之间的关系如下保持:
- sign' = sign;
- significand′ = significand/2;
- 指数' = 指数 + 1.
特别是在 binary64 格式中,这就是为什么 exponentmin = -1022 在 IEEE 754 规范化形式和 exponent'min = -1021 以 C 规范化形式 (DBL_MIN_EXP
) 和 exponentmax = 1023 以 IEEE 754 规范化形式和 exponent'max = 1024 以 C 规范化形式 (DBL_MAX_EXP
)。
在 Python 中:
- IEEE 754 规范化significand 和指数可以通过以下方式提取:
math.ldexp(x,-math.floor(math.log2(x))),math.floor(math.log2(x))
- C 规范化的significand' 和exponent' 可以通过以下方式提取:
math.frexp(x)
例如:
>>> import math
>>> x = 12
>>> math.ldexp(x,math.floor(math.log2(x))
(1.5,3)
>>> math.frexp(12)
(0.75,4)