【发布时间】:2010-07-23 21:31:42
【问题描述】:
我正在从 Matlab 迁移到 C + GSL,我想知道计算矩阵 B 的最有效方法是什么:
B[i][j] = exp(A[i][j])
其中 i 在 [0, Ny] 中,j 在 [0, Nx] 中。
请注意,这与矩阵指数不同:
B = exp(A)
这可以通过 GSL (linalg.h) 中的一些不稳定/不受支持的代码来实现。
我刚刚找到了蛮力解决方案(几个“for”循环),但是有什么更聪明的方法吗?
编辑
Drew Hall 的解答帖结果
所有结果都来自一个 1024x1024 for(for) 循环,其中在每次迭代中分配了两个 double 值(一个复数)。 时间是 100 次执行的平均时间。
- 考虑到存储矩阵的 {Row,Column}-Major 模式时的结果:
- 在 Row-Major 模式下循环内循环中的行时为 226.56 毫秒(案例 1)。
- 在 Row-Major 模式下在内循环中循环列时为 223.22 毫秒(案例 2)。
- 使用 GSL 提供的
gsl_matrix_complex_set函数时为 224.60 毫秒(案例 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);
}
}
【问题讨论】:
-
我认为您只是认为它效率低下/愚蠢,因为您已经习惯了 MATLAB,其中使用嵌套 fors 是灾难的根源。但是 MATLAB 会在幕后做到这一点,只是如果你把它写出来,那就糟透了。但是 C 不是那样工作的,你总是把它写出来,它会和 MATLAB 一样快/快...
-
嗯...这些性能数据无法区分。我很惊讶——我们能看到你在每种情况下运行的代码吗?我想知道您的编译器是否注意到这些值是独立的并自动重新排序和展开循环以最大化性能。在每种情况下查看生成的程序集都会告诉我们这一点。
-
在每种情况下,您都在赋值的 RHS 上使用了一个常量值(exp() 发生了什么?)——我怀疑编译器已将其提升到循环之外并替换了循环使用某种类似 memset() 的操作。尝试根据数据进行分配——即使只是像 matrix[2*(is_tda + j)] = sin(matrix[2*(is_tda + j)]) 之类的东西也可能击败优化并显示缓存效果。
-
@Drew:
c_value不是一个常数。我只是缩短了代码以避免它太长。我使用的实际代码托管在signal.c第45行附近的项目gico-lib(有点混乱)的google代码中。我将尝试使用该技巧伪造编译器(达尔文的 gcc 4.2.1 (MacOsX))并稍后发布结果。 -
涉及到矩阵元素的赋值(A[i] = exp(A[i]) 等价)情况1和2的差别差不多,大约5毫秒。
标签: c performance matrix exponential