44

After a series of calculations in my code, I have a BigDecimal with value 0.01954

I then need to multiply this BigDecimal by 100 and I wish the calculated value to be 1.95

I do not wish to perform any rounding up or down, I just want any values beyond two decimal places to be truncated

I tried setting scale to 2, but then I got an ArithmeticException saying rounding is necessary. How can I set scale without specifying rounding?

Joel
  • 4,732
  • 9
  • 39
  • 54
DJ180
  • 18,724
  • 21
  • 66
  • 117
  • 1
    the `Math.floor(VALUE)` will return a int val, so why not do: `(double)((double)Math.Floor(1.95*100)/(double)100)` – Fallenreaper Jun 17 '14 at 20:41

5 Answers5

78

Use either RoundingMode.DOWN or RoundingMode.FLOOR.

BigDecimal newValue = myBigDecimal.setScale(2, RoundingMode.DOWN);
GriffeyDog
  • 8,186
  • 3
  • 22
  • 34
  • new BigDecimal(4343.33).setScale(2, RoundingMode.DOWN) returns 4343.32 – user666 Sep 13 '19 at 05:13
  • 4
    @user666 You are using the constructor that takes a floating point value, which can have rounding errors itself. Use the constructor that takes a `String` instead: `new BigDecimal("4343.33").setScale(2, RoundingMode.DOWN)` – GriffeyDog Sep 16 '19 at 15:31
  • 1
    that is correct, I tried it and it worked. But what if I have a bigDecimal object already existing? will it be treated like the string? – user666 Sep 17 '19 at 07:36
  • @San4musa Not true, you will get x.55. You can try it yourself: `BigDecimal myBigDecimal = new BigDecimal("5.5555555"); BigDecimal newValue = myBigDecimal.setScale(2, RoundingMode.DOWN); System.out.println(newValue);` – GriffeyDog Dec 06 '21 at 21:49
  • @GriffeyDog you are right, I messed up with HALF_DOWN , my comment can not be edited to I'm deleting the comment "RoundingMode.DOWN will fail if the value is x.5555555 as the truncating value is > 0.5 so it will round to x.56 if you use BigDecimal newValue = myBigDecimal.setScale(2, RoundingMode.DOWN); " This statement is true for HALF_DOWN not for DOWN mode. – San4musa Dec 07 '21 at 15:24
13

Use the setScale override that includes RoundingMode:

value.setScale(2, RoundingMode.DOWN);
user1676075
  • 3,056
  • 1
  • 19
  • 26
8

I faced an issue truncating when I was using one BigDecimal to set another. The source could have any value with different decimal values.

BigDecimal source = BigDecimal.valueOf(11.23); // could 11 11.2 11.234 11.20 etc

In order to truncate and scale this correctly for two decimals, I had to use the string value of the source instead of the BigDecimal or double value.

new BigDecimal(source.toPlainString()).setScale(2, RoundingMode.FLOOR))

I used this for currency and this always results in values with 2 decimal places.

  • 11 -> 11.00
  • 11.2 -> 11.20
  • 11.234 -> 11.23
  • 11.238 -> 11.23
  • 11.20 -> 11.20
Joe Taras
  • 15,166
  • 7
  • 42
  • 55
maheeka
  • 1,983
  • 1
  • 17
  • 25
1

BigDecimal.valueOf(7.777) .setScale(2, RoundingMode.DOWN) .stripTrailingZeros()

Result: 7.77

BigDecimal.valueOf(7.7) .setScale(2, RoundingMode.DOWN) .stripTrailingZeros()

Result: 7.7

BigDecimal.valueOf(77) .setScale(2, RoundingMode.DOWN) .stripTrailingZeros()

Result: 77

teja
  • 11
  • 3
0

As far as I tested rounding functions doesnt do the magic.What is a value comes as following amount.

BigDecimal val2 = new BigDecimal(45.9);
System.out.println(val2.setScale(2,RoundingMode.DOWN));

result; 45.89

Best thing is to cast from sql side or write a util function to multiply by 100 and pass to an Integer, again divide by hundred and pass to a BigDecimal.

In my case I used

sql:-  CAST(<VALUE> AS decimal(10,2)). 
Kandy
  • 1,067
  • 12
  • 29
  • Your first case fails because you use a double to create the `BigDecimal`. Plus, you use `setScale` to _add_ decimals which is the opposite of what the question asks. – Zastai Dec 12 '22 at 20:57