所有人。
我的问题是是否有三个数组,如下所示
float a[7] = {1.0, 2.0, 3.0, 4.0,
5.0, 6.0, 7.0};
float b[7] = {2.0, 2.0, 2.0, 2.0,
2.0, 2.0, 2.0};
float c[7] = {0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0};我想按以下方式执行元素级的乘法操作
c[i] = a[i] * b[i], i = 0, 1, ..., 6对于前四个元素,我可以使用SSE本质,如下所示
__m128* sse_a = (__m128*) &a[0];
__m128* sse_b = (__m128*) &b[0];
__m128* sse_c = (__m128*) &c[0];
*sse_c = _mm_mul_ps(*sse_a, *sse_b);C中的内容将是
c[0] = 2.0, c[1] = 4.0, c[2] = 6.0, c[3] = 8.0
c[4] = 0.0, c[5] = 0.0, c[6] = 0.0在索引4、5和6中剩下的三个数字,我使用下面的代码来执行按元素进行的乘法操作。
sse_a = (__m128*) &a[4];
sse_b = (__m128*) &b[4];
sse_c = (__m128*) &c[4];
float mask[4] = {1.0, 1.0, 1.0, 0.0};
__m128* sse_mask = (__m128*) &mask[0];
*sse_c = _mm_add_ps( *sse_c,
_mm_mul_ps( _mm_mul_ps(*sse_a, *sse_b), *sse_mask ) );c4-6中的内容将是
c[4] = 10.0, c[5] = 12.0, c[6] = 14.0, which is the expected result._mm_add_ps()并行地添加四个浮点,在数组a、b和c中分别在索引4、5和6中分配第一、第二和第三个浮点数。但是第四个浮点数没有分配给数组。为了避免无效的内存访问,我在sse_mask上乘以使第四个数字为零,然后再将结果添加回sse_c (数组c)。
但我想知道这是否安全?
非常感谢。
发布于 2016-09-08 07:01:02
您的数学操作似乎是正确的,但我不确定像您所做的那样使用强制转换是在__m128 vars中加载和存储数据的方法。
装载和储存
若要将数据从数组加载到__m128变量,应使用__m128 _mm_load_ps (float const* mem_addr)或__m128 _mm_loadu_ps (float const* mem_addr)。很容易搞清楚这里是什么,但是有几个精确性:
load和loadu。第一个要求您的内存在一个16字节的边界上对齐,而u版本则没有这个要求。如果您不知道内存对齐,请使用u版本。load_ps和load_pd。不同之处是:s代表单精度,而d代表双精度(好的旧float)。当然,您只能在每个__m128变量中放置两个双倍,但是可以放置4个浮点数。所以从数组中加载数据非常容易,只需做:__m128* sse_a = _mm_loadu_ps(&a[0]);。对b做同样的操作,但是对于c,这确实取决于。如果你只想要乘法的结果,它是无用的初始化它在0,加载它,然后把乘法的结果到它,然后最后得到它回来。
您应该使用load的挂起操作来存储数据,即void _mm_storeu_ps (float* mem_addr, __m128 a)。因此,一旦复制完成并在sse_c中得到结果,只需执行_mm_storeu_ps(&c[0@, sse_c) ;
算法
使用掩码背后的想法是好的,但您有一些更简单的东西:从a[3]加载ans存储数据(b和c相同)。那样的话,它就会有4个元素,所以就没有必要使用任何掩码了?是的,有一个操作已经对第三个元素完成了,但这将是完全透明的:store操作将用新的值替换旧值。既然两者是平等的,那就不是问题了。
另一种方法是在数组中存储8个元素,即使只需要7个。这样,您就不必担心内存是否被分配了,不需要像上面这样的特殊逻辑来支付3个浮点数的成本,这在最近的所有计算机上都是没有的。
https://stackoverflow.com/questions/39384037
复制相似问题