四倍精度的 Epsilon (gcc)
Epsilon in quadruple precision (gcc)
根据维基百科,不同精度数据类型的布局是
- single precision:指数(e):8位,小数(f):23位
- double precision: e: 11 位, f: 52 位
- quadruple precision: e: 15 位, f: 112 位.
我写了一个小程序来输出float、double和long double[=38的数值限制=] 在 C++ 中(用 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)) 一致,对于 float 和 double,epsilon 与2^(-f)。对于 long double,但是根据该逻辑,epsilon 应该大致为 1.9259e-34。
有谁知道,为什么不知道?
long double
不保证实现为 IEEE-745 四倍精度。 C++ reference reads:
long double
- extended precision floating point type. Does not necessarily map to types mandated by IEEE-754. Usually 80-bit x87 floating point type on x86 and x86-64 architectures.
如果long double
实现为80-bits x86 extended precision,则epsilon为2<sup>-63</sup> = 1.0842e-19
.这是您作为输出获得的值。
一些编译器 support __float128
type that has quadruple precision. In GCC long double
becomes an alias for __float128
if -mlong-double-128
command line option is used, and on x86_64 targets __float128
is guaranteed 是 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 <quadmath.h>
...
std::cout << (double)FLT128_EPSILON;
获得相同的输出。
根据维基百科,不同精度数据类型的布局是
- single precision:指数(e):8位,小数(f):23位
- double precision: e: 11 位, f: 52 位
- quadruple precision: e: 15 位, f: 112 位.
我写了一个小程序来输出float、double和long double[=38的数值限制=] 在 C++ 中(用 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)) 一致,对于 float 和 double,epsilon 与2^(-f)。对于 long double,但是根据该逻辑,epsilon 应该大致为 1.9259e-34。
有谁知道,为什么不知道?
long double
不保证实现为 IEEE-745 四倍精度。 C++ reference reads:
long double
- extended precision floating point type. Does not necessarily map to types mandated by IEEE-754. Usually 80-bit x87 floating point type on x86 and x86-64 architectures.
如果long double
实现为80-bits x86 extended precision,则epsilon为2<sup>-63</sup> = 1.0842e-19
.这是您作为输出获得的值。
一些编译器 support __float128
type that has quadruple precision. In GCC long double
becomes an alias for __float128
if -mlong-double-128
command line option is used, and on x86_64 targets __float128
is guaranteed 是 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 <quadmath.h>
...
std::cout << (double)FLT128_EPSILON;
获得相同的输出。