www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - float equality

reply spir <denis.spir gmail.com> writes:
Hello,

What do you think of this?

unittest {
     assert(-1.1 + 2.2 == 1.1);          // pass
     assert(-1.1 + 2.2 + 3.3 == 4.4);    // pass
     assert(-1.1 + 3.3 + 2.2 == 4.4);    // fail
     assert(-1.1 + 3.3 == 2.2);          // fail
}

There is approxEquals in stdlib, right; but shouldn't builtin "==" be 
consistent anyway?

Denis
-- 
_________________
vita es estrany
spir.wikidot.com
Feb 19 2011
next sibling parent Simon Buerger <krox gmx.net> writes:
On 19.02.2011 13:06, spir wrote:
 Hello,

 What do you think of this?

 unittest {
 assert(-1.1 + 2.2 == 1.1); // pass
 assert(-1.1 + 2.2 + 3.3 == 4.4); // pass
 assert(-1.1 + 3.3 + 2.2 == 4.4); // fail
 assert(-1.1 + 3.3 == 2.2); // fail
 }

 There is approxEquals in stdlib, right; but shouldn't builtin "==" be
 consistent anyway?

 Denis
It is generally a bad idea to use "==" with floats, as most decimals cant be represented exact in binary floating point. That means there is no float for the value "1.1". Though there are exact floats for 0.25, 0.5, 42.125 and so on. The only reason the first two testcases work is, that it is rounded the same way both sides of the "==" but you should not rely on that. Also note, that these calculations are probably done at compile-time, and the compiler is allowed to use a higher precision than at run-time, so you might get different result when you let the user input the numbers. - Krox
Feb 19 2011
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter:

 There's a total lack of evidence for that.
MISRA-C standard disallows the equality among FP values. I presume they have some serious evidence for their choices, but I don't know such evidence. Today MISRA-C is one of the most serious attempts at fixing the holes in C language to write more reliable code for the industry. MISRA-C standard is sometimes extreme and I don't suggest to follow everything they say, but I suggest to not totally ignore what it says about many C features.
 1. Roundoff error is not of a fixed magnitude.
I meant to replace the nude FP equality with a function that has the shared number of mantissa bits as third required argument. And then perform the normal FP equality using the "is" operator. Regarding FP rounding errors, eventually it will be good to add to Phobos2 a library for Interval FP arithmetic, with trigonometric functions too, etc: http://en.wikipedia.org/wiki/Interval_arithmetic Bye, bearophile
Feb 20 2011
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
bearophile wrote:
 There's a total lack of evidence for that.
MISRA-C standard disallows the equality among FP values. I presume they have some serious evidence for their choices, but I don't know such evidence. Today MISRA-C is one of the most serious attempts at fixing the holes in C language to write more reliable code for the industry. MISRA-C standard is sometimes extreme and I don't suggest to follow everything they say, but I suggest to not totally ignore what it says about many C features.
MISRA is not suggesting having the language silently default to approximate equality.
Feb 20 2011
parent bearophile <bearophileHUGS lycos.com> writes:
Walter:

 MISRA is not suggesting having the language silently default to approximate 
 equality.
Right. But I am not suggesting that, in what I have suggested there is nothing silent :-) Given: double x, y; I have suggested in D: x == y => syntax error. x is y => the same FP equality as today. some syntax(x, y, how_much_to_approximate) => approximate equality. Bye, bearophile
Feb 20 2011
prev sibling parent reply so <so so.so> writes:
On Sun, 20 Feb 2011 14:53:03 +0200, bearophile <bearophileHUGS lycos.com>  
wrote:

 Walter:

 There's a total lack of evidence for that.
MISRA-C standard disallows the equality among FP values. I presume they have some serious evidence for their choices, but I don't know such evidence. Today MISRA-C is one of the most serious attempts at fixing the holes in C language to write more reliable code for the industry. MISRA-C standard is sometimes extreme and I don't suggest to follow everything they say, but I suggest to not totally ignore what it says about many C features.
 1. Roundoff error is not of a fixed magnitude.
I meant to replace the nude FP equality with a function that has the shared number of mantissa bits as third required argument. And then perform the normal FP equality using the "is" operator.
I still think "==" should mean the exact equality test and must be consistent in language. Making something like almostEqual default is far more catastrophic than its current form. It doesn't solve the existing problem and create a basis for new form of problems. If one doesn't know what floating point is and insists on using it, it is his own responsibility to face the consequences.
 Regarding FP rounding errors, eventually it will be good to add to  
 Phobos2 a library for Interval FP arithmetic, with trigonometric  
 functions too, etc:
 http://en.wikipedia.org/wiki/Interval_arithmetic

 Bye,
 bearophile
