range/tolerance check

Hi all

New to C++:
how do i do a range check for a number to be within , say
+/- 1e-5 of xxx?
1) : what is the syntax for e-5 to write as a constant?

thanks
I would just use if(number > xxx + 1*pow(10,-5) && number < xxx - 1*pow(10,-5))

XeY = X*pow(10,Y)

Include cmath, I believe. However you may have to specify int, long, etc if the variables are ambiguous between the overloaded function.
Last edited on
You could write numbers like this 1e-5
Here are some macros you may want to use.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
using namespace std;

#define ZERO 1e-10
#define SMALL 1e-4
#define DELTA 1e-10
#define isZero(A) ( (A < ZERO) && (A > -ZERO) )
#define isSmall(A) ( (A < SMALL) && (A > -SMALL) )
#define isSame(A, B) ( ((A-B) < ZERO) && ((A-B) > -ZERO) )
#define isSimilar(A, B) ( ((A-B) < SMALL) && ((A-B) > -SMALL) )
#define isBetween(A, B, C) ( ((A-B) > -ZERO) && ((A-C) < ZERO) )

int main() {

 if (isBetween(5, 0, 10)) { // Is 5 Between 0 and 10
 }

 if  (isSame(5.0, 5.000000001) { // Are both close enuff within our threshold of ZERO
 }

 // etc

 return 0;
}
Don't use macros. They don't care about namespaces or anything. They are a stupid text substitution functionality. If you have to use them, at least use names that won't clash with anything that might occur as a normal function/type/object name (e.g. MACRO_isZero). But even that's not advisable. Just Say No.
#define ZERO 1e-10
Yeah, let's #define away the transitivity of equality. That might work for some applications. But in the general case, this is a source of endless pain (as is any macro, in case I haven't mentioned that). Just wait until you get to the debugging. (By the way, why do you choose 1e-10, and not 1e-20, or 1e-8? You don't even distinguish between float and double, let alone the actual operand size. If you must use an epsilon, at least use a known error bound)

You can do all that with (template) functions. They will be inlined automatically by any decent compiler, so there really isn't any runtime speed difference, but you have type safety, they respect namespaces, and when it comes to debugging, you have the chance to actually find the error. Plus, you can overload them if you require different functions, say, for float and double.
@exception: And yet, the boost library uses them without an issue. So does google.

Yes they have problems, but they offer sometimes very simple and quick solutions to common problems (e.g inequality of doubles).

Mine are merely an illustration. I use them only for doubles, and it's 1e-10 because anything less than that is considered scientifically insignificant in my work so it is not a worry. I can use all of 10 lines of Macros, stored in a known location with known uses and not have to write a heap of template code.

The stl::string class has >100 member functions. That doesn't make monolithic class design a Good Thing.
Macros don't care about scope, or type, or pretty much anything. Using them is not safe and contradicts encapsulation. They don't belong into C++, even though needed/useful in C. C++ has a type-safe and scope-safe solution for all the problems macros possibly can offer, without even being more complex:
template<typename T> equal(const T& t1, const T& t2) {return abs(t2-t1)<epsilon(t1,t2);}
... where you now could easily overload the epsilon function for double, float, whatever.
I also would question your "without issues" statement. It still isn't safe/portable to use the '_' in the beginning of a name, even if not in global scope, because some compiler vendors use names starting with a single '_' in macros (thinking that they are in "global scope", but there is no such thing as a scope for a macro). Since these names are reserved in global scope only, this actually *is* an issue (although not for the one writing the macro...).

I use them only for doubles, and it's 1e-10 because anything less than that is considered scientifically insignificant in my work so it is not a worry.

If you would write a program for me, and you wouldn't document the input domain and the error tolerance of the output, I'd consider such a fixed, undocumented epsilon a bug. And being honest, do you really know, when writing your code, what the error of an expression like a*b+c/d is for a, b,c and d in the range [-1000, 1000] would be? I don't, but I'm very happy that my semantic epsilon function does. (Also note that being "insignificant for the output" does not imply "insignificant for the calculations")
Last edited on
Topic archived. No new replies allowed.