根据维基百科,不同精度数据类型的布局为
单精度:指数(e):8位,分数(f):23位
双精度:e:11位,f:52位
四倍精度:e:15位,f:112位。
我写了一个小程序来输出C ++中的float,double和long double的数值限制(与g ++编译)
#include#include #include template void print(std::string name) { std::cout << name << " (" << sizeof(T) * 8 << "): " << std::numeric_limits ::epsilon() << "\t" << std::numeric_limits ::min() << "\t" << std::numeric_limits ::max() << std::endl; } int main() { std::cout.precision(5); print ("float"); print ("double"); print ("long double"); return 0; }
哪个输出(我已经在多台机器上运行了相同的结果)
float (32): 1.1921e-07 1.1755e-38 3.4028e+38 double (64): 2.2204e-16 2.2251e-308 1.7977e+308 long double (128): 1.0842e-19 3.3621e-4932 1.1897e+4932
上限与2 ^(2 ^(e-1))一致,对于float和double,ε与2 ^(-f)一致。对于较长的double,按照该逻辑,ε应当约为1.9259e-34。
有谁知道,为什么没有呢?
long double
不保证将其实现为IEEE-745的四倍精度。C ++参考内容为:
long double
-扩展的精度浮点类型。不一定映射到IEEE-754要求的类型。通常在x86和x86-64体系结构上使用80位x87浮点类型。
如果long double
实现为80位x86扩展精度,则epsilon为。这是您作为输出获得的值。2-63 = 1.0842e-19
一些编译器支持 __float128
具有四倍精度的类型。在GCC long double
成为一个别名__float128
,如果-mlong-double-128
命令行选项被使用,并且在x86_64目标__float128
被保证是IEEE四倍精度类型(在软件中实现)。
std::numeric_limits
并非专为__float128
。要获得epsilon的值,可以使用以下技巧(假设使用低端字节序的机器):
__float128 f1 = 1, f2 = 1; // 1.q -> ...00000000 std::uint8_t u = 1; std::memcpy(&f2, &u, 1); // 1.q + eps -> ...00000001 std::cout << double(f2 - f1); // Output: 1.9259e-34
使用GCC,您可以使用libquadmath:
#include... std::cout << (double)FLT128_EPSILON;
获得相同的输出。