【问题标题】:C and Matlab: Why does this one line in Matlab become so many lines in C++ code generated by Matlab Coder?C 和 Matlab:为什么 Matlab 中的这一行代码在 Matlab Coder 生成的 C++ 代码中会变成这么多行?
【发布时间】:2012-10-08 21:25:11
【问题描述】:

我有一些运行数百万次的 Matlab 代码,正如这个问题中提到的:Matlab: Does calling the same mex function repeatedly from a loop incur too much overhead?

我正在尝试对其进行混合,看看是否有帮助。现在,当我使用 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];
}

【问题讨论】:

  • 为什么不自己在mex文件中实现呢?这似乎是一个相当简单的功能。在我看来,MATLAB 显式地生成了索引 d(:,1)1:length(s1) 向量,以便在最后一个循环 SD-&gt;f0.d_data=... 中使用它们。如果您计算的是第一个注释行,则可以将所有内容写在一个循环中。
  • 我喜欢直接在 C++ 中完成,而不是信任自动生成的代码,但我这样做是为了一个只知道 Matlab 并希望以后能够自己维护代码的客户on,在我们的合同结束后。因此需要依赖 Matlab Coder。

标签: c++ c matlab code-generation


【解决方案1】:

对于您真正想要完成的事情,这是非常有趣的生成代码。您只想将整数 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;
}

【讨论】:

  • 您的解释帮助我更轻松地完成了代码,我现在明白发生了什么。谢谢!
【解决方案2】:

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

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

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

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

找到 x IN 2x2 + 6x + 3 = 0

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

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

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

【讨论】:

  • 虽然这适用于任意 Matlab 语句和相应的 C++ 版本,但在这种特殊情况下,它只是一个数组赋值,并且可以很容易地用更少的 C++ 行来完成,正如@JCooper 的回答所描述的那样.
【解决方案3】:

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

如果您知道哪一行导致出现奇怪、混乱的 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

【讨论】:

    猜你喜欢
    • 2018-06-01
    • 2011-09-17
    • 2016-11-13
    • 2014-06-09
    • 2017-07-06
    • 2017-05-11
    • 2018-11-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多