www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Suggestion: Additional operators for float cmp

reply nail <nail_member pathlink.com> writes:
What if there will some additional operators for float comparement? E.g ==~ <~
~ etc. Because of floats nature it is very often we have to use constructions
like
if (equal(firstVector3, secondVector3)) { } or if (greater_equal(float1, float2)) { } Definition of this functions is very simple and as a rule wraps to comparement difference of operants with float.epsilon. But I think it is very annoying to use this method very often, even more usual operators like ==, <= are used rarely then a approximal comparement. Is this necessary, how do u think?
Oct 14 2004
next sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
nail wrote:

 What if there will some additional operators for float comparement? 
 E.g ==~ <~ >~ etc.
Defining either of those will potentially break existing code, as ~ is a unary operator.
 Because of floats nature it is very often we have to use
 constructions like
 
 if (equal(firstVector3, secondVector3))
 {
 }
What's wrong with == ?
 or
 
 if (greater_equal(float1, float2))
 {
 }
What's wrong with >= ? Stewart.
Oct 14 2004
parent reply nail <nail_member pathlink.com> writes:
In article <ckm5p7$2lao$1 digitaldaemon.com>, Stewart Gordon says...
nail wrote:

 What if there will some additional operators for float comparement? 
 E.g ==~ <~ >~ etc.
Defining either of those will potentially break existing code, as ~ is a unary operator.
Hm... I forgot about this.
 Because of floats nature it is very often we have to use
 constructions like
 
 if (equal(firstVector3, secondVector3))
 {
 }
What's wrong with == ?
exp(x) not always equal to exp(x)
 or
 
 if (greater_equal(float1, float2))
 {
 }
What's wrong with >= ?
float x = 5.f / 6.f; for ( ; x < 100; x += 5.f / 6.f) ; for ( ; x >= 5.f / 6.f; x -= 5.f / 6.f) ; if (x != 5.f / 6.f) assert(0); Assertion will be thrown
Oct 14 2004
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
nail wrote:
 In article <ckm5p7$2lao$1 digitaldaemon.com>, Stewart Gordon says...
 
 nail wrote:
<snip>
 if (equal(firstVector3, secondVector3))
 {
 }
What's wrong with == ?
exp(x) not always equal to exp(x)
You mean if exp(x) is NaN? And that your equal would treat NaN as equal to NaN? Or what?
 or
 
 if (greater_equal(float1, float2))
 {
 }
What's wrong with >= ?
float x = 5.f / 6.f; for ( ; x < 100; x += 5.f / 6.f) ; for ( ; x >= 5.f / 6.f; x -= 5.f / 6.f) ; if (x != 5.f / 6.f) assert(0); Assertion will be thrown
Actually, compiler error will be thrown. A ; by itself isn't a statement in D. But I've no idea what you're talking about. How would your greater_equal enable x to be not greater than or equal to a certain value, while at the same time being equal to that same value? Stewart.
Oct 15 2004
parent reply pragma <pragma_member pathlink.com> writes:
In article <cko4tu$1fnf$1 digitaldaemon.com>, Stewart Gordon says...
 (...)
But I've no idea what you're talking about.  How would your 
greater_equal enable x to be not greater than or equal to a certain 
value, while at the same time being equal to that same value?

