Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. Other Discussions
  3. Clever Code
  4. doubles a == b or not ?

doubles a == b or not ?

Scheduled Pinned Locked Moved Clever Code
csharphelpquestion
33 Posts 14 Posters 32 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R Offline
    R Offline
    Rudi Breedenraedt
    wrote on last edited by
    #1

    Well, actually this is not really a bug, but a very strange behavior of the .NET double type. I'll put it as a riddle and let you find it out ! Ok, if no one found it, I'll post the answer, over a couple of days, time to let you search... ;) Take the following method:

    public static string LittleTest(double a, double b)
    {
    double x = 5.0;

    if (a != b)
    	return "Try other values for a and b...";
    
    double xa = x / a;
    double xb = x / b;
    
    if (xa == xb)
    	return "Not yet right...";
    else
    	return "You've got it !!!";
    

    }

    For which values a and b will the method return "You've got it !!!" ???

    L P R 3 Replies Last reply
    0
    • R Rudi Breedenraedt

      Well, actually this is not really a bug, but a very strange behavior of the .NET double type. I'll put it as a riddle and let you find it out ! Ok, if no one found it, I'll post the answer, over a couple of days, time to let you search... ;) Take the following method:

      public static string LittleTest(double a, double b)
      {
      double x = 5.0;

      if (a != b)
      	return "Try other values for a and b...";
      
      double xa = x / a;
      double xb = x / b;
      
      if (xa == xb)
      	return "Not yet right...";
      else
      	return "You've got it !!!";
      

      }

      For which values a and b will the method return "You've got it !!!" ???

      L Offline
      L Offline
      Lost User
      wrote on last edited by
      #2

      Zero and negative zero

      S A M 3 Replies Last reply
      0
      • R Rudi Breedenraedt

        Well, actually this is not really a bug, but a very strange behavior of the .NET double type. I'll put it as a riddle and let you find it out ! Ok, if no one found it, I'll post the answer, over a couple of days, time to let you search... ;) Take the following method:

        public static string LittleTest(double a, double b)
        {
        double x = 5.0;

        if (a != b)
        	return "Try other values for a and b...";
        
        double xa = x / a;
        double xb = x / b;
        
        if (xa == xb)
        	return "Not yet right...";
        else
        	return "You've got it !!!";
        

        }

        For which values a and b will the method return "You've got it !!!" ???

        P Offline
        P Offline
        PIEBALDconsult
        wrote on last edited by
        #3

        Never... well virtually never, a wise developer would never trust it.

        R 1 Reply Last reply
        0
        • L Lost User

          Zero and negative zero

          S Offline
          S Offline
          supercat9
          wrote on last edited by
          #4

          How often is the handling of infinity and negative infinity actually useful? If x is the largest non-infinite positive float, the expression x+x+(-x)+(-x) could evaluate as positive infinity, negative infinity, zero, or NaN, depending upon the order of evaluation. In what sense would any value other than zero or NaN be meaningful?

          L P 2 Replies Last reply
          0
          • L Lost User

            Zero and negative zero

            A Offline
            A Offline
            akidan
            wrote on last edited by
            #5

            Correct. :) Here's another fun one.

            public static string NextTest(double a) {
            if (a != a && a.Equals(a))
            return "Correct!";
            else
            return "Not yet!";
            }

            Bonus points if you can explain the rationale for why it acts like this...

            L 1 Reply Last reply
            0
            • S supercat9

              How often is the handling of infinity and negative infinity actually useful? If x is the largest non-infinite positive float, the expression x+x+(-x)+(-x) could evaluate as positive infinity, negative infinity, zero, or NaN, depending upon the order of evaluation. In what sense would any value other than zero or NaN be meaningful?

              L Offline
              L Offline
              Lost User
              wrote on last edited by
              #6

              I don't know, I just pointed out that the values for A and B should be zero and negative zero (in any order) :) That expression, well, I guess I'd like to get 0 as the result, but the other results are reasonable as well - even if they aren't useful or meaningful.

              1 Reply Last reply
              0
              • A akidan

                Correct. :) Here's another fun one.

                public static string NextTest(double a) {
                if (a != a && a.Equals(a))
                return "Correct!";
                else
                return "Not yet!";
                }

                Bonus points if you can explain the rationale for why it acts like this...

                L Offline
                L Offline
                Lost User
                wrote on last edited by
                #7

                I'm guessing NaN, but let me test that first.. It would be because: NaN != NaN (definition of NaN), but the bit pattern and type are the same so NaN.Equals(NaN) Edit: ok tested, NaN works

                A 1 Reply Last reply
                0
                • L Lost User

                  I'm guessing NaN, but let me test that first.. It would be because: NaN != NaN (definition of NaN), but the bit pattern and type are the same so NaN.Equals(NaN) Edit: ok tested, NaN works

                  A Offline
                  A Offline
                  akidan
                  wrote on last edited by
                  #8

                  Correct, nice job. :) Basically, the IEEE definition of equality for floating points requires NaN != NaN (see here)... but the .NET definition of equality requires that a.Equals(a). (Otherwise, you'd never be able to get anything back out of a Dictionary if the key had a NaN in it). So floats and doubles have a special clause in their Equals operator that checks for NaN for this reason.

                  S J 2 Replies Last reply
                  0
                  • A akidan

                    Correct, nice job. :) Basically, the IEEE definition of equality for floating points requires NaN != NaN (see here)... but the .NET definition of equality requires that a.Equals(a). (Otherwise, you'd never be able to get anything back out of a Dictionary if the key had a NaN in it). So floats and doubles have a special clause in their Equals operator that checks for NaN for this reason.

                    S Offline
                    S Offline
                    supercat9
                    wrote on last edited by
                    #9

                    Is there anything that specifies that two NaN's will test equal to each other via the .Equals predicate? I recall one floating-point system where the bit value of a NaN would indicate which type of operation first produced an invalid value, so sqrt(-1) would yield one bit pattern while (0/0) would yield another. I would expect that if a variable holding a NaN is copied to another variable of the same precision, the two variables would be guaranteed to compare .Equals, but that wouldn't imply that all NaN's are equal. Do you know what actual rules exist?

                    L A 2 Replies Last reply
                    0
                    • S supercat9

                      Is there anything that specifies that two NaN's will test equal to each other via the .Equals predicate? I recall one floating-point system where the bit value of a NaN would indicate which type of operation first produced an invalid value, so sqrt(-1) would yield one bit pattern while (0/0) would yield another. I would expect that if a variable holding a NaN is copied to another variable of the same precision, the two variables would be guaranteed to compare .Equals, but that wouldn't imply that all NaN's are equal. Do you know what actual rules exist?

                      L Offline
                      L Offline
                      Luc Pattyn
                      wrote on last edited by
                      #10

                      Hi, AFAIK there are many bit patterns that get interpreted as NaN, hence when a and b are NaN then a.Equals(b) can evaluate either true or false. :)

                      Luc Pattyn [Forum Guidelines] [My Articles]


                      - before you ask a question here, search CodeProject, then Google - the quality and detail of your question reflects on the effectiveness of the help you are likely to get - use the code block button (PRE tags) to preserve formatting when showing multi-line code snippets


                      1 Reply Last reply
                      0
                      • S supercat9

                        Is there anything that specifies that two NaN's will test equal to each other via the .Equals predicate? I recall one floating-point system where the bit value of a NaN would indicate which type of operation first produced an invalid value, so sqrt(-1) would yield one bit pattern while (0/0) would yield another. I would expect that if a variable holding a NaN is copied to another variable of the same precision, the two variables would be guaranteed to compare .Equals, but that wouldn't imply that all NaN's are equal. Do you know what actual rules exist?

                        A Offline
                        A Offline
                        akidan
                        wrote on last edited by
                        #11

                        Yes - here are the rules laid out by the ECMA CLI standard. For ==:

                        3.21 ceq
                        The ceq instruction compares value1 and value2. If value1 is equal to value2, then 1 (of
                        type int32) is pushed on the stack. Otherwise, 0 (of type int32) is pushed on the stack.
                        For floating-point numbers, ceq will return 0 if the numbers are unordered (either or both
                        are NaN). The infinite values are equal to themselves.

                        For Object.Equals(Object):

                        8.2.5.2 Equality

                        For value types, the equality operator is part of the definition of the exact type.
                        Definitions of equality should obey the following rules:

                        • Equality should be an equivalence operator, as defined above.
                        • Identity should imply equality, as stated earlier.
                        • If either (or both) operand is a boxed value, equality should be computed by
                        o first unboxing any boxed operand(s), and then
                        o applying the usual rules for equality on the resulting values.

                        Equality is implemented on System.Object via the Equals method.

                        [Note: Although two floating point NaNs are defined by IEC 60559:1989 to always compare
                        as unequal, the contract for System.Object.Equals requires that overrides must satisfy
                        the requirements for an equivalence operator. Therefore, System.Double.Equals and
                        System.Single.Equals return True when comparing two NaNs, while the equality operator
                        returns False in that case, as required by the IEC standard. end note]

                        Unfortunately, as far as bit patterns are concerned with NaN... things get much more vague. It's good in some sense because it means you don't really have to deal with it on the bit pattern level, though. As long as you stay within a precision, you can pretty safely assume NaN is NaN in .NET.:

                        12.1.3 Handling of floating-point data types

                        Floating-point calculations shall be handled as described in IEC 60559:1989. This standard
                        describes encoding of floating-point numbers, definitions of the basic operations and
                        conversion, rounding control, and exception handling.

                        The standard defines special values, NaN, (not a number), +infinity, and –infinity. These
                        values are returned on overflow conditions. A general principle is that operations that
                        have a value in the limit return an appropriate infinity while those that have no limiting
                        value return NaN (see the standard for details).

                        [Note: The following examples show the most commonly encountered cases.
                        X rem 0 = NaN
                        0 * +infinity = 0 * -infinity = NaN
                        (X / 0) = +infinity, if X > 0
                        NaN, if X = 0
                        infinity, if X < 0
                        NaN op X = X op

                        D 1 Reply Last reply
                        0
                        • A akidan

                          Yes - here are the rules laid out by the ECMA CLI standard. For ==:

                          3.21 ceq
                          The ceq instruction compares value1 and value2. If value1 is equal to value2, then 1 (of
                          type int32) is pushed on the stack. Otherwise, 0 (of type int32) is pushed on the stack.
                          For floating-point numbers, ceq will return 0 if the numbers are unordered (either or both
                          are NaN). The infinite values are equal to themselves.

                          For Object.Equals(Object):

                          8.2.5.2 Equality

                          For value types, the equality operator is part of the definition of the exact type.
                          Definitions of equality should obey the following rules:

                          • Equality should be an equivalence operator, as defined above.
                          • Identity should imply equality, as stated earlier.
                          • If either (or both) operand is a boxed value, equality should be computed by
                          o first unboxing any boxed operand(s), and then
                          o applying the usual rules for equality on the resulting values.

                          Equality is implemented on System.Object via the Equals method.

                          [Note: Although two floating point NaNs are defined by IEC 60559:1989 to always compare
                          as unequal, the contract for System.Object.Equals requires that overrides must satisfy
                          the requirements for an equivalence operator. Therefore, System.Double.Equals and
                          System.Single.Equals return True when comparing two NaNs, while the equality operator
                          returns False in that case, as required by the IEC standard. end note]

                          Unfortunately, as far as bit patterns are concerned with NaN... things get much more vague. It's good in some sense because it means you don't really have to deal with it on the bit pattern level, though. As long as you stay within a precision, you can pretty safely assume NaN is NaN in .NET.:

                          12.1.3 Handling of floating-point data types

                          Floating-point calculations shall be handled as described in IEC 60559:1989. This standard
                          describes encoding of floating-point numbers, definitions of the basic operations and
                          conversion, rounding control, and exception handling.

                          The standard defines special values, NaN, (not a number), +infinity, and –infinity. These
                          values are returned on overflow conditions. A general principle is that operations that
                          have a value in the limit return an appropriate infinity while those that have no limiting
                          value return NaN (see the standard for details).

                          [Note: The following examples show the most commonly encountered cases.
                          X rem 0 = NaN
                          0 * +infinity = 0 * -infinity = NaN
                          (X / 0) = +infinity, if X > 0
                          NaN, if X = 0
                          infinity, if X < 0
                          NaN op X = X op

                          D Offline
                          D Offline
                          Dan Neely
                          wrote on last edited by
                          #12

                          Good info, but when pasting docs into a pre block you really need to insert manual linebreaks. That's going to horizontal scroll on anything less than a dual 30" setup.

                          Today's lesson is brought to you by the word "niggardly". Remember kids, don't attribute to racism what can be explained by Scandinavian language roots. -- Robert Royall

                          A 1 Reply Last reply
                          0
                          • D Dan Neely

                            Good info, but when pasting docs into a pre block you really need to insert manual linebreaks. That's going to horizontal scroll on anything less than a dual 30" setup.

                            Today's lesson is brought to you by the word "niggardly". Remember kids, don't attribute to racism what can be explained by Scandinavian language roots. -- Robert Royall

                            A Offline
                            A Offline
                            akidan
                            wrote on last edited by
                            #13

                            Oops, sorry about that. I've fixed the offending blocks.. I think.

                            1 Reply Last reply
                            0
                            • S supercat9

                              How often is the handling of infinity and negative infinity actually useful? If x is the largest non-infinite positive float, the expression x+x+(-x)+(-x) could evaluate as positive infinity, negative infinity, zero, or NaN, depending upon the order of evaluation. In what sense would any value other than zero or NaN be meaningful?

                              P Offline
                              P Offline
                              peterchen
                              wrote on last edited by
                              #14

                              SHouldn't it end up as NaN no matter what execution order is?

                              Burning Chrome ^ | Linkify!| FoldWithUs! | sighist

                              S 1 Reply Last reply
                              0
                              • P peterchen

                                SHouldn't it end up as NaN no matter what execution order is?

                                Burning Chrome ^ | Linkify!| FoldWithUs! | sighist

                                S Offline
                                S Offline
                                supercat9
                                wrote on last edited by
                                #15

                                peterchen wrote:

                                SHouldn't it end up as NaN no matter what execution order is?

                                The expression I gave was x+x+(-x)+(-x). (((x+x)-x)-x) should yield positive infinity (inf-x is inf) (x+(x-(x+x))) should yield negative infinity (-inf+x is -inf) (x+x)-(x+x) should yield NaN (inf + -inf is NaN) x+(x-x)-x should yield zero (no overflows anyplace).

                                P 1 Reply Last reply
                                0
                                • P PIEBALDconsult

                                  Never... well virtually never, a wise developer would never trust it.

                                  R Offline
                                  R Offline
                                  realJSOP
                                  wrote on last edited by
                                  #16

                                  A wise developer would never compare a double or float for equality without washing the data first.

                                  "Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997
                                  -----
                                  "...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001

                                  C 1 Reply Last reply
                                  0
                                  • S supercat9

                                    peterchen wrote:

                                    SHouldn't it end up as NaN no matter what execution order is?

                                    The expression I gave was x+x+(-x)+(-x). (((x+x)-x)-x) should yield positive infinity (inf-x is inf) (x+(x-(x+x))) should yield negative infinity (-inf+x is -inf) (x+x)-(x+x) should yield NaN (inf + -inf is NaN) x+(x-x)-x should yield zero (no overflows anyplace).

                                    P Offline
                                    P Offline
                                    peterchen
                                    wrote on last edited by
                                    #17

                                    I am not sure how IEEE floats work, but inf-x=inf works only for finite x. inf-inf should in any case end up NaN, and no matter how this expression is evaluated, you will end up with that subexpression at one point, and once any operand is NaN, it should stick.


                                    I googled, here's what I came upon: scroll down to "special operations": Clickety[^]

                                    Burning Chrome ^ | Linkify!| FoldWithUs! | sighist

                                    S 1 Reply Last reply
                                    0
                                    • P peterchen

                                      I am not sure how IEEE floats work, but inf-x=inf works only for finite x. inf-inf should in any case end up NaN, and no matter how this expression is evaluated, you will end up with that subexpression at one point, and once any operand is NaN, it should stick.


                                      I googled, here's what I came upon: scroll down to "special operations": Clickety[^]

                                      Burning Chrome ^ | Linkify!| FoldWithUs! | sighist

                                      S Offline
                                      S Offline
                                      supercat9
                                      wrote on last edited by
                                      #18

                                      I should have said that the indicated mathematical expression could yield four different results depending upon the order in which the terms were grouped. If the expression is coded in a particular form, the language's standard rules of associativity will dictate how the terms are grouped, but if it is computed using something like a sum() method on a database field, such behavior would not be guaranteed. While it wouldn't seem particularly likely that an implementation would separately sum together the two positive terms and the two negative terms before adding the two sums, such an approach would generally yield better precision than adding everything in sequence.

                                      P 1 Reply Last reply
                                      0
                                      • S supercat9

                                        I should have said that the indicated mathematical expression could yield four different results depending upon the order in which the terms were grouped. If the expression is coded in a particular form, the language's standard rules of associativity will dictate how the terms are grouped, but if it is computed using something like a sum() method on a database field, such behavior would not be guaranteed. While it wouldn't seem particularly likely that an implementation would separately sum together the two positive terms and the two negative terms before adding the two sums, such an approach would generally yield better precision than adding everything in sequence.

                                        P Offline
                                        P Offline
                                        peterchen
                                        wrote on last edited by
                                        #19

                                        My point was that grouping doesn't matter if you define the arithmetics for special values correctly (Which the IEEE standard apparently does)

                                        Burning Chrome ^ | Linkify!| FoldWithUs! | sighist

                                        S 1 Reply Last reply
                                        0
                                        • P peterchen

                                          My point was that grouping doesn't matter if you define the arithmetics for special values correctly (Which the IEEE standard apparently does)

                                          Burning Chrome ^ | Linkify!| FoldWithUs! | sighist

                                          S Offline
                                          S Offline
                                          supercat9
                                          wrote on last edited by
                                          #20

                                          Grouping very much does matter. Adding together the four items: +x, +x, -x, -x (where x is the the largest number short of infinity) If they are grouped as (+x + +x) + (-x + -x) the result will be (+inf) + (-inf), or NaN. If they are grouped as ((+x + +x) + -x) + -x the result will be (+inf + -x) + -x, or +inf + -x, or +inf. If they are grouped as +x + (+x + (-x + -x)) the result will be +x + (+x + -inf), or +x + -inf, or -inf. If they are grouped as (+x + (+x + -x)) + -x, the result will be (+x + 0) + -x, or +x + -x, or zero. With which of those statements do you disagree.

                                          P C 2 Replies Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • World
                                          • Users
                                          • Groups