长双精度(GCC特定)和浮点数128

长双精度(GCC特定)和浮点数128,gcc,long-double,Gcc,Long Double,我正在GCC/x86中查找有关长双精度和浮点128的详细信息(更多是出于好奇,而不是因为实际问题) 可能很少有人会需要这些(我只是第一次真正需要一个双倍的),但我想知道你的工具箱里有什么以及它是关于什么的仍然是值得的(而且很有趣) 有鉴于此,请原谅我有些开放性的问题: 有人能解释一下这些类型的实现原理和预期用途吗?例如,它们是“尴尬的实现”,因为标准允许使用该类型,如果它们的精度与double相同,有人可能会抱怨,还是打算作为一级类型 或者,是否有人有一个好的、可用的web引用可以共享?谷歌搜索

我正在GCC/x86中查找有关
长双精度
浮点128
的详细信息(更多是出于好奇,而不是因为实际问题)

可能很少有人会需要这些(我只是第一次真正需要一个
双倍的
),但我想知道你的工具箱里有什么以及它是关于什么的仍然是值得的(而且很有趣)

有鉴于此,请原谅我有些开放性的问题:

  • 有人能解释一下这些类型的实现原理和预期用途吗?例如,它们是“尴尬的实现”,因为标准允许使用该类型,如果它们的精度与
    double
    相同,有人可能会抱怨,还是打算作为一级类型
  • 或者,是否有人有一个好的、可用的web引用可以共享?谷歌搜索“长双”网站:gcc.gnu.org/onlinedocs
  • 并没有给我多少真正有用的信息
  • 假设常见的咒语“如果你认为你需要双精度,你可能不理解浮点”不适用,也就是说,你真的需要更多的精度而不仅仅是
    float
    ,你也不在乎8字节还是16字节的内存被烧掉。。。我们是否有理由期望在没有显著性能影响的情况下跳转到
    长双精度
    \uuuu128
    而不是
    双精度
  • 当值在内存和寄存器之间移动时,Intel CPU的“扩展精度”功能历来是令人不快的意外之源。如果实际存储了96位,则长双精度
  • 类型应该可以消除此问题。另一方面,我了解到
    长双精度
    类型与
    -mfpmath=sse
    是相互排斥的,因为在sse中没有“扩展精度”这样的东西<另一方面,code>\uuu float128应该可以很好地与SSE math配合使用(尽管在没有四精度指令的情况下,肯定不会以1:1指令为基础)。我的这些假设正确吗 (3.和4.可能可以通过一些分析和分解工作来解决,但可能其他人以前也有同样的想法,并且已经完成了这项工作。)

    太长了,读不下去了(背景是TL,DR部分):>BR> 起初,我无意中发现了长双精度,因为我在
    中查找
    DBL\u MAX
    ,顺便说一下
    LDBL\u MAX
    在下一行。“哦,看,GCC实际上有128位的双倍,不是我需要它们,而是…酷”是我的第一个想法。惊喜,惊喜:
    sizeof(长双精度)
    返回12。。。等等,你是说16岁

    <> P. C和C++标准并不意外地给出了一个非常具体的定义。C99(6.2.5 10)说
    double
    的数字是
    long double
    的一个子集,而C++03(3.9.1 8)说
    long double
    至少具有与
    double
    相同的精度(这是同样的事情,只是措辞不同)。基本上,这些标准将一切都留给实现,方式与
    long
    int
    short
    相同

    维基百科说,GCC“在x86处理器上使用80位扩展精度,而不管使用的是什么物理存储”

    GCC文档在同一页上声明,由于i386 ABI,类型的大小为96位,但任何选项都不能启用超过80位的精度(嗯?什么?),奔腾和更新的处理器也希望将其对齐为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;
    }
    
    这表明它不是一个80位的数字。80位数字有18个十六进制数字。我看到22个十六进制数字在变化,看起来更像96位数字(24个十六进制数字)。它也不是128位数字,因为未触及
    0xdeadbeef
    ,这与
    sizeof
    返回12一致

    \uuu int128
    的输出看起来实际上只是一个128位的数字。所有的比特最终都会翻转

    如文档所示,使用
    -m128位长双精度
    编译时,不会将
    长双精度
    与32位零填充对齐到128位。它也不使用
    \uuu int128
    ,但实际上似乎与128位对齐,用值
    0x7ffdd000
    (?!)填充

    此外,
    LDBL\u MAX
    似乎可以作为
    +inf
    用于
    长双精度
    \u浮点128
    。将像
    1.0E100
    1.0E2000
    这样的数字与
    LDBL_MAX
    相加或相减会产生相同的位模式。
    到目前为止,我认为
    foo_MAX
    常量包含的最大可表示数字不是
    +inf
    (显然不是这样的?)。我也不太清楚,对于128位的值,80位的数字如何可以想象为
    +inf
    。。。也许一天结束时我太累了,做了些错事。

    广告1

    这些类型设计用于处理具有巨大动态范围的数字。长双精度在x87 FPU中以本机方式实现。我怀疑在现代x86上,128b double将以软件模式实现,因为没有硬件在硬件中进行计算

    有趣的是,在一行中执行许多浮点运算是很常见的,中间结果实际上并不存储在声明的变量中,而是存储在FPU寄存器中,充分利用了全精度。这就是为什么比较:

    double x = sin(0); if (x == sin(0)) printf("Equal!");
    
    不安全,无法保证工作(无额外开关)

    公元3年

    速度会受到影响,具体取决于您使用的精度。Y
    double x = sin(0); if (x == sin(0)) printf("Equal!");
    
    void 
    set_fpu (unsigned int mode)
    {
      asm ("fldcw %0" : : "m" (*&mode));
    }