1

Possible Duplicate:
Moving decimal places over in a double

I am having this weird problem in Java, I have following code:

double velocity = -0.07;
System.out.println("raw value  " + velocity*200 );
System.out.println("floored value  " + Math.floor(velocity*200) );

I have following output:

raw value  -14.000000000000002
floored value  -15.0

Those traling 0002 screw everything up, and BTW there should not be that traling 2, I think it should be all zeroes after decimal point, can I get rid of that 2?

Update: Thanks for help, Guys do you know any way to make floor rounding on BigDecimal object without calling doubleValue method?

Community
  • 1
  • 1
Rustam Issabekov
  • 2,621
  • 6
  • 22
  • 31

4 Answers4

4

Because floor(-14.000000000000002) is indeed -15!

You see, floor is defined as the maximal whole number less or equal to the argument. As -14.000000000000002 is not a whole number, the closest whole number downwards is -15.

Well, now let's clear why -0.07 * 200 is not exactly -14. This is because the inner representation of floating-point numbers is in base 2, so the fractions where the denominator is not a power of 2 cannot be represented with 100% precision. (The same way as you cannot represent 1/3 as the decimal fraction with finite amount of decimal places.) So, the value of velocity is not exactly -0.07. (When the compiler sees the constant -0.07, it silently replaces it with a binary fraction which is quite close to -0.07, but not actually equal to.) This is why velocity * 200 is not exactly -14.

Vlad
  • 33,616
  • 5
  • 74
  • 185
3

From The Floating-Point Guide:

Why don’t my numbers, like 0.1 + 0.2 add up to a nice round 0.3, and instead I get a weird result like 0.30000000000000004?

Because internally, computers use a format (binary floating-point) that cannot accurately represent a number like 0.1, 0.2 or 0.3 at all.

When the code is compiled or interpreted, your “0.1” is already rounded to the nearest number in that format, which results in a small rounding error even before the calculation happens.

If you need numbers that exactly add up to specific expected values, you cannot use double. Read the linked-to site for details.

Michael Borgwardt
  • 327,225
  • 74
  • 458
  • 699
2

Use BigDecimal... The problem above is a well-known rounding problem with the representation schemes used on a computer with finite-memory. The problem is that the answer is repetitive in the binary (that is, base 2) system (i.e. like 1/3 = 0.33333333... with decimal) and cannot be presented correctly. A good example of this is 1/10 = 0.1 which is 0.000110011001100110011001100110011... in binary. After some point the 1s and 0s have to end, causing the perceived error.

Hope you're not working on life-critical stuff... for example http://www.ima.umn.edu/~arnold/disasters/patriot.html. 28 people lost their lives due to a rounding error.

Jaco Van Niekerk
  • 3,894
  • 2
  • 18
  • 41
  • 2
    I didn't downvote, but you might want to fix your wording: There's a difference between "irrational" and "not exactly representable". – Mysticial May 15 '12 at 13:48
  • 2
    The problem has absolutely nothing to do with Java – Michael Borgwardt May 15 '12 at 13:49
  • 1
    No, that number is not irrational, it is a simple rational value :-) And the rounding issue is general to floating point arithmetic, not specific to Java. – Péter Török May 15 '12 at 13:49
  • 1
    The problem isn't with 'computers' either. It has to do with IEEE754 representation of floating point numbers. – eljenso May 15 '12 at 13:54
  • I can use BigDecimal, but then again I still need to do floor rounding and to do it I need to get double value, is there any floor rounding operating on BigDecimals? – Rustam Issabekov May 15 '12 at 14:17
  • Go to google. Type in "BigDecimal floor" and click on the first link. It explains all the possible rounding you could possibly want. – Jaco Van Niekerk May 15 '12 at 14:20
1

Java doubles follow the IEEE 754 floating-point arithmetic, which can't represent every single real number with infinite accuracy. This round up is normal. You can't get rid of it in the internal representation. You can of course use String.format to print the result.

kgiannakakis
  • 96,871
  • 26
  • 155
  • 191