floating-point - PPC64 long double的机器epsilon计算
问题描述
我正在玩在 qemu 中模拟的 PPC64 虚拟机,试图模仿 POWER8 CPU。
在这里,该long double
类型与 x86 中用于长双精度的 80 位浮点数不同,并且据我所知,它也不符合 IEEE754 的 float128,因为根据 C 宏它有一个 106 位的尾数LDBL_MANT_DIG
(对比。 IEEE754 为其 float128 规定的 112 位尾数)。
维基百科说 IEEE754 float128 的机器 epsilon 应该在 1.93e-34 左右,比 80 位 x86 浮点数 (1.08e-19) 要好得多。
然而,当我尝试在这个虚拟机中获取机器 epsilon 时,我得到了一个相当令人惊讶的答案:
#include <iostream>
int main()
{
long double eps = 1.0l;
while (1.0l + 0.5l * eps != 1.0l)
eps = 0.5l * eps;
std::cout << eps << std::endl;
return 0;
}
它输出以下内容:
4.94066e-324
我从LDBL_EPSILON
和 从得到相同的结果std::numeric_limits<long double>::epsilon()
。
这将使它比预期的精确度高出大约 10 倍,逻辑告诉我这应该是不可能的。看到尾数正好是 2x53(IEEE754 的 float64 的),我认为它可能使用双双结构,维基百科还说,它对小数字的精度应该低于 IEEE754 float128。
这里发生了什么?
解决方案
首先,让我假设您的操作系统是 Linux。到目前为止,64 位 PowerPC 上的所有编译器都默认使用“双双”类型long double
,其格式不符合 IEEE 标准。
格式其实是两个double
s的组合,所以理解为struct { double high; double low; }
。高的部分与普通的没有什么不同double
,而低的部分提供了扩展的尾数。整体的指数与 相同double
,这意味着它的最大可表示数不比double
's 大几个数量级(因为 double-double 的尾数更长,所以它们仍然不同)。
目前双双浮点数的运算没有原生 PowerPC 指令支持。a+b
long double 最终将被转换为对 function 的调用__gcc_qadd
。(LLVM 的compiler-rt和 GCC 的libgcc都有自己的实现,见add 函数的源代码)
从POWER ISA 3.0 (Power9) 开始,支持“binary128”(符合 IEEE 的 128 位浮点类型)的本机指令支持。您可以使用-mcpu=power9 -mfloat128
来启用该功能并使用__float128
来表示它,或者添加-mabi=ieeelongdouble
以使编译器将 long double 视为 binary128 而不是 double-double(以及 C 库声明)。
Binary128 不是两个双精度的组合,而是通过向量寄存器存储/传递,并且比双精度具有更好的精度,尾数为 112 位,指数为 15 位。通过使用 compiler-rt/libgcc 中的支持函数,GCC/Clang 实际上支持带有 VSX(Power7 或更高版本)的目标的 binary128。(例如,为 Power9 和更高版本、为 Power7 和 Power8a+b
生成指令)xsaddqp
__addkf3
如果您的工具链相对较新(例如,高级工具链-mabi=ieeelongdouble
14 或更新版本),请尝试使用 C 代码启用。在 C++ 库支持完成后,GCC 和 Clang计划将来在 64 位 little endian 上将默认的 long double 类型切换为 binary128。
推荐阅读
- ruby - 你如何从ruby中的另一个类调用一个类变量
- github-pages - Github Pages:无限重定向,只有 2 条记录
- rust - 如何在源文件中将字符“E”表示为单个字节?
- javascript - Chrome 图标看起来很苍白
- mysql - 使用 MySQL 连接器 (.NET) 导致锁定的并发 MySQL 事务
- java - 创建一个类。添加以下方法:min、max、isEven、square。在 main 方法中,调用那些方法
- python-3.x - ATBS Regex Search Project-如何解决本地范围错误?
- java - 无法将 Java 项目中的类文件导入同一项目中的另一个类文件
- c++ - 带有通配符和标头的不同文件夹中的 Makefile 对象(模块化编译)?
- wagtail - 如何 ajaxify Wagtail-CMS 页面的操作?