相关疑难解决方法(0)

融合乘法加法和默认舍入模式

使用GCC 5.3,以下代码符合 -O3 -fma

float mul_add(float a, float b, float c) {
  return a*b + c;
}
Run Code Online (Sandbox Code Playgroud)

生成以下程序集

vfmadd132ss     %xmm1, %xmm2, %xmm0
ret
Run Code Online (Sandbox Code Playgroud)

我注意到GCC -O3已经在GCC 4.8中这样做了.

Clang 3.7带-O3 -mfma产品

vmulss  %xmm1, %xmm0, %xmm0
vaddss  %xmm2, %xmm0, %xmm0
retq
Run Code Online (Sandbox Code Playgroud)

但Clang 3.7与-Ofast -mfmaGCC生成的代码相同-O3 fast.

我很惊讶GCC的确如此,-O3因为从这个答案来看

除非允许使用宽松的浮点模型,否则不允许编译器融合分离的加法和乘法.

这是因为FMA只有一个舍入,而ADD + MUL有两个舍入.因此,编译器将通过融合违反严格的IEEE浮点行为.

但是,从这个链接

无论FLT_EVAL_METHOD的值如何,任何浮点表达式都可以收缩,即,计算好像所有中间结果都具有无限范围和精度.

所以现在我感到困惑和担忧.

  1. GCC是否有理由使用FMA -O3
  2. 融合是否违反了严格的IEEE浮点行为?
  3. 如果融合确实违反了IEEE浮点运算,那么GCC的回归__STDC_IEC_559__不是一个矛盾吗?

由于FMA 可以在软件中进行仿真,因此似乎应该有两个用于FMA的编译器开关:一个用于告诉编译器在计算中使用FMA,一个用于告诉编译器硬件具有FMA.


显然,这可以通过选项进行控制-ffp-contract.对于GCC,默认是-ffp-contract=fast和Clang不一样.其他选项例如 …

c gcc clang ieee-754 fma

14
推荐指数
1
解决办法
1347
查看次数

优化快速乘法但缓慢添加:FMA和doubledouble

当我第一次使用Haswell处理器时,我尝试使用FMA来确定Mandelbrot集.主要算法是这样的:

intn = 0;
for(int32_t i=0; i<maxiter; i++) {
    floatn x2 = square(x), y2 = square(y); //square(x) = x*x
    floatn r2 = x2 + y2;
    booln mask = r2<cut; //booln is in the float domain non integer domain
    if(!horizontal_or(mask)) break; //_mm256_testz_pd(mask)
    n -= mask
    floatn t = x*y; mul2(t); //mul2(t): t*=2
    x = x2 - y2 + cx;
    y = t + cy;
}
Run Code Online (Sandbox Code Playgroud)

这确定n像素是否在Mandelbrot集中.因此对于双浮点,它运行超过4个像素(floatn = __m256d,intn = __m256i).这需要4个SIMD浮点乘法和4个SIMD浮点加法.

然后我修改了这个就像这样使用FMA

intn n = 0; …
Run Code Online (Sandbox Code Playgroud)

floating-point x86 assembly mandelbrot fma

9
推荐指数
1
解决办法
944
查看次数

我的fma()坏了吗?

在使用中,double fma(double x, double y, double z);我希望d下面标有的输出行中有一个非零值'?'.它似乎在内部只使用long double精度,而不是无限精度的规定.

fma函数计算(x× y)+ z,四舍五入一个三元操作:它们计算的值(仿佛)到无限精度和圆一次的结果的格式,根据当前的舍入模式.§7.12.13.12(我的重点)

那我的fma()坏了,或者我在代码或编译选项中如何错误地使用它?

#include <float.h>
#include <math.h>
#include <stdio.h>

int main(void) {
  // Invoking: Cygwin C Compiler
  // gcc -std=c11 -O0 -g3 -pedantic -Wall -Wextra -Wconversion -c -fmessage-length=0 
  //   -v -MMD -MP -MF"x.d" -MT"x.o" -o "x.o" "../x.c"

  printf("FLT_EVAL_METHOD %d\n", FLT_EVAL_METHOD);
  for (unsigned i = 20; i < 55; i++) …
Run Code Online (Sandbox Code Playgroud)

c floating-point gcc5

9
推荐指数
1
解决办法
330
查看次数

将双精度数舍入到以位数给出的较低精度的有效方法

在C#中,我希望将双精度舍入到较低的精度,以便我可以将它们存储在关联数组中的不同大小的存储桶中.与通常的舍入不同,我想要舍入到一些重要的位.因此,大数字的绝对值会比小数字更改,但它们往往会按比例改变.因此,如果我想要舍入到10个二进制数字,我会找到十个最高有效位,并将所有低位都清零,可能会添加一个小数字进行舍入.

我更喜欢将"中途"数字四舍五入.

如果它是整数类型,这里可能是一个算法:

  1. Find: zero-based index of the most significant binary digit set H.
  2. Compute: B = H - P, 
       where P is the number of significant digits of precision to round
       and B is the binary digit to start rounding, where B = 0 is the ones place, 
       B = 1 is the twos place, etc. 
  3. Add: x = x + 2^B 
       This will force a carry if necessary (we round halfway values up).
  4. Zero …
Run Code Online (Sandbox Code Playgroud)

c# floating-point rounding

6
推荐指数
1
解决办法
1935
查看次数

标签 统计

floating-point ×3

c ×2

fma ×2

assembly ×1

c# ×1

clang ×1

gcc ×1

gcc5 ×1

ieee-754 ×1

mandelbrot ×1

rounding ×1

x86 ×1