MATLAB - integers vs decimals assignment strange bug - matlab

newT = [b(i) d(i) a(i) z(i)];
newT, b(i), a(i)
Prints
newT =
123 364 123 902
ans =
1.234e+02
ans =
1.234e+02
What is the problem here? Why are the first and third entry in newT rounded to integer values? Why aren't they correctly assigned?

Unlike most other programming languages, integer types in Matlab take precedence over floating point types. When you combine them, either through concatenation or arithmetic, the floating point values are implicitly narrowed to integers, instead of the integers being widened to floating point.
>> int32(3) + 0.4
ans =
3
>> [int32(3) 0.4]
ans =
3 0
This is for historical reasons, because (IIRC) Matlab originally didn't have support for integers at all, so all numeric constants in Matlab produce double values, and the promotion rules were created to make it possible to mix integer types with floating-point constants.
To fix this, explicitly convert those int types to doubles before concatenating.
newT = [b(i) double(d(i)) a(i) double(z(i))];

Related

Can I represent a rational symbolic value like a decimal approximation?

For example, I have the symbolic value which is 's+5/2'. Is there a way to display it like 's+2.5'?
Yes, use vpa. Simply take your symbolic expression and use the vpa function to facilitate the conversion. vpa evaluates each term in the symbolic expression and converts each value to using up to 32 significant digits whenever possible. You can also override the amount of significant digits with the second parameter to vpa, but that's not needed in your case.
Here's a quick example:
>> syms s
>> A = s + 5/2
A =
s + 5/2
>> vpa(A)
ans =
s + 2.5
You can also set the initial approximation mode of the numeric literal to decimal mode, where the precision is dictated by digits, using the 'd' flag of the sym function:
>> expr = sym('s') + sym(5/2,'d')
expr =
s + 2.5

Is 1 + 1 == 2 always true in Matlab?

As this example suggests:
0.1 + 0.1 + 0.1 == 0.3
gives the surprising result of false due to precision issues when storing 0.1.
However,
1 + 1 + 1 == 3
evaluates to true as expected. Note that there is still the issue of comparison of floating numbers here. As pointed out in the comments, the default numeric data type is double unless specified otherwise.
My question is, if a + b + c + ...= T, and a, b, c, ... , T are all integers, is the evaluated value of
a + b + c + ... == T
always true?
What other ways are there to relax the condition of a, b, c, ... , T being integers and still maintain the truth of the above statement?
As helpfully pointed out in one answer, any sort of overflow encountered at any point of the evaluation will cause this to evaluate to false:
A = realmax('double')
A - A + A == A % evaluates to true
A + A - A == A % evaluates to false
Thus, for the purposes of my original question, assume that no overflow problems at encountered at any stage necessary to evaluate the expression.
If integers are represented using fixed-sized data types, then there is a limit to how large (in magnitude) a number can be represented. Thus, if a calculation would go over that limit (a condition known as overflow), the result would not be correct.
If you think about how integers are represented in floating point notation, as long as there is no representation error there will be no problem with equality comparison. For "small" integers it is never an issue, because you have plenty of bits for the mantissa and they can be represented exactly. If you try adding very (really) large integers, then issues may arise:
>> 2^50 == 2^50+1
ans =
0
While:
>> 2^53 == 2^53+1
ans =
1
This is the overflow that Scott Hunter is talking about. Look for IEEE Standard 754 to learn more about the representation of floating point numbers.

Is there any way to increase 'realmax' in MATLAB?

realmax on my machine is:
1.7977e+308
I know I have to write my code in a way to avoid long integer calculations, but is there any way to increase the limit?
I mean something like gmp library in C
You may find vpa (variable- precision arithmetic) helpful:
R = vpa(A) uses variable-precision arithmetic (VPA) to compute each element of A to at least d decimal digits of accuracy, where d is the current setting of digits.
R = vpa(A,d) uses at least d significant (nonzero) digits, instead of the current setting of digits.
Here's an example how to use it:
>> x = vpa('10^500/20')
ans =
5.0e498
Note that:
The output x is of symbolic (sym) type. Of course, you shouldn't convert it to double, because it would exceed realmax:
>> double(x)
ans =
Inf
Use string input in order to avoid evaluating large input values as double. For example, this doesn't work
>> vpa(10^500/20)
ans =
Inf
because 10^500 is evaluated as double, giving inf, and then is used as an input to vpa.

Okay to use double for == comparison and indexing?

In this answer gire mentioned to better not use == when comparing doubles.
When creating a increment variable in a for loop using start:step:stop notation, it's type will be of double. If one wants to use this loop variable for indexing and == comparisons, might that cause problems due to floating point precision?!
Should one use integers? If so, is there a way to do so with the s:s:s notation?
Here's an example
a = rand(1, 5);
for ii = length(a):-1:1
if (ii == 1) % Comparing var of type double with ==
b = 0;
else
b = a(ii); % Using double for indexing
end
... % Code
end
Note that the floating point double specification uses 52 bits to store the mantissa (the part after the decimal point) so you can exactly represent any integer in the range
-4503599627370496 <= x <= 4503599627370496
Note that this is larger than the range of an int32, which can only represent
-2147483648 <= x <= 2147483647
If you are just using the double as a loop variable, and only incrementing it in integer steps, and you are not counting above 4,503,599,627,370,496 then you are fine to use a double, and to use == to compare doubles.
One reason people suggest for not using doubles is that you can't represent some common decimals exactly, e.g. 0.1 has no exact representation as a double. Therefore if you are working with monetary values, it may be better to separately store the data as an int and remember a scale factor of 10x or 100x or whatever.
It's sometimes bad to directly compare floating point numbers for equality because rounding issues can cause two floats to be not equal, even though the numbers are mathematically equal. This generally happens when the numbers are not exactly representable as floats, or when there is a significant size difference between the numbers, e.g.
>> 0.3 - 0.2 == 0.1
ans =
0
If you're indexing between integer bounds with integer steps (even though the variable class is actually double), it is ok to use == for comparisons with other integers.
You can cast the indices, if you really want to be safe.
For example:
for ii = int16(length(a):-1:1)
if (ii == 1)
b = 0;
end
end

Performing Bit modification on Floating point numbers in Matlab

I'm working in Matlab using Non-negative Matrix factorization to decompose a matrix into two factors. Using this I get from A two double precision floating point matrices, B and C.
sample results are
B(1,1) = 0.118
C(1,1) = 112.035
I am now trying to modify specific bits within these values but using the bitset function on either values I get an error because bitset requires unsigned integers.
I have also tried using dec2bin function, which I assumed would convert decimals to binary but it returns '0' for B(1,1).
Does anyone know of any way to deal with floats at bit level without losing precision?
You should look into the typecast and bitset functions. (Doc here and here respectively). That lets you do stuff like
xb = typecast( 1.0, 'uint64' );
xb = bitset( xb, 10, 1 );
typecast( xb, 'double' );
The num2hex and hex2num functions are your friends. (Though not necessarily very good friends; hexadecimal strings aren't the best imaginable form for working on binary floating-point numbers. You could split them into, say, 8-nybble chunks and convert each to an integer.)
From the MATLAB docs:
num2hex([1 0 0.1 -pi Inf NaN])
returns
ans =
3ff0000000000000
0000000000000000
3fb999999999999a
c00921fb54442d18
7ff0000000000000
fff8000000000000
and
num2hex(single([1 0 0.1 -pi Inf NaN]))
returns
ans =
3f800000
00000000
3dcccccd
c0490fdb
7f800000
ffc00000