0

Take this code for example.

class Main {
  public static void main(String[] args) {
   int i = 41;
   long l = i*9/5;  //no explicit type casting required
   float f = i*9/5; //no explicit type casting required
   double d = i*9/5;    //no explicit type casting required
   double e = (double) i*9/5;
   System.out.println("Int value "+i);
   System.out.println("Long value "+l);
   System.out.println("Float value "+f);
   System.out.println("Double value "+d);
   System.out.println("Double value cast "+e);
  }
}

The target type is larger than the source type and hence no explicit casting is required but why is there a loss of precision? Why can't I get d and f as 73.8?

SDJ
  • 3,622
  • 1
  • 10
  • 30
Natty
  • 33
  • 1
  • 1
  • 8
  • 3
    Because you're doing integer math **first**, then converting to a floating point type. – markspace Dec 13 '18 at 21:30
  • 1
    `9/5` is `1`... – SLaks Dec 13 '18 at 21:31
  • 1
    just try `9.0/5.0`, at least for float and double (and still float and double do not have infinite precision) – user85421 Dec 13 '18 at 22:05
  • @CarlosHeuberger Your suggestion did help me in getting the desired result without type casting. Thanks. I want to know the cause of this behaviour. Why is there a loss of precision? Could you please help in making me understand that? – Natty Dec 14 '18 at 11:15
  • if both operands of division (or other operations) are integer, java does integer arithmetic, that means, the result is also integer so `9/5 == 0`. If any operand is double, double arithmetic is done: – user85421 Dec 14 '18 at 11:43
  • 1
    @CarlosHeuberger Shouldn't 9/5 = 1, in case of integer arithmetic? 9/5=1.8, taking only integer part will be 1. – Natty Dec 14 '18 at 16:08
  • yes, it is 1, but cannot change comment now – user85421 Dec 14 '18 at 17:50
  • @CarlosHeuberger How is double e = (double) i*9/5; different from double e = i*9.0/5.0;? Internally, is it the same? – Natty Dec 16 '18 at 19:27
  • not sure how they are compiled but I am pretty confident that the compiler writes the same bytecode in both cases: convert the integer value to double and use double literals for 9 and 5. – user85421 Dec 16 '18 at 20:52

1 Answers1

1

Technically what is happening here is not a loss of precision, but rather the use of the integer division.

Let's take the case of f: float f = i*9/5;

Because the multiplication and division operators have the same precedence and are left-associative, the statement is equivalent to: float f = (i*9)/5;

Because both i=41 and 9 are int-typed, the type of the resulting value is also an int (369). The next step in the evaluation is thus 369/5. Because the type of both operands is int, the interpretation of the / operator is to use integer division, which discards any fractional remainder. Because 369/5 = 73 + 4/5, the expression evaluates to 73, which is then converted to the float value 73.0 and assigned to f.

A very similar process happens for d, except that the final conversion of 73 is to a double value 73.0.

Note that although I included the intermediate steps in the evaluation, the left-associativity does not have an impact on the use of the integer division. float f = i*(9/5); results in f = 41.0.

SDJ
  • 3,622
  • 1
  • 10
  • 30