ISEQUALFP Check two values for equality within floating point precision
It is widely known that floating point computation has a fundamental
limitation: not every value can be represented exactly. This can
lead to surprising results for those unfamiliar with this
limitation, especially since 'double' is MATLAB's default numerical
This function accepts two float values (single or double) or arrays
of floats, and returns a logical value indicating whether they
are equal within floating point precision. Mixed single and double
inputs will be evaluated based on single floating point precision.
Floating point accuracy reference:
yn = isequalfp(a,b)
a,b: floats or arrays of floats to compare
yn: logical scalar result indicating equality
a = 0.3;
b = 0.1*3;
isequal(a,b) % ans = 0
isequalfp(a,b) % ans = 1
c = a+2*eps(a) % c = 0.3000...
isequalfp(a,c) % ans = 0
See also: EPS, ISEQUAL
Andrew Davis (2019). ISEQUALFP: Check equality within floating point precision (https://www.mathworks.com/matlabcentral/fileexchange/36734-isequalfp-check-equality-within-floating-point-precision), MATLAB Central File Exchange. Retrieved .
I think I'll keep the behaviour for different sizes as it is, simply because I think it would confuse me if I was expecting yn=1, but got 0 because one vector was 1 item shorter, for example. Alternatively the function could return 0 but with a warning about the sizes, I suppose, but this is easy enough for people to change if it bugs them.
As for the mixed single and double cases, I like the current behaviour because I had intended for this function to be somewhat generous in calling values equal. This is because I'm never operating near the limits of floating point precision in my day-to-day work. In this way the max() function keeps things somewhat loose in that it returns a single-valued result for mixed single and double inputs. Even, for example, max(single(1), 1+1e6*eps('double')) returns single(1). So the behaviour is:
isequalfp(single(1), 1+1e8*eps('double')) => 1
isequalfp(single(1)+eps('single'), 1) => 1
isequalfp(single(1)+2*eps('single'), 1) => 0
I've updated the documentation to attempt to convey this. Again, thanks for your comments, I'm glad this generated some discussion.
Fine. Now it works as expected. I'd prefer to get FALSE if the sizes do not match, equivalently to ISEQUAL. But this is a matter of taste.
What do you expect if one input is a SINGLE and the other a DOUBLE? E.g.:
Note that "single(1) - (1+eps('double'))" replies: single(-2.2204e-016)
However, the function works as I expect it, it is well documented, useful and usable. Although this is a one-line actually, floating point arithmetics are never trivial. See also: http://en.wikipedia.org/wiki/Floating_point
You're right, Jan, that does work better for very disparate arrays. I've updated the file -- thanks for your comment!
The function fails for: isequalfp([1e17, 1], [1e17, -1]) => true
I think you want:
yn = abs(a - b) <= eps(max(abs(a), abs(b)));
Updated documentation to explain single/double behaviour
Syntax modified per Jan's suggestion
Description grammar and spacing corrections
Inspired: Solve Magic Square