Why is 24.0000 not equal to 24.0000 in MATLAB?

I am writing a program where I need to remove duplicate points stored in a matrix. The problem is that when it comes to checking if these points are in the matrix, MATLAB cannot recognize them in the matrix, although they exist.

In the following code, the intersections function gets the intersection points:

 [points(:,1), points(:,2)] = intersections(... obj.modifiedVGVertices(1,:), obj.modifiedVGVertices(2,:), ... [vertex1(1) vertex2(1)], [vertex1(2) vertex2(2)]); 

Result:

 >> points points = 12.0000 15.0000 33.0000 24.0000 33.0000 24.0000 >> vertex1 vertex1 = 12 15 >> vertex2 vertex2 = 33 24 

Two points ( vertex1 and vertex2 ) should be excluded from the result. This should be done using the following commands:

 points = points((points(:,1) ~= vertex1(1)) | (points(:,2) ~= vertex1(2)), :); points = points((points(:,1) ~= vertex2(1)) | (points(:,2) ~= vertex2(2)), :); 

After that, we get this unexpected result:

 >> points points = 33.0000 24.0000 

The result should be an empty matrix. As you can see, the first (or second?) Pair [33.0000 24.0000] was eliminated, but not the second.

Then I checked these two expressions:

 >> points(1) ~= vertex2(1) ans = 0 >> points(2) ~= vertex2(2) ans = 1 % <-- It means 24.0000 is not equal to 24.0000? 

What is the problem?




More surprisingly, I created a new script that only has the following commands:

 points = [12.0000 15.0000 33.0000 24.0000 33.0000 24.0000]; vertex1 = [12 ; 15]; vertex2 = [33 ; 24]; points = points((points(:,1) ~= vertex1(1)) | (points(:,2) ~= vertex1(2)), :); points = points((points(:,1) ~= vertex2(1)) | (points(:,2) ~= vertex2(2)), :); 

The result, as expected:

 >> points points = Empty matrix: 0-by-2 
+56
floating-point precision matlab
Mar 26 '09 at 16:10
source share
6 answers

The problem you're having is related to the way the floating point numbers are represented on the computer. A more detailed discussion of floating point representations appears at the end of my answer (section "Floating view"). TL version ; DR : since computers have a limited amount of memory, numbers can only be represented with finite precision. Thus, the precision of floating-point numbers is limited to a certain number of decimal places (about 16 significant digits for double-precision values, the default value is used in MATLAB).

Actual and displayed accuracy

Now, to turn to a specific example in the question ... while 24.0000 and 24.0000 displayed in the same way, it turns out that in this case they actually differ in very small decimal amounts. You do not see this because MATLAB only displays 4 significant digits by default , keeping the overall display neat and tidy. If you want to see full accuracy, you must either issue the format long command or view the hexadecimal representation of the number:

 >> pi ans = 3.1416 >> format long >> pi ans = 3.141592653589793 >> num2hex(pi) ans = 400921fb54442d18 

Initialized values ​​versus calculated values

Since there is only a finite number of values ​​that can be represented for a floating point number, it is possible that the calculation will result in a value that lies between two of these representations. In this case, the result should be rounded to one of them. This results in a small machine accuracy error. It also means that initializing a value directly or with some calculation can give slightly different results. For example, a value of 0.1 does not have an exact floating point representation (i.e., it is slightly rounded), and therefore you get counter-intuitive results like this because of the accumulation of rounding errors: / p>

 >> a=sum([0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1]); % Sum 10 0.1s >> b=1; % Initialize to 1 >> a == b ans = logical 0 % They are unequal! >> num2hex(a) % Let check their hex representation to confirm ans = 3fefffffffffffff >> num2hex(b) ans = 3ff0000000000000 

How to handle floating point comparisons correctly

Since floating point values ​​can differ in very small amounts, any comparisons should be made by checking that the values ​​are within a certain range (i.e., tolerance) from each other, and not exactly equal to each other. For example:

 a = 24; b = 24.000001; tolerance = 0.001; if abs(ab) < tolerance, disp('Equal!'); end 

displays "Equal!".

Then you can change your code to something like:

 points = points((abs(points(:,1)-vertex1(1)) > tolerance) | ... (abs(points(:,2)-vertex1(2)) > tolerance),:) 



Floating point

A good overview of floating point numbers (and, in particular, the IEEE 754 standard for floating point arithmetic ) What every computer scientist should know about David Goldberg's floating point arithmetic .

The binary floating-point number is actually represented by three integers: the signed bit s , the value (or coefficient / fraction) b and the exponent e . For a double-precision floating-point format, each number is represented by 64 bits laid out in memory as follows:

enter image description here

The real value can be found by the following formula:

enter image description here

This format allows numeric representations in the range from 10 ^ -308 to 10 ^ 308. For MATLAB, you can get these restrictions from realmin and realmax :

 >> realmin ans = 2.225073858507201e-308 >> realmax ans = 1.797693134862316e+308 

Since there are a finite number of bits used to represent a floating point number, there are only a lot of finite numbers in the above range. Calculations often lead to a value that does not exactly match one of these final representations, so the values ​​should be rounded. These machine error errors manifest themselves in different ways, as described in the examples above.

To better understand these rounding errors, it is useful to take a look at the relative floating point precision provided by the eps function, which quantifies the distance from a given number to the next largest floating point representation:

 >> eps(1) ans = 2.220446049250313e-16 >> eps(1000) ans = 1.136868377216160e-13 

Note that the accuracy matches the size of the number represented; large numbers will have large distances between floating point representations and therefore will have fewer precision digits after the decimal point. This may be an important consideration in some calculations. Consider the following example:

 >> format long % Display full precision >> x = rand(1, 10); % Get 10 random values between 0 and 1 >> a = mean(x) % Take the mean a = 0.587307428244141 >> b = mean(x+10000)-10000 % Take the mean at a different scale, then shift back b = 0.587307428244458 

Please note that when we shift the x values ​​from the range [0 1] to the range [10000 10001] , calculate the average value, and then subtract the average offset for comparison, we get a value that differs for the last 3 significant digits. This illustrates how shifting or scaling data can change the accuracy of the calculations performed on it, which should be associated with certain problems.

+80
Mar 26 '09 at 16:14
source share
— -

Take a look at this article: Floating Point Hazards . Although his examples in FORTRAN make sense for almost any modern programming language, including MATLAB. Your problem (and solution for it) is described in the Safe Comparisons section.

+20
Mar 26 '09 at 16:18
source share

type of

 format long g 

This command will show the FULL value of the number. It will probably be something like 24.00000021321! = 24.00000123124

+12
Mar 26 '09 at 21:14
source share

Try to write

0.1 + 0.1 + 0.1 == 0.3.

Warning: you may be surprised at the result!

+7
Dec 14 2018-11-21T00:
source share

Perhaps these two numbers are really 24.0 and 24.000000001, but you do not see all the decimal places.

+1
Mar 26 '09 at 16:17
source share

Check out the EPS Matlab feature .

Matlab uses floating point math up to 16 digits of precision (only 5 is displayed).

+1
Mar 26 '09 at 16:25
source share



All Articles