I'm trying to floor (not round!) doubles to two digits in a Java application. I use DecimalFormat
for this, but noticed that for negative values close to zero, the values are not rounded to -0.01
but to -0.00
.
public class MyTest {
void formatAndPrint(double value) {
DecimalFormat df = new DecimalFormat("0.00");
df.setRoundingMode(RoundingMode.FLOOR);
System.out.println(value + " => " + df.format(value));
}
@Test
public void testFloor() {
formatAndPrint(2.3289); // 2.32
formatAndPrint(2.3); // 2.30
formatAndPrint(-1.172); // -1.18
formatAndPrint(0.001); // 0.00
formatAndPrint(0.0001); // 0.00
formatAndPrint(-0.001); // -0.01
formatAndPrint(-0.0001); // -0.00 WRONG, expected: -0.01
}
}
Other solutions like Math.floor(value * 100.0) / 100.0
does not have this issue but has other issues, like wrongly flooring 2.3
to 2.29
.
Is there a flooring solution for Java which works in all cases?
format(“%. 2f”) We also can use String formater %2f to round the double to 2 decimal places.
The number of decimal places in a double is 16.
Java Math floor() floor() method with the help of examples. The floor() method rounds the specified double value downward and returns it. The rounded value will be equal to a mathematical integer. That is, the value 3.8 will be rounded to 3.0 which is equal to integer 3.
The BigDecimal implementation works fine.
BigDecimal value = new BigDecimal(-0.0001);
value = value.setScale(2, BigDecimal.ROUND_FLOOR);
System.out.println(value.toPlainString());
Output: -0.01
2.3
will still floor to 2.29
. This is not a result of the flooring, but instead the result of writing 2.3
as double. The closest 64-Bit IEEE754 representation of 2.3 is 2.29999...
When instantiating the BigDecimal you can instead provide a String like new BigDecimal("2.3")
which will not result in such errors.
BigDecimal.valueOf()
instead, which will call Double.toString()
for instantiation. Double.toString()
does not use the exact value of the double
but will instead "round" to the closest unique value.
Double
JavaDoc:
There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type double.
Here is a small table of long values (used with Double.longBitsToDouble(long)
and their BigDecimal
and Double.toString()
counterparts:
long value Double.toString() new BigDecimal()
4612361558371493473 - 2.2999999999999976 - 2.299999999999997601918266809661872684955596923828125
4612361558371493474 - 2.299999999999998 - 2.29999999999999804600747665972448885440826416015625
4612361558371493475 - 2.2999999999999985 - 2.299999999999998490096686509787105023860931396484375
4612361558371493476 - 2.299999999999999 - 2.2999999999999989341858963598497211933135986328125
4612361558371493477 - 2.2999999999999994 - 2.299999999999999378275106209912337362766265869140625
4612361558371493478 - 2.3 - 2.29999999999999982236431605997495353221893310546875
4612361558371493479 - 2.3000000000000003 - 2.300000000000000266453525910037569701671600341796875
4612361558371493480 - 2.3000000000000007 - 2.300000000000000710542735760100185871124267578125
4612361558371493481 - 2.300000000000001 - 2.300000000000001154631945610162802040576934814453125
4612361558371493482 - 2.3000000000000016 - 2.30000000000000159872115546022541821002960205078125
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With