Reputation: 18580
My Question - part 1: What is the best way to test if a floating point number is an "integer" (in Matlab)?
My current solution for part 1: Obviously, isinteger
is out, since this tests the type of an element, rather than the value, so currently, I solve the problem like this:
abs(round(X) - X) <= sqrt(eps(X))
But perhaps there is a more native Matlab method?
My Question - part 2: If my current solution really is the best way, then I was wondering if there is a general tolerance that is recommended? As you can see from above, I use sqrt(eps(X))
, but I don't really have any good reason for this. Perhaps I should just use eps(X)
, or maybe 5 * eps(X)
? Any suggestions would be most welcome.
An Example: In Matlab, sqrt(2)^2 == 2
returns False. But in practice, we might want that logical condition to return True. One can achieve this using the method described above, since sqrt(2)^2
actually equals 2 + eps(2)
(ie well within the tolerance of sqrt(eps(2))
. But does this mean I should always use eps(X)
as my tolerance, or is there good reason to use a larger tolerance, such as 5 * eps(X)
, or sqrt(eps(X))
?
UPDATE (2012-10-31): @FakeDIY pointed out that my question is partially a duplicate of this SO question (apologies, not sure how I missed it in my initial search). Given this I'd like to emphasize the "tolerance" part of the question (which is not covered in that link), ie is eps(X)
a sensible tolerance, or should I use something larger, like 5 * eps(X)
, and if so, why?
UPDATE (2012-11-01): Thanks everyone for the responses. I've +1'ed all three answers as I feel they all contribute meaningfully to various aspects of the question. I'm giving the answer tick to Eric Postpischil as that answer really nailed the tolerance part of the question well (and it has the most upvotes at this point in time).
Upvotes: 3
Views: 6817
Reputation: 815
1) I have historically used your method with a simple tolerance, eps(X)
. The mod methods interested me though, so I benchmarked a couple using Steve Eddins timeit function.
f = @() abs(X - round(X)) <= eps(X);
g = @() X == round(X);
h = @() ~mod(X,1);
For single values, like X=1.0
, yours appears to fastest:
timeit(f) = 7.3635e-006
timeit(g) = 9.9677e-006
timeit(h) = 9.9214e-006
For vectors though, like X = 1:0.01:100
, the other methods are faster (though round still beats mod):
timeit(f) = 0.00076636
timeit(g) = 0.00028182
timeit(h) = 0.00040539
2) The error bound is really problem dependent. Other answers cover this much better than I am able to.
Upvotes: 1
Reputation: 224546
No, there is no general tolerance that is recommended, and there cannot be.
The difference between a computed result and a mathematically ideal result is a function of the operations that produced the computed result. Because those operations are specific to each application, there is no general rule for testing any property of a computed result.
To design a proper test, you must determine what errors may have occurred during computation, determine bounds on the resulting error in the computed result, and test whether the computed result differs from the ideal result (perhaps the nearest integer) by less than those bounds. You must also decide whether those bounds are sufficiently small to satisfy your application’s requirements. (Using a relaxed test that accepts as an integer something that is not an integer decreases false negatives [incorrect rejections of a result as an integer where the ideal result would be an integer] but increases false positives [incorrect acceptances of a result as an integer where the ideal result would not be an integer].)
(Note that it can even be the case the testing as if the error bounds were zero can produce false negatives: It is possible a computation produces a result that is exactly an integer when the ideal result is not an integer, so any error tolerance, even zero, will falsely report this result is an integer. If this is unacceptable for your application, then, in such a case, the computations must be redesigned.)
It is not only not possible to state, without specific knowledge of the application, a numerical tolerance that may be used, it is impossible to state whether the tolerance should be absolute, should be relative to the computed value or to a target value, should be measured in ULPs (units of least precision), or should be set in some other manner. This is because errors may be introduced into computations in a variety of ways. For example, if there is a small relative error in a
and a
and b
are close in value, then a-b
has a large relative error. Additionally, if c
is large, then (a-b)*c
has a large absolute error.
Upvotes: 6
Reputation: 1445
Its probably not the most efficient method but I would use mod
for this:
a = 15.0000000000;
b = mod(a,1.0)
c = 15.0000000001;
d = mod(c,1.0)
returns b = 0
and d = 1.0000e-010
There are a number of other alternatives suggested here:
How do I test for integers in MATLAB?
I like the idea of comparing (x == floor(x))
too.
Upvotes: 3