fixed point to the power 0 changes word length

1 view (last 30 days)
I'm trying to implement the equivalent of C data types, e.g., int32_t, with MATLAB. As far as I know (suggestions welcome!), the right way to do this is to define my own my_int32 like so:
function y = my_int32(x)
%MY_UINT16 Summary of this function goes here
% Detailed explanation goes here
persistent T32 F32
T32 = numerictype('Signedness', 'Signed', ...
'WordLength', 32, ...
'FractionLength', 0);
F32 = fimath('RoundingMethod', 'Zero', ...
'OverflowAction', 'Wrap', ...
'ProductMode', 'KeepLSB', ...
'ProductWordLength', 32, ...
'ProductFractionLength', 0, ...
'SumMode', 'KeepLSB', ...
'SumWordLength', 32, ...
'SumFractionLength', 0, ...
'CastBeforeSum', true);
y = fi(x, T32, F32);
end
MATLAB's versions of int32 won't work for me because they don't have wrap-around overflow like they do in C. Now I get some odd behavior for 2^0:
>> my_int32(2)^1
ans =
2
DataTypeMode: Fixed-point: binary point scaling
Signedness: Signed
WordLength: 32
FractionLength: 0
RoundingMethod: Zero
OverflowAction: Wrap
ProductMode: KeepLSB
ProductWordLength: 32
SumMode: KeepLSB
SumWordLength: 32
CastBeforeSum: true
>> my_int32(2)^0
ans =
1
DataTypeMode: Fixed-point: binary point scaling
Signedness: Unsigned
WordLength: 1
FractionLength: 0
RoundingMethod: Zero
OverflowAction: Wrap
ProductMode: KeepLSB
ProductWordLength: 32
SumMode: KeepLSB
SumWordLength: 32
CastBeforeSum: true
For some reason, the word length of my_int32(2)^0 is not 32, but 1. I've tried things like my_int32(2)^my_int32(0) to no avail. Why is this and how can I fix it?

Answers (1)

