5

Trying out floating point arithmetic in Groovy. Have no idea why/how/what groovy is doing behind the scenes to cause these different types of behaviors?

double point2 = 0.2
double point1 = 0.1
double point3 = 0.3

assert point2 + point1 == point3 // false, as expected
   |      | |      |  |
   0.2    | 0.1    |  0.3
          |        false
          0.30000000000000004    

float point2 = 0.2
float point1 = 0.1
float point3 = 0.3

assert point2 + point1 == point3 // false, as expected
   |      | |      |  |
   0.2    | 0.1    |  0.3
          |        false
          0.30000000447034836

def point2 = 0.2
def point1 = 0.1
def point3 = 0.3

assert point2 + point1 == point3 // this returns true  
assert 0.2 + 0.1 == 0.3 // this returns true

I thought it had to do with BigDecimal but then I tried this.

BigDecimal point2 = 0.2
BigDecimal point1 = 0.1
BigDecimal point3 = 0.3

float point4 = 0.4

assert point1 + point3 == point4
   |      | |      |  |
   0.1    | 0.3    |  0.4
          0.4      false

What is causing this behavior?

cfrick
  • 35,203
  • 6
  • 56
  • 68
kschmit90
  • 378
  • 2
  • 3
  • 13
  • possible duplicate of [Is floating point math broken?](http://stackoverflow.com/questions/588004/is-floating-point-math-broken) – tmyklebu Jan 07 '15 at 20:53
  • 2
    @tmyklebu no this is not duplicate of this question; while the first half would indicate that, as the asserts are phrased wrong, the question here is about the (implicit) type casts of groovy for "floaty" numbers. – cfrick Jan 07 '15 at 21:06
  • @cfrick: I see. You're right; this is about the type of an apparent floating-point literal. Please forgive my itchy trigger finger; I saw `0.1` and `0.2` and `0.3` and said "Oh God; not again." – tmyklebu Jan 07 '15 at 21:30

1 Answers1

5

your def:s there are BigDecimals

groovy:000> p1 = 0.1
===> 0.1
groovy:000> p1.getClass()
===> class java.math.BigDecimal

And equals fails for comparsion between BigDecimal and the native float/double

groovy:000> p1.equals(0.1f)
===> false
groovy:000> p1.equals(0.1)
===> true
groovy:000> p1==0.1f
===> false
groovy:000> p1==0.1
===> true

Not sure yet, why == works for [Dd]ouble.

groovy:000> p1.equals(0.1d)
===> false
groovy:000> p1==0.1d
===> true

My guess would be, that it's burried in DefaultTypeTransformation.compareToWithEqualityCheck. As both sides are Number:s.

cfrick
  • 35,203
  • 6
  • 56
  • 68
  • I figured that out and added more to the question. – kschmit90 Jan 07 '15 at 20:36
  • Okay, but why does equals fail for comparison between BigDecimal and native float/double? So I can compare a double to a BigDecimal but not a float? – kschmit90 Jan 07 '15 at 20:41
  • 3
    actually I think you found a bug. My assumption would be that the BigDecimal is wrongly converted to a double for the comparison. I opened http://jira.codehaus.org/browse/GROOVY-7238 to track this – blackdrag Jan 08 '15 at 02:36