简体   繁体   中英

C and Matlab: Why does this one line in Matlab become so many lines in C++ code generated by Matlab Coder?

I have some Matlab code that is run many millions of times as mentioned in this question: Matlab: Does calling the same mex function repeatedly from a loop incur too much overhead?

I'm trying to mex-ify it to see whether that helps. Now, when I generate code from the Matlab code using Matlab Coder tool, the code is generally reasonable, but this one line of Matlab code (in a C++ comment in the first line below) begets this monstrosity, and I have no idea why. Any help in understanding and reducing its complexity would be appreciated.

For context, d is a two dimensional matrix, and s1 is a row vector. s1_idx is assigned to be length(s1) + 1 in preceding C++ code,

/* 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];
}

That's pretty funny generated code for what you actually want to accomplish. You just want to stuff the integers 0 to k into an array. But the code generator is built to deal with the general case. So there are three parts to the generated code:

  1. Create an array of indices specifying where, on the left-hand side, the elements from the right-hand side will go. You used the : expression, but you could have used something else. The code generator has to be prepared for you doing something like d(length(s1):0, 1)=0:length(s1) .
  2. Create an array of values for the right-hand side. Your just doing sequential integers, but the code generator is prepared to deal with doubles and when creating values from a range of doubles you might have funny rounding issues. It's checking for all kinds of edge cases.
  3. Finally, there's the loop that actually assigns the values on the right-hand side to memory slots on the left-hand side as indexed by the array created in step 1.

In the end, it might be that all you need is:

cdiff = s1_idx_0 - 1;
for (nm1d2 = 0; nm1d2 <= cdiff; nm1d2++) {
   SD->f0.d_data[nm1d2] = nm1d2;
}

MatLab is a special case, designed to work with special math functions. You do realize that under the hood stuff is still being translated to lots of machine code which processor can understand.

There are a lot of questions on SO that ask the same thing: "why is XX so easy to do in Matlab and so hard in C++?". Because Matlab was designed for this while C++ is a general-purpose language.

Matlab developers had to write those big code sheets to provide you a way to use this functionality with just one line. C++ doesn't have it in the standard library, thus you will need to make it yourself.

Well, take a simple example. Assume users A and B want to solve a quadratic equasion. User A is using a mathematical package, and all he has to do is write

FIND x IN 2x 2 + 6x + 3 = 0

User B, on the other hand, is using C++, and he has to write a function to count the discriminant, compute the values (he'll have to worry about negative discriminant too of course) and output them, something that the developers of the mathematical package had already done for user A. That is a lot of code really, here's an example that I quickly googled.

Now imagine user A saying "Hey, B, why the hell do you need to write so much code? I can do it in just 1 line!" and this will be your case ;)

Also don't forget that automatically-generated code is not always the best code ever if you talk about readability and ease of understanding by human.

I'm late to this party, but the existing answers focus on why it happened and don't discuss what you can do about it.

If you know which line causes that strange, messy looking C code, you should try changing that line. Instead of:

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

One thing to try is removing the dependency on variable s1 :

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

Another option is to write a simple loop that can be almost directly translated to C. Hopefully codegen will give very similar and simple C code.

for i = 0:size(d,1)
    d(i,1) = i;
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM