6

根据维基百科,不同精度数据类型的布局是

我写了一个小程序来输出 C++ 中floatdoublelong double的数值限制(用 g++ 编译)

#include<iostream>
#include<limits>
#include<string>

template<typename T>
void print(std::string name) {
    std::cout << name << " (" << sizeof(T) * 8 << "): " << std::numeric_limits<T>::epsilon() << "\t"  <<  std::numeric_limits<T>::min() << "\t" <<  std::numeric_limits<T>::max() << std::endl;
}

int main() {
    std::cout.precision(5);
    print<float>("float");
    print<double>("double");
    print<long double>("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)) 一致,对于floatdouble,epsilon 与 2^(-f) 一致。但是对于long double,按照这种逻辑, epsilon 应该大约是 1.9259e-34 。

有谁知道,为什么不是?

4

1 回答 1

5

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成为别名,并且在 x86_64 上,目标保证为IEEE 四倍精度类型(在软件中实现)。__float128-mlong-double-128__float128

std::numeric_limits不是专门为__float128. 要获得 epsilon 的值,可以使用以下技巧(假设是 little-endian 机器):

__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 <quadmath.h>
...

std::cout << (double)FLT128_EPSILON;

获得相同的输出。

于 2019-11-28T11:21:23.800 回答