If only interval arithmetic would solve all the problems, i wouldn't hesitate dumping everything about FP. But no, it comes with its shortcomings.
Feb 21 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
so:

 I still think "==" should mean the exact equality test and must be  
 consistent in language.
Everyone in this thread has misunderstood what I have tried to say, so I will try to explain again, see the bottom of this post. My idea was to turn the "==" operator among FP values into a syntax error (plus other added ideas).
 Making something like almostEqual default is far more catastrophic than  
 its current form.
This problem doesn't exists in my idea.
 It doesn't solve the existing problem and create a basis for new form of  
 problems.
The problems it creates are smaller.
 If one doesn't know what floating point is and insists on using it, it is  
 his own responsibility to face the consequences.
I don't buy this argument.
 If only interval arithmetic would solve all the problems, i wouldn't  
 hesitate dumping everything about FP.
 But no, it comes with its shortcomings.
I agree that interval arithmetic has its downsides. I have not proposed to replace normal floating point values with intervals. I have suggested to add a Phobos module for interval arithmetic because it's a useful thing to have. --------------------- The little proposal I was thinking about is: 1) Turn the "==" operator into a compile-time syntax error if one or both operands are floating point values. if (x == y) { ==> syntax error 2) The semantic of the "==" is now done by the "is" operator. So if you want exactly this C code: if (x == y) { you use: if (x is y) { 3) Then another built-in function or semantics is added, that is similar to: some_syntax(x, y, an_approximation_level) It takes tree arguments: x, y and a number of bits. Turning the == into a syntax error is done to remember programmers that == among FP values is tricky, and the "is" operator is added because there are some situations where you want an exact comparison and you know what you are doing. This was my idea. I know it doesn't improve the current situation a lot... so I don't expect this to be accepted. But I like to be understood :-) Bye, bearophile
Feb 21 2011
parent reply so <so so.so> writes:
 If one doesn't know what floating point is and insists on using it, it  
 is
 his own responsibility to face the consequences.
I don't buy this argument.
Why not? A logical flaw on my part or the statement being somewhat harsh? Because i don't think it is the former, i will give an example for the latter. I am a self-taught programmer and i too made big mistakes when using FP, probably i still do since it is a strange beast to deal with even if you know all about it. For this reason it is somewhat understandable for people like me failing this kind of traps but can we say same thing for others? Do they have this excuse? Not knowing the fundamental thing about FP and use it?
 The little proposal I was thinking about is:

 1) Turn the "==" operator into a compile-time syntax error if one or  
 both operands are floating point values.
 if (x == y) { ==> syntax error

 2) The semantic of the "==" is now done by the "is" operator.
 So if you want exactly this C code:
 if (x == y) {
 you use:
 if (x is y) {

 3) Then another built-in function or semantics is added, that is similar  
 to:
 some_syntax(x, y, an_approximation_level)
 It takes tree arguments: x, y and a number of bits.

 Turning the == into a syntax error is done to remember programmers that  
 == among FP values is tricky, and the "is" operator is added because  
 there are some situations where you want an exact comparison and you  
 know what you are doing.

 This was my idea. I know it doesn't improve the current situation a  
 lot... so I don't expect this to be accepted. But I like to be  
 understood :-)

 Bye,
 bearophile
One thing i fail to understand here is, yes i agree "float == float" probably a "code smell" and we can find a workaround for this. But i have to ask, where does it stop? I mean i can just here find you pages and pages of illogical results created with crafted examples using not even floating points but integrals. If you want to make it easier like the case in hand, ignore a fundamental rule and you get tons of examples. All i am trying to say is that if we are not in a position to solve this huge problem with a syntax change, lets just keep it the way it is instead of making yet another inconsistency.
Feb 21 2011
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
so:

 Why not?
A system language has to allow the programmer to do everything the hardware is capable to do, including comparing floats in the usual way. But in general for a well designed language it's better to clearly denote dangerous/unsafe/bad things, and to make the safer routes the first ones you usually try.
 where does it stop?
I don't know, I am here to learn this too. You have languages like Assembly, SPARK, ATS. They are successful in their niche and for their purposes. They are at the (current) opposites for safety, control, freedom, power, performance, etc. In the area that has those tree languages as vertices (and there are many more possible vertices to choose from) there is a lot of design space for good languages. Bye, bearophile
Feb 21 2011
prev sibling parent spir <denis.spir gmail.com> writes:
On 02/21/2011 10:17 PM, so wrote:
 If one doesn't know what floating point is and insists on using it, it is
 his own responsibility to face the consequences.
