使用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)
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的值如何,任何浮点表达式都可以收缩,即,计算好像所有中间结果都具有无限范围和精度.
所以现在我感到困惑和担忧.
-O3?__STDC_IEC_559__不是一个矛盾吗?由于FMA 可以在软件中进行仿真,因此似乎应该有两个用于FMA的编译器开关:一个用于告诉编译器在计算中使用FMA,一个用于告诉编译器硬件具有FMA.
显然,这可以通过选项进行控制-ffp-contract.对于GCC,默认是-ffp-contract=fast和Clang不一样.其他选项例如 …
当我第一次使用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) 在使用中,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#中,我希望将双精度舍入到较低的精度,以便我可以将它们存储在关联数组中的不同大小的存储桶中.与通常的舍入不同,我想要舍入到一些重要的位.因此,大数字的绝对值会比小数字更改,但它们往往会按比例改变.因此,如果我想要舍入到10个二进制数字,我会找到十个最高有效位,并将所有低位都清零,可能会添加一个小数字进行舍入.
我更喜欢将"中途"数字四舍五入.
如果它是整数类型,这里可能是一个算法:
Run Code Online (Sandbox Code Playgroud)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 …