Code Generation with some unnecessary code

6 ビュー (過去 30 日間)
tao shuxin
tao shuxin 2021 年 12 月 13 日
回答済み: Abhishek Kumar Singh 2024 年 4 月 9 日 12:17
For example, I try to generate C code of a ADD function:
function y = ADD(u1, u2)
u1 = fi(u1,1,32,10);
u2 = fi(u2,1,32,20);
y = fi(u1+u2,1,32,10);
The "fimath" settings are as follows : the OverflowAction is set to Wrap,and the SumMode is set to KeepMSB
ans =
RoundingMethod: Floor
OverflowAction: Wrap
ProductMode: FullPrecision
MaxProductWordLength: 128
SumMode: KeepMSB
SumWordLength: 32
CastBeforeSum: true
The C codes are as follows:
void V_ob_code_TEST(void)
{
/* Outport: '<Root>/t1' incorporates:
* Inport: '<Root>/Input'
* Inport: '<Root>/Input1'
* MATLAB Function: '<S1>/MATLAB Function'
*/
y = ((u1 >> 1) + (u2 >> 11)) << 1;
}
I hope the code to be changed like this :
y = u1 + (u2 >> 10);
How can I do?

回答 (1 件)

Abhishek Kumar Singh
Abhishek Kumar Singh 2024 年 4 月 9 日 12:17
Hi Tao,
I understand you want to know why there are 'uncessary' shifts involved in generated C code for addition MALTAB script. MATLAB's code generation is not that straight forward- It several important aspects of fixed-point computation, error handling, and precision management. I generated the code for the following MATLAB function which is quite similar to the one given in question:
function y = add4codegen(u1, u2) %#codegen
% Define fi objects with custom fimath properties
F = fimath('RoundingMethod', 'Floor', 'OverflowAction', 'Wrap', 'SumMode', 'KeepMSB', 'SumWordLength', 32, 'CastBeforeSum', true);
% Create fi objects for u1 and u2 with the defined fimath
u1 = fi(u1, 1, 32, 10, 'fimath', F);
u2 = fi(u2, 1, 32, 20, 'fimath', F);
y = fi(u1*u2, 1, 32, 10, 'fimath', F);
end
For this I get the following C code generated through MATLAB Coder for which I got the following primary function implementation
int32_T add4codegen(real_T u1, real_T u2)
{
real_T d;
real_T d1;
int32_T i;
int32_T i1;
/* Define fi objects with custom fimath properties */
/* Create fi objects for u1 and u2 with the defined fimath */
d = muDoubleScalarFloor(u1 * 1024.0);
if (muDoubleScalarIsNaN(d) || muDoubleScalarIsInf(d)) {
d = 0.0;
} else {
d = muDoubleScalarRem(d, 4.294967296E+9);
}
d1 = muDoubleScalarFloor(u2 * 1.048576E+6);
if (muDoubleScalarIsNaN(d1) || muDoubleScalarIsInf(d1)) {
d1 = 0.0;
} else {
d1 = muDoubleScalarRem(d1, 4.294967296E+9);
}
if (d < 0.0) {
i = -(int32_T)(uint32_T)-d;
} else {
i = (int32_T)(uint32_T)d;
}
if (d1 < 0.0) {
i1 = -(int32_T)(uint32_T)-d1;
} else {
i1 = (int32_T)(uint32_T)d1;
}
return ((i >> 1) + (i1 >> 11)) << 1;
}
The generated C code takes a detailed approach to handle the addition of two fixed-point numbers (u1 and u2) with different fractional lengths. Here are the key considerations:
The code scales u1 and u2 by their respective scaling factors (1024.0 for u1 and 1.048576E+6 for u2) to convert them from floating-point to fixed-point representation. This step ensures that the values are appropriately quantized to their fixed-point formats. Along with overflow management and sign handling and conversion, the shifting most probably occurs to adjust precision before addition.
The reason for right-shifting (i >> 1) and then left-shifting (i<< 1) around the addition operation, as well as adjusting i1 by right-shifting (i1 >> 11), is to manage the differing scales and ensure that the addition operation is performed at a common scale. This also implicitly handles the alignment of fractional bits when adding two fixed-point numbers with different precisions.
Finally this brings to the important question here: why not simply y = u1 + (u2 >> 10)?
It seems straightforward but overlooks several key aspects:
  1. Precision and Scale Management: Directly shifting u2 by 10 bits aligns the scales but does not consider the intermediate precision loss that might occur due to the shift. The generated code's approach of adjusting both operands around the addition operation allows for a more controlled management of precision and scale, especially important in fixed-point arithmetic where every bit shift can lead to loss of information.
  2. Overflow and Sign Handling: The straightforward approach does not address potential overflow or underflow issues, nor does it handle sign conversion explicitly, both of which are critical in fixed-point arithmetic.
Consider adding u1 = 0.5 and u2 = 1024.5: With u1 scaled by 1024.0 and u2 scaled by 1.048576E+6 (due to the 20 fractional bits), the direct addition without careful scaling and precision management could lead to incorrect results. Simply shifting u2 right by 10 bits (u2 >> 10) and adding it to u1 would not properly account for the precision and scale differences, potentially leading to precision loss or incorrect alignment of the fractional parts.

製品

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by