1

I have a BigDecimal value of 123.45. I'd like to convert it to a long value of 12345 and I wonder what's the best way of doing this.

I'd rather avoid doing something like val.multiply(new BigDecimal(100)).toBigInteger()

Vargan
  • 1,277
  • 1
  • 11
  • 35
  • `Long.parseLong(bigDecimal.toString().replace(".", ""))` – Michael Sep 21 '20 at 11:58
  • `long times100 = new BigDecimal("123.45").multiply(new BigDecimal("100")).longValue();` – deHaar Sep 21 '20 at 11:59
  • 1
    @deHaar aha. I'd assumed `12.345` should have the same result. Guess the requirements are ambiguous – Michael Sep 21 '20 at 12:01
  • @Michael possible... OP would have to alter the multiplicator then... Not very elegant, I admit. – deHaar Sep 21 '20 at 12:02
  • Why do you want to avoid the multiplication? It's the fastest way to do this. – NomadMaker Sep 21 '20 at 12:03
  • It probably is, but I'd have problem in case my bigdecimal comes with more decimal points than I expect. And I don't particularly like string conversions – Vargan Sep 21 '20 at 12:05
  • 1
    @NomadMaker+ no it's not. `scaleByPowerOfTen` never needs to multiply, and `movePointRight(pos)` or `...Left(neg)` doesn't as long as you don't make the scale negative (then it clamps the scale and multiplies the significand, albeit using precomputed constants rather than needing to re-generate what is actually a constant). Also, using `BigDecimal.longValueExact` _sometimes_ avoids going through an actual `BigInteger`, which is also faster. Although probably not enough you can notice. – dave_thompson_085 Sep 21 '20 at 12:31
  • bigdecimal comes with more decimal points than I expect. - um, a BigDecimal can only ever contain one 'decimal point'. Did you mean: In case the digits after the separator are more or less than 2? This smells of currency. Generally, use a long to represent cents, all throughout the system, not a BD, but I guess you're stuck with this design. Definitely multiply by 100 and convert that, and work out for yourself how you want to deal with 15 bazillion trillion cents (i.e. something that exceeds the long bounds). – rzwitserloot Sep 21 '20 at 12:47
  • You don't like string conversions and you don't like math conversions. What's left? – WJS Sep 21 '20 at 12:55
  • @dave_thompson_085 , thanks, your answer it's what I was looking for. If you care to make it an answer I'll accept it as my preferred solution. – Vargan Sep 21 '20 at 13:08

2 Answers2

1

Use to string of BigDecimal and string replace the "." and do a Long.valueOf

Ed Bighands
  • 159
  • 8
1

Just posting this in case you want to know. Made a test for performances, as expected String replacement performed the worst.

results: movePointRight: 1230 multiply: 833 scaleByPowerOfTen: 591 String replacement: 3289

    BigDecimal val = new BigDecimal(0);
    long start = System.currentTimeMillis();
    for(int i = 0; i < 1000000; i++) {
        BigDecimal d = new BigDecimal(123.45);
        val = d.movePointRight(2);
    }
    long end = System.currentTimeMillis();
    System.out.println("movePointRight: " + (end - start));

    BigDecimal ten = new BigDecimal(10);
    start = System.currentTimeMillis();
    for(int i = 0; i < 1000000; i++) {
        BigDecimal d = new BigDecimal(123.45);
        val = d.multiply(new BigDecimal(100));
    }

    end = System.currentTimeMillis();
    System.out.println("multiply: " + (end - start));

    start = System.currentTimeMillis();
    for(int i = 0; i < 1000000; i++) {
        BigDecimal d = new BigDecimal(123.45);
        val = d.scaleByPowerOfTen(2);
    }

    start = System.currentTimeMillis();
    for(int i = 0; i < 1000000; i++) {
        BigDecimal d = new BigDecimal(123.45);
        val = d.scaleByPowerOfTen(2);
    }
    end = System.currentTimeMillis();
    System.out.println("scaleByPowerOfTen: " + (end - start));

    start = System.currentTimeMillis();
    for(int i = 0; i < 1000000; i++) {
        BigDecimal d = new BigDecimal(123.45);
        val =  new BigDecimal(d.toString().replace(".", ""));
    }
    end = System.currentTimeMillis();
    System.out.println("String replacement: " + (end - start));
Vargan
  • 1,277
  • 1
  • 11
  • 35
  • See https://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java – Michael Sep 21 '20 at 23:21