我的问题很简单:在c中规范化2d双数组的最有效方法是什么,以便它的列(或其行)总和为1.下面是一个简单的例子来说明我想要做什么。如果重要的话,可以重新整形数组以标准化其行或列。我也愿意使用外部c线性代数库。只是不知道从哪里开始。感谢您提前提供任何帮助!
void normalize(double** array, int nrow) {
int i;
double sum = 0;
for(i = 0; i < nrow; i++) {
sum += array[i][0];
}
for(i = 0; i < nrow; i++) {
array[i][0] /= sum;
}
}
顺便说一句,这是隐马尔可夫模型动态规划算法的一部分,并且它被多次调用。所以我想让这部分尽可能高效。
答案 0 :(得分:1)
我不知道您的示例代码与您的应用程序的匹配程度,但如果您循环遍历这样的行,您几乎肯定会遇到缓存问题。如果我以行主要和列主要顺序对循环进行编码,我会发现性能差异很大。
使用nrow=1000000
和ncol=1000
,如果我使用array[i][0]
,我的运行时间大约为1.9秒。如果我使用array[0][i]
,则会降至0.05秒。
如果您可以通过这种方式转置数据,那么您应该会看到很大的性能提升。
#ifdef COL_MAJOR
array = (double **)malloc(nrow * sizeof(double *));
for(i=0; i<nrow; i++) {
array[i] = (double *)malloc(ncol * sizeof(double));
array[i][0] = i;
}
for(i=0; i<nrow; i++) {
sum += array[i][0];
}
for(i=0; i<nrow; i++) {
array[i][0] /= sum;
}
#else
array = (double **)malloc(ncol * sizeof(double *));
for(i=0; i<ncol; i++) {
array[i] = (double *)malloc(nrow * sizeof(double));
}
for(i=0; i<nrow; i++) {
array[0][i] = i;
}
for(i=0; i<nrow; i++) {
sum += array[0][i];
}
for(i=0; i<nrow; i++) {
array[0][i] /= sum;
}
#endif
printf("%f\n", sum);
$ gcc -DCOL_MAJOR -O2 -o normed normed.c $ time ./normed 499999500000.000000 real 0m1.904s user 0m0.325s sys 0m1.575s $ time ./normed 499999500000.000000 real 0m1.874s user 0m0.304s sys 0m1.567s $ time ./normed 499999500000.000000 real 0m1.873s user 0m0.296s sys 0m1.573s $ gcc -O2 -o normed normed.c $ time ./normed 499999500000.000000 real 0m0.051s user 0m0.017s sys 0m0.024s $ time ./normed 499999500000.000000 real 0m0.050s user 0m0.017s sys 0m0.023s $ time ./normed 499999500000.000000 real 0m0.051s user 0m0.014s sys 0m0.022s $