71

In Java, I'm working with the BigDecimal class and part of my code requires me to extract the fractional part from it. BigDecimal does not appear to have any built in methods to help me get the number after the decimal point of a BigDecimal.

For example:

BigDecimal bd = new BigDecimal("23452.4523434");

I want to extract the 4523434 from the number represented above. What's the best way to do it?

Franklin
  • 1,771
  • 3
  • 17
  • 35

4 Answers4

118

I would try bd.remainder(BigDecimal.ONE).

Uses the remainder method and the ONE constant.

BigDecimal bd = new BigDecimal( "23452.4523434" );
BigDecimal fractionalPart = bd.remainder( BigDecimal.ONE ); // Result:  0.4523434
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Taymon
  • 24,950
  • 9
  • 62
  • 84
  • 13
    @Franklin -- please un-accept my answer and instead accept Taymon's answer since it is cleaner and overall better than mine. 1+ to Taymon. – Hovercraft Full Of Eels Apr 06 '12 at 03:45
  • 11
    Current solution's code would return "0.4523434", not "4523434" as the author wanted. Some more moves will be required. – Pavel Vlasov Feb 20 '16 at 12:07
  • 4
    its important to get only the "4523434" in some cases , this answer dont return the correct result , should print the output as well. – diego matos - keke Apr 21 '16 at 20:17
  • 1
    For performance sensitive applications, I measured this to be quite slow. The equivalent `BigDecimal fractionalPart = bd.subtract(new BigDecimal(bd.toBigInteger()))` is about 50x - 80x faster depending on scale. – helospark May 15 '22 at 11:06
16

If the value is negative, using bd.subtract() will return a wrong decimal.

Use this:

BigInteger decimal = bd.remainder(BigDecimal.ONE).movePointRight(bd.scale()).abs().toBigInteger();

It returns 4523434 for 23452.4523434 or -23452.4523434


In addition, if you don't want extra zeros on the right of the fractional part, use:

bd = bd.stripTrailingZeros();

before the previous code.

IvanRF
  • 7,115
  • 5
  • 47
  • 71
  • 3
    While your code is correct formally, it is not in reality. Imagine the input is `BigDecimal("123.45").setScale(6)` then you will get `450000`. Hardly a useful result. – Pavel Vlasov Feb 20 '16 at 12:56
  • 1
    @PavelVlasov that number will still be fractional part, which is the original question. Every zero on the right of "fractional part" is useless, so `45` or `450000` are equal in this context. – IvanRF Feb 20 '16 at 15:06
  • 2
    @PavelVlasov to solve your case, apply `bd = bd.stripTrailingZeros();` before my code. – IvanRF Feb 20 '16 at 15:42
  • Thanks for the strip function. Btw, such code is useful when one need to spell numbers (cents). – Pavel Vlasov Mar 10 '16 at 11:16
  • 2
    Careful here! if you have "5.009" you will get "9" – Brais Gabin Aug 19 '21 at 13:38
7

Here's an alternative to using the remainder() method:

BigDecimal bd = new BigDecimal("23452.4523434");
BigDecimal fracBd = bd.subtract(new BigDecimal(bd.toBigInteger()));

Further, you can try the abs() method to ensure the fraction part is positive:

BigDecimal fracBd = bd.subtract(new BigDecimal(bd.toBigInteger())).abs();
shams
  • 3,460
  • 24
  • 24
6

It doesn't work!!!

BigDecimal d = BigDecimal.valueOf(23452.4523434);
BigInteger decimal = 
d.remainder(BigDecimal.ONE).movePointRight(d.scale()).abs().toBigInteger();

When you input number, which fractional-part starts with '0', for ex. "123.00456". You get "456" instead of "00456". It happens because we convert it .toBigInteger(), and the first zeros just gone; If you use .toString() instead of .toBigInteger(), you get 456.00000, it's wrong too!

So my advise is using this:

BigDecimal fractPart = bd.remainder(BigDecimal.ONE);
StringBuilder sb = new StringBuilder(fractPart.toString());
sb.delete(0, 2);
String str = sb.toString();

And then just use this str how you want

Jared Forth
  • 1,577
  • 6
  • 17
  • 32
MainS
  • 120
  • 1
  • 6