Wrong output using "find" while filtering a matrix

1 vue (au cours des 30 derniers jours)
Christos Tsallis
Christos Tsallis le 6 Jan 2023
I am trying to filter some values of a matrix using an index. Given the value "i=0.10", and after that using "range_limits = [i i+0.05]", I am saying that range limits are from 0.10 to 0.15. The next condition is to find all the values inside the range 0.10 to 0.15 (without 0.15). Even if I have "a(:) < range_limits(2))" only with less (and not less or equal), matlab still outputs that row 2 is inside the range of 0.10 to 0.15 (without 0.15). This is 100% wrong. When I type range_limits = [0.1 0.15] then the output is right and in_range_rows is 1, 6 and 9 without the 2. But I need to have an index inside my range_limits. How can I do it?
%CORRECT OUTPUT
a=[0.10;0.15;0.25;0.34;0.41;0.10;0.20;0.40;0.14;0.56]
a = 10×1
0.1000 0.1500 0.2500 0.3400 0.4100 0.1000 0.2000 0.4000 0.1400 0.5600
i=0.10
i = 0.1000
range_limits = [i 0.15]
range_limits = 1×2
0.1000 0.1500
in_range_rows = find(a(:) >= range_limits(1) & a(:) < range_limits(2))
in_range_rows = 3×1
1 6 9
%WRONG OUTPUT
a=[0.10;0.15;0.25;0.34;0.41;0.10;0.20;0.40;0.14;0.56]
a = 10×1
0.1000 0.1500 0.2500 0.3400 0.4100 0.1000 0.2000 0.4000 0.1400 0.5600
i=0.10
i = 0.1000
range_limits = [i i+0.05]
range_limits = 1×2
0.1000 0.1500
in_range_rows = find(a(:) >= range_limits(1) & a(:) < range_limits(2))
in_range_rows = 4×1
1 2 6 9

Réponses (1)

Walter Roberson
Walter Roberson le 6 Jan 2023
You have fallen victim to the third classic blunder -- though admittedly less well known than never going against a Sicilian when death is on the line.
(0.1 + 0.05) - 0.15
ans = 2.7756e-17
MATLAB does not compute in decimal. Very few systems compute in decimal. (Some banking regulations require computation in decimal.)
  3 commentaires
Walter Roberson
Walter Roberson le 6 Jan 2023
Suppose you try to fix this kind of problem by working in decimal, under the hypothesis that the "real" problem is using binary representation. Suppose that you are restricted to a finite number of decimal places. For point of illustration we will use 5 decimal places.
Now consider storing 2/3 to 5 decimal places. Mathematically 2/3 is an infinitely repeating value between 0.66666 and 0.66667. But you need to pick one of the two values for your finite representation, you cannot have 2/3 convert to one of the values sometimes and to the other value the rest of the time.
Pick one of the two representations and add it to itself a total of 3 times.
0.66666 + 0.66666 + 0.66666 = 1.99998
0.66667 + 0.66667 + 0.66667 = 2.00001
So one of the two cases the total will be too low and the other case the total will be too high.
Would using more decimal places help? Well you can reduce the absolute error, but if you use any finite number of decimal places you still end up with the last digit being low by 2 or being high by 1. You can only make the calculation exact by using an infinite number of decimal places.
This shows that the problem is not the use of binary, that the problem is the use of finite precision positional notation.
It follows that if you need A + B = C to be reliably (theoretical A) + (theoretical B) = (theoretical C) for A B C that are not irrational, then you cannot use any finite positional notation, and need to switch all of your calculations to rational. At least until you run out of memory storing the rationals, as you run into different problems if you use fixed length rationals...
You are fighting against finite mathematics, and you are going to lose in some situations.
Walter Roberson
Walter Roberson le 6 Jan 2023
Did you ever take Chemistry or Physics and have to deal with Significant Digits? The idea that if you are given a number such as 6.02 that you should not treat it as the infinitely precise rational (602)/(100) and should instead treat 6.02 as standing in for some indefinitely precise value whose exact value is not known, but which is between 6015/1000 (inclusive) and 6025/1000 (exclusive)?
When you program computers you should treat literal constants such as 0.1 the same kind of way, of standing in for some value that you do not know precisely. The hardware and programming language will have rules that give concrete definitions but the values are not easy to keep mental track of, and as soon as you get into transcendental functions you will find that the formal specifications give some leeway to manufacturers, so if for example log(8.19789) is 1 bit different on one CPU than on another then both might be working to within the standards. (There are formulas for which you can show that no matter how many "guard digits" you use, that you will sometimes get results that disagree with theory)
So it is not a matter that "accurate" calculations on computers is "hard work with lots of details and might be expensive and slow, but is do-able": theory shows that you cannot get completely "accurate" calculations in all cases if you compute with finite resources.
All of which is to suggest that you should be adjusting your expectations instead of looking for a technical solution.

Connectez-vous pour commenter.

Catégories

En savoir plus sur Loops and Conditional Statements dans Help Center et File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by