1

I have the following two calculation using Math.round(...):

double x = 0.57145732;
x = x * 100;
x = Math.round(x * 10);
x = x / 10;

If I now print the value of x it will show me: 57.1.

double x = 0.57145732;
x = (Math.round((x * 100) * 10)) / 10;
// x = (Math.round(x * 1000)) / 10; //Also gives me 57.0.

If I now print the value of x it will show me: 57.0.

Why is there this difference in the outcome?

Rob The Ranger
  • 389
  • 1
  • 3
  • 17
  • 3
    Math.round returns an int or long. This affects the calculation slightly. Floating point numbers are weird. – byxor Sep 05 '16 at 08:31
  • 1
    Because, floating point numbers, rounding, and such things ...are more complicated under the surface than one typically assumes?! Especially when mixing **double** and **float** (as you are doing when using Math.round()). – GhostCat Sep 05 '16 at 08:31
  • @Bob I just figured that out haha. Thanks, editing comment. (Silly me). – byxor Sep 05 '16 at 08:32
  • Sorry. Made a copy mistake. the floats should be doubles. (As in the original code). Going to change it in my example. – Rob The Ranger Sep 05 '16 at 08:33
  • Try to divide by 10.0 instead of 10 in order to get double instead of integer as outcome – Aboulfouz Sep 05 '16 at 08:41

4 Answers4

5

The Math.round() method returns an integer (of type long - as pointed out by Ole V.V). It's usually thought to return a float or double which gives rise to confusions as these.

In the second calculation,

Math.round((x * 100) * 10)

returns 571. Now, this value and 10 both are integers (571 is long, 10 is int). So when the calculation takes the form

x = 571 / 10

where x is double, 571/10 returns 57 instead of 57.1 since it is int. Then, 57 is converted to double and it becomes 57.0

If you do

x = (double)Math.round((x * 100) * 10) / 10.0;

its value becomes 57.1.


Edit: There are two versions of the Math.round() function. The one you used accepts a double (since x is double) and returns long. In your case, implicit type casting spares you the trouble of considering the precise little details.

progyammer
  • 1,498
  • 3
  • 17
  • 29
  • 1
    For the sake of precision, the overloaded version of Math.round() that accepts a double (which is the one used here) returns a long. It still has the value 571, so the argument holds all the way through. – Ole V.V. Sep 05 '16 at 09:04
  • @OleVV thanks for correcting me. – progyammer Sep 05 '16 at 11:39
2

The reason of the difference is that in the second formula you're making a division of two integer. in order to have the same result you have to add a cast to double:

double x = 0.57145732;
x = (double)(Math.round((x * 100) * 10)) / 10;
hasnae
  • 2,137
  • 17
  • 21
1

The difference is between

x = Math.round(571.45732) / 10;

and

x = Math.round(571.45732);
x = x / 10;

Since round(double) returns a long, in the first case you divide a long by an int, giving the long 57. Converting back to double leads to 57.0. The second case is equivalent to

x = ((double)Math.round(571.45732)) / 10;

where a double is divided by an int, resulting in 57.1.

Beethoven
  • 375
  • 1
  • 8
0

This because Math.round() returns an int. If you do this step-by-step (as in the first example), you assign the result of Math.round() to a float value. The following calculation uses then a float division.

In the second example, you let the JVM decide which types to use (and it uses an integer division as the intermediate step). This is why the precision gets lost.

SebastianK
  • 712
  • 4
  • 19