我正在对以前从文件中读取的矩阵执行模板计算。 我使用两种不同的矩阵(NonZero类型和Zero类型)。 两种类型共享边界的值(通常为1000),而其余元素对于零类型为0,对于NonZero类型为1。
该代码将文件的矩阵存储在两个相同大小的分配矩阵中。 然后,它使用自己的值和邻居值(添加x 4和mul x 1)在一个矩阵的每个元素中执行操作,并将结果存储在第二个矩阵中。 一旦计算完成,交换矩阵的指针并且执行相同的操作有限次数。 在这里你有核心代码:
#define GET(I,J) rMat[(I)*cols + (J)] #define PUT(I,J) wMat[(I)*cols + (J)] for (cur_time=0; cur_time<timeSteps; cur_time++) { for (i=1; i<rows-1; i++) { for (j=1; j<cols-1; j++) { PUT(i,j) = 0.2f*(GET(i-1,j) + GET(i,j-1) + GET(i,j) + GET(i,j+1) + GET(i+1,j)); } } // Change pointers for next iteration auxP = wMat; wMat = rMat; rMat = auxP; }
我暴露的情况使用固定量的500个timeSteps(外部迭代)和8192行和8192列的矩阵大小,但是在更改timeSteps或矩阵大小的数量时问题仍然存在。 请注意,我只测量算法的这个具体部分的时间,因此从文件读取矩阵或其他任何因素都会影响时间度量。
它发生的是,我根据我使用的矩阵类型得到不同的时间,在使用Zero类型时获得更差的性能(每个其他矩阵执行与NonZero类型相同,因为我已经尝试生成一个充满随机的矩阵值)。
我确信它是乘法运算,就像我删除它并只留下添加,它们执行相同的操作。 注意,对于零矩阵类型,大多数类型的和的结果将为0,因此操作将为“0.2 * 0”。
这种行为对我来说当然很奇怪,因为我认为浮点运算独立于操作数的值,这看起来不像这里的情况。 我也尝试捕获并显示SIGFPEexception以防出现问题,但我没有得到任何结果。
如果有帮助,我使用的是Intel Nehalem处理器和gcc 4.4.3。
这个问题已经被大部分诊断出来了,但我会准确地写下这里发生的事情。
从本质上讲,提问者是模拟扩散; 边界上的初始量扩散到整个大网格中。 在每个时间步t,扩散前沿的值将为0.2 ^ t(忽略角落处的效应)。
最小的归一化单精度值为2 ^ -126; 当cur_time = 55
,扩散前沿的值为0.2 ^ 55,略小于2 ^ -127。 从此时开始,网格中的一些单元格将包含非正规值。 在提问者的Nehalem上,非正规数据的操作比标准化浮点数据上的相同操作慢约100倍,这解释了减速。
当网格最初填充1.0
常量数据时,数据永远不会变得太小,因此避免了非正规停顿。
请注意,将数据类型更改为double
会延迟,但不会缓解此问题。 如果计算使用双精度,则在第441次迭代中将首先出现非正规值(现在小于2 ^ -1022)。
以扩散前沿的精度为代价,您可以通过启用“Flush to Zero”来解决减速问题,这会导致处理器在算术运算中产生零而不是非正规结果。 这可以通过在FPSCR或MXSCR中切换一个位来完成,最好是通过C库中
头中定义的函数。
另一个(hackier,不太好)“修复”将最初用非常小的非零值( 0x1.0p-126f
,最小的正常数)填充矩阵。 这也可以防止在计算中出现非正规。
也许你的ZeroMatrix使用稀疏矩阵的典型存储方案:将每个非零值存储在链表中。 如果是这种情况,那么为什么它比典型的基于arrays的存储方案表现更差是完全可以理解的:因为它需要为你执行的每个操作运行一次链表。 在这种情况下,您可以通过使用矩阵乘法算法来加快处理速度,该算法考虑具有稀疏矩阵。 如果不是这种情况,请发布最小但完整的代码,以便我们可以使用它。
这是有效地乘以稀疏矩阵的可能性之一:
需要了解更多c/c++开发分享浮点乘法执行速度较慢,具体取决于C中的操作数,也可以关注C/ C++技术分享栏目—计算机技术网(www.ctvol.com)!
以上就是c/c++开发分享浮点乘法执行速度较慢,具体取决于C中的操作数相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/979671.html