I don't buy this argument.
Why not? A logical flaw on my part or the statement being somewhat harsh? Because i don't think it is the former, i will give an example for the latter. I am a self-taught programmer and i too made big mistakes when using FP, probably i still do since it is a strange beast to deal with even if you know all about it. For this reason it is somewhat understandable for people like me failing this kind of traps but can we say same thing for others? Do they have this excuse? Not knowing the fundamental thing about FP and use it?
I understand your position. But I don't share it. The problem is binary floating point representations of numbers introduce a little set of traps due to the fact that they are implicitely supposed to be the type representing "fractional" or real numbers, but they cannot do that in a way that matches our (widely unconscious) intuitions in the domain, themselves (I guess) a by-product of years of manipulation at school. The simple notation "1.1" comes with a huge baggage of pre-existing knowledge by everyone (programmers). We should not blindly make abstraction of that fact, and put the burden on the users' shoulders, without even a honest trial in solving the issue. When a programmer writes: x = 1.1; or x = 1/3.0; the meaning is just that, and refers to all this knowledge. There is in most cases no intention (not even implicite) to use binary floating point numbers, instead to have a representation for the plain arithmetics values as written down. Hope I'm clear. Very few people (ones that have repetedly been caught by the conceptual traps) will have "alarm bell" ring when writing this, and consequently take all appropriate precautions required to avoid subsequenty falling into the traps and... have buggy code. This may be a bit different if the notation did not recall all of that knowledge: x = 1.1f; // alarm bell!? I would advocate that a general-purpose language should use a different representation for ordinary need of fractional/real numbers, one that does not introduce such traps and/or warns about them (via warnongs/errors, like Bearophile's proposal). One possibility may be to use fixed point with a /decimal/ scale factor (the mantissa beeing binary or decimal integer). Other possibilities: true rationals, decimal 'reals'. The issue is indeed any of those solutions has a cost (even more with modern machines having native float artithmetic). But numeric computation intensive apps would just use floats, /explicitely/ (and hopefully correctly). A similar issue is the one of signed <--> unsigned ints. I would just make as default the range of unsigned ints be a subset of signed ones. And let the full range available for people who really need it, to be used explicitely. Anyway, such solutions may not be good for D, beeing (also) a systems programming language in the C line. Still, I think it's worth exploring the topic instead of letting bug-prone features silently sit at the deep core of the language. Denis -- _________________ vita es estrany spir.wikidot.com
Feb 22 2011
prev sibling next sibling parent reply Kagamin <spam here.lot> writes:
bearophile Wrote:

 Jonathan M Davis:
 
 The thing is, of course, that actual equality sucks for floating point values. 
So much, that some people have proposed to deprecate the normal FP equality. MISRA-C disallows them. When you see a == among FP values is often a code smell.
Is it safe to assert that noone needs exact FP comparison?
Feb 21 2011
parent "Robert Jacques" <sandford jhu.edu> writes:
On Mon, 21 Feb 2011 10:15:28 -0500, Kagamin <spam here.lot> wrote:

 bearophile Wrote:

 Jonathan M Davis:

 The thing is, of course, that actual equality sucks for floating  
point values. So much, that some people have proposed to deprecate the normal FP equality. MISRA-C disallows them. When you see a == among FP values is often a code smell.
Is it safe to assert that noone needs exact FP comparison?
Nope. if(var == 0) is a common, important and valid test. To say nothing of testing for sentinel values.
Feb 21 2011
prev sibling parent so <so so.so> writes:
On Sat, 19 Feb 2011 14:06:38 +0200, spir <denis.spir gmail.com> wrote:

 Hello,

 What do you think of this?

 unittest {
      assert(-1.1 + 2.2 == 1.1);          // pass
      assert(-1.1 + 2.2 + 3.3 == 4.4);    // pass
      assert(-1.1 + 3.3 + 2.2 == 4.4);    // fail
      assert(-1.1 + 3.3 == 2.2);          // fail
 }

 There is approxEquals in stdlib, right; but shouldn't builtin "==" be  
 consistent anyway?

 Denis
Strange no one mentioned this. Problem is not the floating point format in your example. I can do the same with integral numbers, how? int(5) / int(2) => int(2) or int(3)? And why? Answer depends on the rounding mode, if you don't know the given rounding mode for a (machine interpreted) number system you can't say anything. You know the answer because you know the rule. I can say same for the floating points since i know how they work.
Feb 21 2011