7

我有一些运行数百万次的 Matlab 代码,如以下问题所述:Matlab:从循环中重复调用相同的 mex 函数会产生太多开销吗?

我正在尝试对其进行混合以查看是否有帮助。现在,当我使用 Matlab Coder 工具从 Matlab 代码生成代码时,代码通常是合理的,但是这一行 Matlab 代码(在下面第一行的 C++ 注释中)引发了这种怪物,我不知道为什么。任何有助于理解和降低其复杂性的帮助将不胜感激。

对于上下文,d 是二维矩阵,s1 是行向量。s1_idx 在前面的 C++ 代码中被赋值为 length(s1) + 1,

/* d(:, 1) = 0:length(s1); */
cdiff = s1_idx_0 - 1;
for (nm1d2 = 0; nm1d2 <= cdiff; nm1d2++) {
   tmp_data[nm1d2] = nm1d2;
}
ndbl = (int32_T)muDoubleScalarFloor((real_T)s1_sizes[1] + 0.5);
apnd = ndbl;
cdiff = ndbl - s1_sizes[1];
if (muDoubleScalarAbs((real_T)cdiff) < 4.4408920985006262E-16 * (real_T)s1_sizes[1]) {
   ndbl++;
   apnd = s1_sizes[1];
} else if (cdiff > 0) {
   apnd = ndbl - 1;
} else {
   ndbl++;
}
if (ndbl > 0) {
   b_tmp_data[0] = 0.0;
   if (ndbl > 1) {
       b_tmp_data[ndbl - 1] = (real_T)apnd;
       nm1 = ndbl - 1;
       nm1d2 = nm1;
       nm1d2 = (int32_T)((uint32_T)nm1d2 >> 1);
       for (cdiff = 1; cdiff <= nm1d2 - 1; cdiff++) {
           b_tmp_data[cdiff] = (real_T)cdiff;
           b_tmp_data[(ndbl - cdiff) - 1] = (real_T)(apnd - cdiff);
       }
       if (nm1d2 << 1 == nm1) {
           b_tmp_data[nm1d2] = (real_T)apnd / 2.0;
       } else {
           b_tmp_data[nm1d2] = (real_T)nm1d2;
           b_tmp_data[nm1d2 + 1] = (real_T)(apnd - nm1d2);
       }
   }
}
cdiff = s1_idx_0 - 1;
for (nm1d2 = 0; nm1d2 <= cdiff; nm1d2++) {
   SD->f0.d_data[tmp_data[nm1d2]] = b_tmp_data[nm1d2];
}
4

3 回答 3

4

对于您真正想要完成的事情,这是非常有趣的生成代码。您只想将整数 0 到 k 填充到数组中。但是代码生成器是为处理一般情况而构建的。所以生成的代码分为三个部分:

  1. 创建一个索引数组,指定左侧的元素在左侧的位置。你使用了这个:表达式,但你可以使用别的东西。代码生成器必须为你做类似的事情做好准备d(length(s1):0, 1)=0:length(s1)
  2. 为右侧创建一个值数组。您只是在做连续整数,但代码生成器已准备好处理双精度数,并且在从一系列双精度数创建值时,您可能会遇到有趣的舍入问题。它正在检查各种边缘情况。
  3. 最后,有一个循环将右侧的值实际分配给左侧的内存槽,由步骤 1 中创建的数组索引。

最后,您可能只需要:

cdiff = s1_idx_0 - 1;
for (nm1d2 = 0; nm1d2 <= cdiff; nm1d2++) {
   SD->f0.d_data[nm1d2] = nm1d2;
}
于 2012-10-18T15:01:14.220 回答
2

MatLab 是一种特殊情况,旨在使用特殊的数学函数。你确实意识到,在幕后东西仍然被翻译成处理器可以理解的大量机器代码。

有很多关于 SO 的问题都在问同样的问题:“为什么 XX 在 Matlab 中这么容易,而在 C++ 中这么难?”。因为 Matlab 就是为此而设计的,而 C++ 是一种通用语言。

Matlab 开发人员必须编写那些大代码表,以便为您提供一种仅用一行代码就可以使用此功能的方法。C++ 标准库中没有它,因此您需要自己制作。

好吧,举个简单的例子。假设用户 A 和 B 想要求解一个二次方程。用户 A 正在使用数学包,他所要做的就是写

查找 x 输入 2x 2 + 6x + 3 = 0

另一方面,用户 B 正在使用 C++,他必须编写一个函数来计算判别式、计算值(当然他也必须担心负判别式)并输出它们,这是开发人员数学包已经为用户 A 完成了。这确实是很多代码,这是我快速搜索的一个示例。

现在想象用户 A 说“嘿,B,你为什么要写这么多代码?我可以在 1 行中完成!” 这将是你的情况;)

另外不要忘记,如果您谈论可读性和人类易于理解,自动生成的代码并不总是最好的代码。

于 2012-10-18T12:22:15.173 回答
1

我参加这个聚会迟到了,但现有的答案集中在它发生的原因上,而不是讨论你能做些什么。

如果您知道哪一行导致出现奇怪、混乱的 C 代码,您应该尝试更改该行。代替:

d(:, 1) = 0:length(s1);

要尝试的一件事是消除对变量的依赖s1

d(:, 1) = 0:size(d,1);

另一种选择是编写一个几乎可以直接翻译成 C 的简单循环。希望 codegen 能提供非常相似和简单的 C 代码。

for i = 0:size(d,1)
    d(i,1) = i;
end
于 2013-09-03T18:05:07.560 回答