这是clang中的错误吗?
这会打印出最大双倍值:
long double a = DBL_MAX;
printf("%Lf\n", a);
Run Code Online (Sandbox Code Playgroud)
它是:
179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000
这将打印出最大的long double值:
long double a = LDBL_MAX;
printf("%Lf\n", a);
Run Code Online (Sandbox Code Playgroud)
它是:
/* … bigger, but not displayed here. For a good reason. ;-) */
Run Code Online (Sandbox Code Playgroud)
这很清楚.
但是,当我使用算术表达式,即可编译为初始化程序的编译时,我得到了一个令人惊讶的结果:
long double a = 1.L + DBL_MAX + 1.L;
printf("%Lf\n", a);
Run Code Online (Sandbox Code Playgroud)
这仍然打印出DBL_MAX而不是DBL_MAX + 2 !?
如果计算在运行时完成,则相同:
long double b = 2.L;
long double a = DBL_MAX;
printf("%Lf\n", a+b);
Run Code Online (Sandbox Code Playgroud)
仍然是DBL_MAX.
$ clang --version
Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn)
Target: x86_64-apple-darwin12.4.0
Thread model: posix
Run Code Online (Sandbox Code Playgroud)
不是错误. long double在clang/x86_64中有64位精度,结果四舍五入以适合该格式.
如果我们使用十六进制而不是二进制,这将更清楚. DBL_MAX是:
0xfffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Run Code Online (Sandbox Code Playgroud)
因此,确切的数学结果1.L + DBL_MAX是:
0xfffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
Run Code Online (Sandbox Code Playgroud)
...但是这不能表示为a long double,因此计算结果四舍五入到最接近的可表示long double,这只是DBL_MAX; 添加1不会(也不应该)更改值.
(它向下舍入而不是向上,因为下一个更大的可表示数字是
0xfffffffffffff801000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Run Code Online (Sandbox Code Playgroud)
这是多从数学上精确的结果比DBL_MAX是)更远.
IEE754浮点的double尾数为53位宽(52个物理+ 1个隐含位).这意味着double可以准确地表示-2^53...+2^53范围内的连续整数(即从)-9007199254740992到+9007199254740992.之后,类型不能再精确地表示连续的整数.相反,该类型只能表示偶数整数值.任何奇值将根据一些具体实施方式中的规则被舍入到一个相邻的偶数值.因此,完全可以预期,由于四舍五入,添加1到9007199254740992内部double可能不会产生任何结果.从该限制开始,您必须至少添加2以查看值的更改(直到您到达添加点2将停止产生任何影响,你必须至少添加4,等等).
long double如果它大于double您的平台,则适用相同的逻辑.在x86上long double可能指的是具有64位尾数的硬件80位浮点类型.这意味着即使使用该类型,精确表示连续整数的范围也仅限于此-2^64...+2^64.
价值DBL_MAX远,FAR,FAAAAR!在那范围之外.这意味着尝试添加1到DBL_MAX不会对价值有任何影响.添加2也不会有任何影响.既不会4,也不会1024,甚至也不会4294967296.您必须在2^960区域(实际nextafter(2^959))中添加一些内容才能对DBL_MAX以80位long double格式存储的值产生影响.
这是预期的行为。
long double a = 1.L + DBL_MAX + 1.L;
Run Code Online (Sandbox Code Playgroud)
类型long double是浮点:它具有有限的精度。大多数运算的结果都会四舍五入到最接近的可表示值。