How to truncate a BigDecimal without rounding
Asked Answered
B

6

47

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?

Blunk answered 17/6, 2014 at 20:36 Comment(1)
the Math.floor(VALUE) will return a int val, so why not do: (double)((double)Math.Floor(1.95*100)/(double)100)Navigable
B
84

Use either RoundingMode.DOWN or RoundingMode.FLOOR.

BigDecimal newValue = myBigDecimal.setScale(2, RoundingMode.DOWN);
Britneybritni answered 17/6, 2014 at 20:41 Comment(5)
new BigDecimal(4343.33).setScale(2, RoundingMode.DOWN) returns 4343.32Thankless
@Thankless 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)Britneybritni
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?Thankless
@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);Britneybritni
@Britneybritni 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.Hallelujah
B
13

Use the setScale override that includes RoundingMode:

value.setScale(2, RoundingMode.DOWN);
Blackwell answered 17/6, 2014 at 20:41 Comment(0)
V
10

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
Vendee answered 24/7, 2020 at 4:50 Comment(1)
11.238 -> 11.28 ?Heteromerous
K
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

Karyolysis answered 10/8, 2022 at 19:21 Comment(0)
S
1

Unfortunately, the accepted answer is wrong. It states to:

Use either RoundingMode.DOWN or RoundingMode.FLOOR

However, as stated in the documentation, RoundingMode.FLOOR rounds "towards negative infinity". The behaviour is further described in the documentation, saying that:

If the result is positive, behave as for RoundingMode.DOWN; if negative, behave as for RoundingMode.UP

A simple test to show how that behaviour is not truncating values is the following:

BigDecimal.valueOf(-1.009).setScale(2, RoundingMode.FLOOR));
// returns: -1.01, so NOT the truncated value of -1.00

The corrects answer is that you can ONLY use RoundingMode.DOWN, as it literally states in the documentation that this method:

Never increments the digit prior to a discarded fraction (i.e., truncates)

Stralsund answered 6/2, 2024 at 13:38 Comment(0)
G
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)). 
Glover answered 9/12, 2022 at 3:57 Comment(1)
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.Crigger

© 2022 - 2025 — McMap. All rights reserved.