我正在寻找有关GCC/x86 的详细信息(更多的是出于好奇而不是因为实际问题)long double。__float128
可能很少有人会需要这些(我只是,有史以来第一次,真正需要 a double),但我想知道你的工具箱里有什么以及它是关于什么的仍然是值得的(而且很有趣)。
鉴于此,请原谅我有些开放的问题:
- 有人可以解释这些类型的实现原理和预期用途,也可以相互比较吗?例如,它们是否因为标准允许类型而“令人尴尬的实现”,如果它们只是与 相同的精度
double,或者它们打算作为一流类型,有人可能会抱怨? - 或者,有人可以分享一个好的、可用的网络参考吗?谷歌搜索
"long double" site:gcc.gnu.org/onlinedocs并没有给我太多真正有用的东西。 - 假设常见的口头禅“如果你认为你需要双精度,你可能不了解浮点数”不适用,即你真的需要比精度更高的精度
float,而且不关心是 8 字节还是 16 字节的内存烧毁...是否可以合理地期望一个人也可以直接跳到long double或者__float128没有double显着的性能影响? - 历史上,当值在内存和寄存器之间移动时,英特尔 CPU 的“扩展精度”特性一直是令人讨厌的意外之源。如果实际存储了 96 位,则该
long double类型应消除此问题。另一方面,我知道该long double类型与 是互斥的-mfpmath=sse,因为 SSE 中没有“扩展精度”之类的东西。__float128,另一方面,在 SSE 数学上应该可以很好地工作(尽管在没有四精度指令的情况下肯定不是在 1:1 指令库上)。我的这些假设是对的吗?
(3. 和 4. 可能可以通过在分析和反汇编上花费一些工作来弄清楚,但也许其他人之前也有同样的想法并且已经完成了这项工作。)
背景(这是 TL;DR 部分):
我最初偶然发现long double是因为我正在查找DBL_MAX,<float.h>顺便说LDBL_MAX一下在下一行。“哦,看,GCC 实际上有 128 位双打,不是我需要它们,但是……很酷”是我的第一个想法。惊喜,惊喜:sizeof(long double)返回 12……等等,你是说 16?
毫不奇怪,C 和 C++ 标准没有给出非常具体的类型定义。C99 (6.2.5 10) 表示的数字是C++03 状态 (3.9.1 8)double的子集,其精度至少与(这是同一件事,只是措辞不同)。基本上,标准将所有内容留给实现,与、和.long doublelong doubledoublelongintshort
维基百科说 GCC 使用“x86 处理器上的 80 位扩展精度,而不管使用的物理存储如何”。
GCC 文档在同一页面上声明,由于 i386 ABI,类型的大小为 96 位,但任何选项(嗯?什么?)启用的精度不超过 80 位,还有 Pentium 和更新版本处理器希望它们对齐为 128 位数字。这是 64 位下的默认设置,可以在 32 位下手动启用,从而产生 32 位的零填充。
运行测试的时间:
#include <stdio.h>
#include <cfloat>
int main()
{
#ifdef USE_FLOAT128
typedef __float128 long_double_t;
#else
typedef long double long_double_t;
#endif
long_double_t ld;
int* i = (int*) &ld;
i[0] = i[1] = i[2] = i[3] = 0xdeadbeef;
for(ld = 0.0000000000000001; ld < LDBL_MAX; ld *= 1.0000001)
printf("%08x-%08x-%08x-%08x\r", i[0], i[1], i[2], i[3]);
return 0;
}
使用 时long double,输出看起来有点像这样,标记的数字是恒定的,而所有其他数字最终都会随着数字越来越大而变化:
5636666b-c03ef3e0-00223fd8-deadbeef
^^ ^^^^^^^^
这表明它不是80 位数字。一个 80 位数字有 18 个十六进制数字。我看到 22 个十六进制数字发生了变化,这看起来更像是一个 96 位数字(24 个十六进制数字)。它也不是一个 128 位的数字,因为没有被触及,这与返回 120xdeadbeef是一致的。sizeof
的输出__int128看起来真的只是一个 128 位的数字。所有位最终都会翻转。
如文档所示,使用 32 位零填充与 128 位不-m128bit-long-double对齐。它也不使用,但确实似乎与 128 位对齐,并用值(?!) 填充。long double__int1280x7ffdd000
此外,LDBL_MAX, 似乎对+inf和 都long double有效__float128。在相同的位模式中添加或减去类似1.0E100或1.0E2000到/从的数字。
到现在为止,我相信常量将包含最大的可表示数字,但事实并非如此(显然情况并非如此?)。我也不太确定一个 80 位数字如何可以想象128 位值......也许我在一天结束时太累了并且做错了什么。LDBL_MAXfoo_MAX +inf+inf