MATLAB MATLAB Floating Point: Find Better Way Than Rounding

AI Thread Summary
The discussion revolves around issues with floating-point representation in MATLAB, specifically regarding the comparison of two vectors, V3 and V3c. The user encounters a problem where the values appear to be equal but are not due to the inherent inaccuracies in floating-point arithmetic. MATLAB represents the same decimal value, 15.1, in slightly different ways, leading to no matches when attempting to find equal values. The conversation highlights that certain decimal fractions cannot be exactly represented in binary, causing discrepancies in calculations. A workaround discussed involves rounding values to a specific number of decimal places, though this is deemed not robust. An alternative suggestion is to use a tolerance-based comparison, where the absolute difference between the two values is checked against a small epsilon value, allowing for a more flexible and accurate comparison of floating-point numbers.
Pythagorean
Science Advisor
Messages
4,416
Reaction score
327
so I make a vector:

V3 = [15.05:.05:15.15];
V3c = [14.75:.05:15.15];

find(V3c == Vc(2))

and I get nothing (no matches)

apparently, when MATLAB constructed V3, it did so such that:
V3(2) == 15.10000000000001
and
V3c(8) == 15.10000000000000

what's the deal?

My cheap way around this is:

V3 = fix(V3*1000)/1000

so I multiply by 1000, shave off the remaining decimals, and divide by 1000, but this doesn't seem robust to me. Is there a better way to handle this floating point difference?
 
Physics news on Phys.org
Certain decimal fractions have computer representations that are only approximate, due to the nature of floating point representations. This isn't something that is specific to matlab, but is present in programming languages that store floating points numbers in binary form.

Decimal fractions that involve 1/2, 1/4, 1/8, 1/16, ... and combinations of them (such as 3/8 = 1/4 + 1/8) have binary representations that are exact. Decimal fractions that involve 1/5, 1/10, and so on have representations that are not exact, because the complete binary representation would require an infinite number of bits. This is similar to the situation with the fraction 1/3 in base-10. The decimal fraction is 0.33333... with an infinite number of 3's. If you truncate the representation, you get a value that is only close to 1/3.

Likewise, the binary representation of 1/10 has an infinitely long binary fraction representation. Since there are only a relatively few bits available (64, typically), the representation is only close to 1/10.
 
Thank you for your response. I understand the concept of floating point numbers. Why does MATLAB represent 15.1 in two different ways though, and what command can I use to force it to use the same method to define 15.1 the same way in both variables?
 
found a function that pretty much does what I do, only makes the decimal place an input.
from:
[URL]http://home.online.no/~pjacklam[/URL]/matlab/software/util/fullindex.html[/URL]

[CODE]function y = fixdec(x, n)
%FIXDEC Round towards zero with a specified number of decimals.
%
% Y = FIXDEC(X, N) rounds the elements of X to N decimals.
%
% For instance, fixdec(10*sqrt(2) + i*pi/10, 4) returns 14.1421 + 0.3141i
%
% See also: FIX, FLOOR, CEIL, ROUND, FIXDIG, ROUNDDEC, ROUNDDIG.

% Author: Peter J. Acklam
% Time-stamp: 2004-09-22 20:08:10 +0200
% E-mail: pjacklam@online.no
% URL: [URL]http://home.online.no/~pjacklam[/URL]

% Check number of input arguments.
error(nargchk(2, 2, nargin));

% Quick exit if either argument is empty.
if isempty(x) || isempty(n)
y = [];
return
end

% Get size of input arguments.
size_x = size(x);
size_n = size(n);
scalar_x = all(size_x == 1); % True if x is a scalar.
scalar_n = all(size_n == 1); % True if n is a scalar.

% Check size of input arguments.
if ~scalar_x & ~scalar_n & ~isequal(size_x, size_n)
error(['When both arguments are non-scalars they must have' ...
' the same size']);
end

f = 10.^n;
y = fix(x .* f) ./ f;[/CODE]
 
Last edited by a moderator:
Pythagorean said:
Thank you for your response. I understand the concept of floating point numbers. Why does MATLAB represent 15.1 in two different ways though, and what command can I use to force it to use the same method to define 15.1 the same way in both variables?
I don't believe that it is representing 15.1 in two different ways. What you are getting are most likely two different values. Your array Vc contains [15.05, 15.05 + .05, 15.05 + .05 + .05]. Because none of those numbers is exactly representable in 64 bits (or however many MATLAB uses for a floating point value), it is extremely unlikely that the array contains [15.05, 15.10, 15.15] as you are probably thinking it is.

The other array contains [14.75, 14.75 + .05, 14.75 + .05 + .05, ...], with values ranging from 14.75 (exactly) up to 15.15 (approximately). Because of the addition of numbers that are only close to .05, the next to last value in the array is only close to 15.10.
 
Mark44 said:
I don't believe that it is representing 15.1 in two different ways. What you are getting are most likely two different values. Your array Vc contains [15.05, 15.05 + .05, 15.05 + .05 + .05]. Because none of those numbers is exactly representable in 64 bits (or however many MATLAB uses for a floating point value), it is extremely unlikely that the array contains [15.05, 15.10, 15.15] as you are probably thinking it is.

The other array contains [14.75, 14.75 + .05, 14.75 + .05 + .05, ...], with values ranging from 14.75 (exactly) up to 15.15 (approximately). Because of the addition of numbers that are only close to .05, the next to last value in the array is only close to 15.10.

Ah, ok, that adjusts some of my assumption about how floating points are handled (it reminds me of equal tempered tuning!)

My deal was that the difference between the two 15.1's was on the order of e-10, so I was wondering why MATLAB was so picky and why it can't just read my damn mind about significant digits :P
 
Instead of using the complicated function above, you could just do something like

abs(V3c-V3(2))<epsilon

where you set epsilon as the tolerance you want to keep. This then returns a logical with ones where the two things were equal.

Hope that helps :smile:
 

Similar threads

Replies
1
Views
9K
Replies
1
Views
3K
Replies
4
Views
3K
Replies
1
Views
3K
Replies
7
Views
3K
Replies
1
Views
2K
Replies
7
Views
4K
Replies
1
Views
3K
Replies
1
Views
3K
Replies
5
Views
3K
Back
Top