繁体   English   中英

用于增强中间浮点计算精度的编译器标志

[英]Compiler flags for enhancing the precision of intermediate floating-point calculation

gcc / clang中是否有一个标志指定中间浮点计算的精度?

假设我有一个C代码

double x = 3.1415926;
double y = 1.414;
double z = x * y;

是否有编译器标志允许以用户机器的最高精度计算'x * y',例如,long-double(64位尾数),然后截断为double(53位尾数,声明变量类型的精度)?

仅供参考,我在64位计算机上使用Ubuntu 14.04。

GCC

[编辑gcc 4.8.4的观察行为,其中默认行为与文档相反]

您需要使用x87 FPU中的80位寄存器。 使用-mfpmath=387您可以覆盖SSE寄存器XMM0-XMM7的默认使用。 此默认值实际上为您提供了IEEE行为,其中每个步骤都使用64位寄存器。

请参阅: https//gcc.gnu.org/wiki/x87note

因此,默认情况下,x87算术不是64/32位IEEE,而是从x87单元获得扩展精度。 但是,只要将值从寄存器移到IEEE 64或32位存储单元,就必须将该80位值向下舍入到适当的位数。

但是,如果您的操作非常复杂,可能会发生寄存器溢出; FP寄存器堆栈只有深度8.因此,当溢出复制到字大小的RAM位置时,您将获得舍入。 您需要在这种情况下自己声明long double并在末尾手动舍入,或者检查汇编器输出是否显式溢出。

有关寄存器的更多信息,请访问: https//software.intel.com/en-us/articles/introduction-to-x64-assembly

特别是,XMM0 ... 7寄存器虽然128位宽,但只能容纳两个同时进行的64位FP操作。 因此,您希望通过FLD(加载),FMUL(乘法)和FSTP(存储和弹出)指令查看堆栈操作的FPR寄存器。

所以我编译了这段代码:

double mult(double x, double y) {
    return x * y;
}

有:

gcc -mfpmath=387 -Ofast -o precision.s -S precision.c

得到了:

mult:
  .LFB24:
    .cfi_startproc
    movsd   %xmm1, -8(%rsp)
    fldl    -8(%rsp)
    movsd   %xmm0, -8(%rsp)
    fldl    -8(%rsp)
    fmulp   %st, %st(1)
    fstpl   -8(%rsp)
    movsd   -8(%rsp), %xmm0
    ret
    .cfi_endproc

现在一切都很完美。 浮点值通过寄存器XMM0和XMM1传递(尽管它们必须通过内存进行奇怪的往返才能将它们放到FPR堆栈上),并根据上面的Intel参考在XMM0中返回结果。 不确定为什么没有直接来自XMM0 / 1的简单FLD指令,但显然指令集不这样做。

如果与-mfpmath=sse进行比较,则在后一种情况下要做的事情要少得多,因为操作数已准备好并在XMM0 / 1寄存器中等待,并且它就像单个MULSD指令一样简单。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM