24
 double d = 4.321562;

Is there an easy way to extract the 0.321562 on it's own from d? I tried looking in the math class but no luck. If this can be done without converting to string or casting to anything else, even better.

David
  • 15,652
  • 26
  • 115
  • 156

3 Answers3

32

Well, you can use:

double x = d - Math.floor(d);

Note that due to the way that binary floating point works, that won't give you exactly 0.321562, as the original value isn't exactly 4.321562. If you're really interested in exact digits, you should use BigDecimal instead.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 3
    Don't use this, make casting instead: `x - (int)x`. Casting will work correctly with both positive and negative numbers. Otherwise, `Math.floor()` will use "the most positive (closest to positive infinity) integer value less than or equal to the argument". Example: `-123.25 - (int)(-123.25)` will result in -0.25, so you can decide what to do with sign. Usage of `Math.floor()` will give positive of `0.75' – Dmitry Gryazin Dec 27 '15 at 18:35
  • 1
    @Bagzerg: Agreed, although casting to long would be better than casting to double, to handle values outside the range of int. Will edit to mention both when I get a chance. – Jon Skeet Dec 27 '15 at 19:19
28

Another way to get the fraction without using Math is to cast to a long.

double x = d - (long) d;

When you print a double the toString will perform a small amount of rounding so you don't see any rounding error. However, when you remove the integer part, the rounding is no longer enough and the rounding error becomes obvious.

The way around this is to do the rounding yourself or use BigDecimal which allows you to control the rounding.

double d = 4.321562;
System.out.println("Double value from toString " + d);
System.out.println("Exact representation " + new BigDecimal(d));
double x = d - (long) d;
System.out.println("Fraction from toString " + x);
System.out.println("Exact value of fraction " + new BigDecimal(x));
System.out.printf("Rounded to 6 places %.6f%n", x);
double x2 = Math.round(x * 1e9) / 1e9;
System.out.println("After rounding to 9 places toString " + x2);
System.out.println("After rounding to 9 places, exact value " + new BigDecimal(x2));

prints

Double value from toString 4.321562
Exact representation 4.321562000000000125510268844664096832275390625
Fraction from toString 0.3215620000000001
Exact value of fraction 0.321562000000000125510268844664096832275390625
Rounded to 6 places 0.321562
After rounding to 9 places toString 0.321562
After rounding to 9 places, exact value 0.32156200000000001448796638214844278991222381591796875

NOTE: double has limited precision and you can see representation issue creep in if you don't use appropriate rounding. This can happen in any calculation you use with double esp numbers which are not an exact sum of powers of 2.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 1
    This system fail if you have number greater than 32 example 32.59. The result of 31.59d - (long)31.59 is different than 32.59d - (long)32.59 – Hari Nov 20 '19 at 19:34
  • 1
    @Hari I have added a note on the need for appropriate rounding for any math using `double` – Peter Lawrey Dec 02 '19 at 13:30
10

Use modulo:

double d = 3.123 % 1;
assertEquals(0.123, d,0.000001);
Cedric Reichenbach
  • 8,970
  • 6
  • 54
  • 89