Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Groovy perform floating point arithmetic this way?

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?

like image 573
kschmit90 Avatar asked Jan 07 '15 20:01

kschmit90


People also ask

What do you mean by floating point arithmetic?

In computing, floating-point arithmetic (FP) is arithmetic using formulaic representation of real numbers as an approximation to support a trade-off between range and precision.

What is floating point arithmetic in Java?

Floating-point numbers are used to represent numbers that have a decimal point in them (such as 5.3 or 99.234). Whole numbers can also be represented, but as a floating point, the number 5 is actually 5.0. In Java, floating-point numbers are represented by the types float and double.

Why is floating point broken?

The main cause of the error in floating point division is the division algorithms used to calculate the quotient. Most computer systems calculate division using multiplication by an inverse, mainly in Z=X/Y , Z = X * (1/Y) .


1 Answers

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.

like image 161
cfrick Avatar answered Sep 29 '22 13:09

cfrick