[英]Most efficient way to calculate the exponential of each element of a matrix
我正在从Matlab迁移到C + GSL,我想知道什么是计算矩阵B的最有效方法:
B[i][j] = exp(A[i][j])
其中i在[0,Ny]中,j在[0,Nx]中。
请注意,这与矩阵指数不同:
B = exp(A)
这可以通过GSL(linalg.h)中的一些不稳定/不支持的代码来完成。
我刚刚找到了强力解决方案(几个'for'循环),但有没有更明智的方法呢?
编辑
所有结果都来自1024x1024 for(for)
循环,其中在每次迭代中分配两个double
值(复数)。 时间是超过100次执行的平均时间 。
gsl_matrix_complex_set
函数时的224.60 ms(案例3)。 案例1的源代码 :
for(i=0; i<Nx; i++)
{
for(j=0; j<Ny; j++)
{
/* Operations to obtain c_value (including exponentiation) */
matrix[2*(i*s_tda + j)] = GSL_REAL(c_value);
matrix[2*(i*s_tda + j)+1] = GSL_IMAG(c_value);
}
}
案例2的源代码 :
for(i=0; i<Nx; i++)
{
for(j=0; j<Ny; j++)
{
/* Operations to obtain c_value (including exponentiation) */
matrix->data[2*(j*s_tda + i)] = GSL_REAL(c_value);
matrix->data[2*(j*s_tda + i)+1] = GSL_IMAG(c_value);
}
}
案例3的源代码 :
for(i=0; i<Nx; i++)
{
for(j=0; j<Ny; j++)
{
/* Operations to obtain c_value (including exponentiation) */
gsl_matrix_complex_set(matrix, i, j, c_value);
}
}
没有办法避免遍历所有元素并在每个元素上调用exp()
或等效元素。 但是有更快更慢的迭代方式。
特别是,您的目标应该是最大限度地减少缓存未命中。 找出你的数据是以行主要顺序还是按列主顺序存储,并确保循环使得内部循环迭代在内存中连续存储的元素,并且外部循环将大步向下一行( if row major)或column(如果是major major)。 虽然这看起来微不足道,但它可以在性能上产生巨大的差异(取决于矩阵的大小)。
处理完缓存后,您的下一个目标是消除循环开销。 第一步(如果您的矩阵API支持它)是从嵌套循环(M&N边界)到迭代基础数据(M N界限)的单个循环。 你需要得到一个指向底层内存块的原始指针(即双倍而不是双倍**)才能做到这一点。
最后,抛出一些循环展开(也就是说,为循环的每次迭代做8或16个元素)以进一步减少循环开销,这可能就像你可以做到的那样快。 你可能需要一个带有fall-through的最终switch语句来清理其余的元素(当你的数组大小为%block size!= 0时)。
不,除非有一些我没有听说过的奇怪的数学怪癖,你几乎只需要用两个for循环遍历元素。
由于未显示循环的内容,计算c_value的位我们不知道代码的性能是受内存带宽限制还是受CPU限制。 确切知道的唯一方法是使用分析器,并使用复杂的分析器。 它需要能够测量内存延迟,即CPU等待数据从RAM到达的空闲时间。
如果您受内存带宽的限制,那么一旦您按顺序访问内存,就无法做很多事情。 顺序获取数据时,CPU和内存最有效。 随机访问达到了吞吐量,因为数据更有可能必须从RAM中提取到缓存中。 你总是可以尝试获得更快的RAM。
如果您受到CPU的限制,那么您可以使用更多选项。 使用SIMD是一种选择,手动编码浮点代码(由于许多原因,C / C ++编译器在FPU代码上不是很好)。 如果这是我,并且内循环中的代码允许它,我将有两个指向数组的指针,一个在开始时,另一个在第4个/ 5个中。 在每次迭代中,将使用第一指针和使用第二指针的标量FPU操作来执行SIMD操作,使得循环的每次迭代执行五个值。 然后,我将SIMD指令与FPU指令交错,以降低延迟成本。 这不应该影响您的缓存,因为(至少在Pentium上)MMU可以同时流式传输多达四个数据流(即为您预取数据而无需任何提示或特殊指令)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.