MathWorks Fixed Point Team
Edited: MathWorks Fixed Point Team on 31 Aug 2020
fi's element-wise power a.^b
is not designed to give the same output data type for all possible values of b.
In general, the output data type can change for each value of b.
The implementation of fi's element-wise power special cases b == 0, and simply assigns the output to the optimal 1 bit representation of a.^0 = 1.
Your clever use of fimath appears to keep the output data type consistent for all positive values of b. But use of fimath on the input cannot impact the special case output assignment for b == 0.
I'm not aware of anyway to directly use fi's element-wise power operator to avoid the b == 0 special casing.
So you will not be able to fully control
y = a.^b
for all supported values of b.
If you are willing and able to replace the operator with a custom function,
y = some_custom_fi_power_function( a, b )
then it would be possible to achieve an output data type that does not change for all values of b.
If building off your use of fimath, the obvious solution is for the custom function to trap b == 0 and call a.^b for everything else.
Another approach to consider is the example shown here and attached.
The example is intended to illustrate some useful concepts such as employing the cast-like pattern. The example passed a very modest amount of spot testing. But "caveat emptor", this illustrative example has not gone through the rigorous testing process for simulation, code generation, etc.
function y = intPowerWrapLike( u, intPow, yLikeDesiredType) %#codegen
% intPowerWrapLike raise input element-wise to an integer power with a wrapping
% cast to a desired type at each step
%
% Usage:
% y = intPowerWrapLike(u,intPow,yLikeDesiredType)
% Input:
% u value to be raised to an integer power
% can be any integer or fi binary point type
% intPow the power to raise u to, must be non-negative, scalar, integer value
% yLikeDesiredType variable to whose type the output should be cast to
% with overflow wrapping and floor rounding
% DEFAULTs to u if yLikeDesiredType is not provided
%
% Example 1
% format compact
% a = int8([-10,2,9]);
% for b=0:3
% y1 = intPowerWrapLike( a, b )
% end
%
% Example 2
% format compact
% a = int8([-10,2,9]);
% yLike = int32(0);
% for b=0:3
% y2 = intPowerWrapLike( a, b, yLike )
% end
%
% Example 3
% format compact
% fp = fipref;
% fp.NumericTypeDisplay = 'short'
% a = fi([-3.375,-0.125,2.25,4],1,8,4);
% yLike = fi(0,1,12,6);
% for b=0:4
% y2 = intPowerWrapLike( a, b, yLike )
% end
% Copyright 2020 The MathWorks, Inc.
if nargin < 3
yLikeDesiredType = u;
end
validateattributes(u,{'embedded.fi','numeric'},{})
validateattributes(intPow,{'embedded.fi','numeric'},{'scalar','integer','nonnegative'})
validateattributes(yLikeDesiredType,{'embedded.fi','numeric'},{})
uFi = getLeanFiEquivalent(u);
intPowFi = valInIntType(intPow);
yLikeFi = getLeanFiEquivalent(yLikeDesiredType);
% For codegen, define the output type early
% The initialization value 1 will be the output if intPow == 0
%
yFi = ones(size(u),'like',yLikeFi);
if intPowFi > 0
one = cast(1,'like',intPowFi);
initialized = false;
runningInputPower = cast(uFi,'like',yLikeFi);
while intPowFi > 0
if bitand(intPowFi, one)
% Multiply in the odd power
if initialized
yFi(:) = mulLike(yFi,runningInputPower,yLikeFi);
else
yFi(:) = runningInputPower;
initialized = true;
end
end
% Divide k by 2 (shift off a bit at each iteration)
intPowFi = bitsrl(intPowFi,1);
if intPowFi ~= 0
% Squaring up the even powers
runningInputPower = mulLike(runningInputPower,runningInputPower,yLikeFi);
end
end
end
% Cast to the specified desired type.
% At most, this will change for fi type to it's
% MATLAB built-in integer equivalent
y = cast(yFi,'like',yLikeDesiredType);
end
function uFi = getLeanFiEquivalent(u)
%
% Get the fi equivalent of the input
% Give the output full precision fimath with lean math options
%
coder.inline('always');
uFi = castIntToFi(u);
assert(isfi(uFi));
assert(isfixed(uFi));
assert(uFi.isscalingbinarypoint);
fm = fimath('RoundingMethod', 'Floor', ...
'OverflowAction', 'Wrap');
uFi = setfimath(uFi,fm);
end
function y = valInIntType(u)
%
% Put value in an integer type, i.e. Fraction Length is zero
% removes unused fraction bits
% appends physical fraction bits if Fraction Length is negative
%
coder.inline('always');
u2 = castIntToFi(u);
if isfi(u2) && isfixed(u2) && u2.isscalingbinarypoint
u3 = u2;
else
u3 = fi(u2,0,32,0);
end
fmLean = fimath('RoundingMethod', 'Floor', ...
'OverflowAction', 'Wrap');
newWordLength = u3.WordLength + u3.FractionLength;
y = fi(u3, 0, newWordLength, 0, fmLean);
end
function y = mulLike(a,b,yLikeFi)
coder.inline('always');
a = removefimath(a);
b = removefimath(b);
if isreal(a) && isreal(b)
fm = fimath(...
'RoundingMethod', 'Floor', ...
'OverflowAction', 'Wrap', ...
'ProductMode', 'SpecifyPrecision', ...
'ProductWordLength', yLikeFi.WordLength, ...
'ProductFractionLength', yLikeFi.FractionLength, ...
'SumMode', 'SpecifyPrecision', ...
'SumWordLength', yLikeFi.WordLength, ...
'SumFractionLength', yLikeFi.FractionLength, ...
'CastBeforeSum', true);
y = mpy(fm,a,b);
else
tempFullPrecisionProduct = a .* b;
y = cast(tempFullPrecisionProduct,'like',yLikeFi);
end
y = removefimath(y);
fmLean = fimath('RoundingMethod', 'Floor', ...
'OverflowAction', 'Wrap');
y = setfimath(y,fmLean);
end

Products


Release

R2020a

Community Treasure Hunt

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

Start Hunting!