Stewart.
All apologies if I've misunderstood the question here. :) It all goes back to what my high-school CS teacher said: "Never directly compare the values of two reals with '=='. It won't work." The problem here is with precision: floating-point representations have to convert a nice, neat decimal number into a binary equivalent. This generates some error in the lowest order bits, and for most purposes is acceptable to ignore. But when comparing the result of a calculation against other values, you need to account for this precision error. This is because the result of your calculation is going to be /close/ to what you'd expect plus or minus that error. This "fudge factor" is usually called "Epsilon". So when you want to do this: float a,b; if(a == b){ /*...*/ } You really need to do this: const float epsilon = 0.000000001; // depends on your application float a,b; if( b-epsilon <= a && a <= b+epsilon){ /*...*/ } .. and so forth. This is better served by a suite of functions for readability's sake: const float epsilon = 0.000000001; // depends on your application float equals(float a,float b){ return b-epsilon <= a && a <= b+epsilon; } float a,b; if(equals(a,b)){ /*...*/ } It's not really so complicated or exotic as it would seem. Anywhere you use floating-point mathematics heavily (3D games, finance, statistics, etc.) you need something like this to keep things sane. Now, if I were to suggest a feature in D to support this, i'd advocate a simple class that contains the needed operators called 'Epsilon'.
 class Epsilon{
     float eps;
     bit eq(float a,float b){
         return(b-eps <= a && a <= b+eps);
     }
     /* other operations like lt, lte, gt, gte, neq, etc go here */
     this(float eps){ this.eps = eps; return this; }
 }
Combine this with D's 'with' syntax and you get something that's pretty useful.
 void main(){
       float a,b;
       a=0;
       b=0.0000001;
       with(new Epsilon(0.0000001)){
           if(eq(a,b)){
               printf("a is equal to b\n");
           }
       }
 }
You could even do the same with a struct which would be even more efficent. Eric Anderton -- at -- yahoo
Oct 15 2004
parent Stewart Gordon <smjg_1998 yahoo.com> writes:
pragma wrote:

<snip>
 But when comparing the result of a calculation against other values, you need
to
 account for this precision error.  This is because the result of your
 calculation is going to be /close/ to what you'd expect plus or minus that
 error.  This "fudge factor" is usually called "Epsilon".
 
 So when you want to do this:
 
 float a,b;
 if(a == b){ /*...*/ }
 
 You really need to do this:
 
 const float epsilon = 0.000000001; // depends on your application
 float a,b;
 if( b-epsilon <= a && a <= b+epsilon){ /*...*/ }
I see. But numerical noise is relative to the order of magnitude of the numbers being dealt with. So it might make more sense to consider values as correct to significant figures rather than decimal places...? <snip>
 It's not really so complicated or exotic as it would seem.  Anywhere you use
 floating-point mathematics heavily (3D games, finance, statistics, etc.) you
 need something like this to keep things sane.
Do many financial applications necessitate dealing with units arbitrarily smaller than a penny, cent or whatever?
 Now, if I were to suggest a feature in D to support this, i'd advocate a simple
 class that contains the needed operators called 'Epsilon'.  
 Combine this with D's 'with' syntax and you get something that's pretty useful.
<snip> Hmm.... Stewart.
Oct 15 2004
prev sibling parent "Ben Hinkle" <bhinkle mathworks.com> writes:
"nail" <nail_member pathlink.com> wrote in message
news:ckm51l$2kfr$1 digitaldaemon.com...
 What if there will some additional operators for float comparement? E.g
==~ <~
~ etc. Because of floats nature it is very often we have to use
constructions like
 if (equal(firstVector3, secondVector3))
 {
 }

 or

 if (greater_equal(float1, float2))
 {
 }

 Definition of this functions is very simple and as a rule wraps to
comparement
 difference of operants with float.epsilon. But I think it is very annoying
to
 use this method very often, even more usual operators like ==, <= are used
 rarely then a approximal comparement. Is this necessary, how do u think?
There are two problems with defining an "approximate equality" operator: 1) precision: what exactly is the tolerance for testing approximate equality? 2) absolute vs relative: how is the approximate value measured? For example, 1e-10 and 1e-11 might be considered approximately equal since they are close to zero but if your data is all very small anyway then 1e-10 and 1e-11 might be very far apart for the particular application. Given these complications I don't think a builtin operator would be sufficient. Measuring against eps is by itself not good enough since eps is meaningful near 1.0 and differences in floating point numbers with maginitutes in the 1000's won't be anywhere close to eps. A user-defined function (or some functions in std.math perhaps) would be good enough. -Ben
Oct 14 2004