Matlab considers different two equal numbers!

I calculated a matrix (attached). In the 11th row, matlab considers the 3rd column, i.e., entry (11, 3) as the maximum entry of the that row, although, the entries in columns 1, 2, ..., 7, and 15 have the exact same value, i.e.,
find(matrix(11, :) == max(matrix(11, :)))
only gives 3.
Does anyone know why it happens?
Thanks

Answers (2)

You are not seeing the entire picture.
If you test ‘matrix(11,:)’:
Check = matrix(11, :) - max(matrix(11,:))
the result is:
Check =
-0.000000000000006 -0.000000000000002 0.000000000000000 -0.000000000000007 -0.000000000000003 -0.000000000000004 -0.000000000000002 -0.500000000000002 -0.999999999999997 -1.499999999999993 -1.999999999999991 -1.499999999999994 -1.000000000000000 -0.500000000000006 -0.000000000000003
and you have encountered ‘floating-point approximation error’.
See the documentation section on Floating-Point Numbers for an extended discussion.

7 Comments

Mohammad
Mohammad on 9 Dec 2019
Edited: Mohammad on 9 Dec 2019
Thanks. But what I want MATLAB to do is to force it do all the calculations only by considering 4 digits after decimal point. Is there a command which I can put at the beginning of my code to do so?
My pleasure.
It is straightforward to truncate decimal fractions to 4 digits after the decimal, without rounding (in this example). Then, do the comparisons on ‘Matrix4’ instead of the particular row of ‘Matrix’ without this pre-processing step:
Matrix4 = fix(rem(Matrix(11,:),1)*1E+4)*1E-4
This can easily be made into an anonymous function:
TruncateRow = @(vector,precision) fix(rem(vector,1)*10^precision)./10^precision;
calling it as:
Matrix4 = TruncateRow(Matrix(11,:),4)
Then do the comparisons.
Experiment to get different results.
Mohammad
Mohammad on 9 Dec 2019
Edited: Mohammad on 9 Dec 2019
Thanks! But that matrix is just a small part of my calculations. I wonder if there is a code that I put at the beginning of my code to make the calculations with only 4 digits as default (or to force MATLAB to always round the numbers to 4 digits during its calculations).
My pleasure.
MATLAB maintains full internal precision, regardless of how it is displayed. If you want to truncate the precision, use my code to create a copy of your original matrix with reduced precision, then do the comparisons or other calculations on that copy. You can do that in the beginning of your code, then work on it later. The original, full-precision data will be stored separately in the event you need it.
Changing the name of the function to ‘TruncateArray’:
TruncateArray = @(array,precision) fix(rem(array,1)*10^precision)./10^precision;
and testing it:
format long
A = rand(5)
R = TruncateArray(A,4)
format short
demonstrates that it works.
You should be considering using ismembertol() instead of comparisons.
ismembertol() works with relative values by default. You can use an absolute tolerance instead if you pass in the option 'Datascale', 1 such as
ismembertol(matrix(11, :), max(matrix(11, :)), 1e-4, 'Datascale', 1)
@Walter —
Thr original Question was about floating-point approximation error. I considered ismembertol for the comaprisions, however this Comment introduces some ambiguity with respect to the what Mohammad wants. Apparently, Mohammad wants 4-digit precision everywhere. That may not be possible because certain operations would inevitably result in extended precision results that would again need to be truncated.
But what I want MATLAB to do is to force it do all the calculations only by considering 4 digits after decimal point.
Use the Fixed Point Designer product; https://www.mathworks.com/help/fixedpoint/

Sign in to comment.

Adam Danz
Adam Danz on 9 Dec 2019
Edited: Adam Danz on 10 Dec 2019
You could limit the values in your matrix to the first 4 decimal places but this is usually not a good idea unles there's a reasonable justification to do so. Take a look at the values you mentioned.
format long % so you can see more decimal places
Trace_Wc([1,2,7],3)
ans =
1.249999999999995
1.250000000000014
1.249999999999999
As you can see, limiting those values to the first 4 dp will not give you matching values.
Those same values in "short" format are
format short
Trace_Wc([1,2,7],3)
ans =
1.2500
1.2500
1.2500
But the key point is that the format just affects what you see, not the actual values.
If you have principled reason to truncate the precision to 4 decimal places (ie, the instrument used to get the data is only precise to 3 dp), you could do so like this:
Trace_WcNew = round(Trace_Wc, 4);
% Trace_WcNew = round(Trace_Wc * 1E4)/1E4 % for <r2014b (see comments below)
Instead, if you're trying to find values in a row that are approximately equal to the max value of that row, use a threshold like this:
idx = abs(Trace_Wc(11,:) - max(Trace_Wc(11,:))) < 0.0001
This locates all values in row 11 that are within 0.0001 of the max. Here's what it's returns:
format long
Trace_Wc(11,idx)
ans =
Columns 1 through 6
2.249999999999984 2.249999999999988 2.249999999999990 2.249999999999983 2.249999999999988 2.249999999999987
Columns 7 through 8
2.249999999999988 2.249999999999988
In that case, 0.0001 is somewhat arbitrarily chosen after looking at the data. Instead, you could use a threshold that is 1/10 of 1% of the range of your data such as
threshold = range(Trace_Wc(11,:))*.001

2 Comments

Trace_WcNew = round(Trace_Wc * 1E4)/1E4
These days,
Trace_WcNew = round(Trace_Wc, 4);
Jeez... that's been out since r2014b and I keep forgetting to use it.... thx Walter.

Sign in to comment.

Tags

Asked:

on 6 Dec 2019

Edited:

on 10 Dec 2019

Community Treasure Hunt

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

Start Hunting!