2

I have a Java BigDecimal expression like below:

(totalPrep.divide(totalCase, 2, BigDecimal.ROUND_HALF_UP)).multiply(new BigDecimal(100))

where

BigDecimal totalCase = BigDecimal.ZERO; BigDecimal totalPrep = BigDecimal.ZERO;

I have to divide totalPrep with totalCase and the result is multiplied with 100 to get result value in %. 66.6666666666666666666666666666666666667

Say total prep is bidecimal 2 and toalCase is 3,then the math results in 66.6666666666666666666666666666666666667. I want to concat this to 2 decimal places 66.67%

Any suggestions?

Geek
  • 3,187
  • 15
  • 70
  • 115
  • I think BigDecimal is a type of floating point. You can control the total number of digits of precision, not the places after the decimal. So there's that little issue to start with. – markspace Dec 01 '20 at 22:21
  • So I think normally you end up rounding the output when printed, not the actual number itself. I just happen to have this handy in my reputation changes: https://stackoverflow.com/questions/54121319/rounding-issue-with-quadratic-program/54121348#54121348 – markspace Dec 01 '20 at 22:23
  • 1
    This also might be what you are looking for: https://stackoverflow.com/questions/3395825/how-to-print-formatted-bigdecimal-values – markspace Dec 01 '20 at 22:27
  • *FYI:* Since Java 1.5, replace [`BigDecimal.ROUND_HALF_UP`](https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/math/BigDecimal.html#ROUND_HALF_UP) with [`RoundingMode.HALF_UP`](https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/math/RoundingMode.html#HALF_UP). The old version is deprecated since Java 9. – Andreas Dec 01 '20 at 22:28
  • 1
    As an aside, if this is a percentage split you're not expecting them to always add up to 100... – Persixty Dec 02 '20 at 00:01

1 Answers1

9

If you want 2 / 3 to result in 66.67, you need to multiply first, then divide and round to 2 decimal places:

BigDecimal totalPrep = BigDecimal.valueOf(2);
BigDecimal totalCase = BigDecimal.valueOf(3);

BigDecimal result = totalPrep.multiply(BigDecimal.valueOf(100))
                             .divide(totalCase, 2, RoundingMode.HALF_UP);

System.out.println(result); // prints: 66.67

That will calculate 2 * 100 = 200, then 200 / 3 = 66.67 (rounded)

When you divide first, you calculate 2 / 3 = 0.67 (rounded), then 0.67 * 100 = 67.00, which is obviously not what you want.

Andreas
  • 154,647
  • 11
  • 152
  • 247
  • Not that it matters but `BigDecimal` has `scaleByPowerOfTen(int n)` which is just a neater way of multiply by 100 with n=2. – Persixty Dec 01 '20 at 22:44
  • You can also declare ```MathContext mc = new MathContext(4)``` and then use it as such: ```BigDecimal result = totalPrep.multiply(BigDecimal.valueOf(100)).divide(totalCase,mc);``` Just another way to get the desired output – p_flame Dec 01 '20 at 22:49
  • 1
    @p_flame Can't use `new MathContext(4)`, since we don't know the magnitude of the result. The result should be a percentage with 2 fractional decimals of precision, but since we don't know the actual number of decimals before the decimal point, we don't know what overall precision to use. – Andreas Dec 01 '20 at 22:52
  • 1
    @Persixty I'd prefer `movePointRight(2)` over `scaleByPowerOfTen(2)`. --- `scaleByPowerOfTen` seems redundant given the already existing `movePointRight`, so I wonder why they added the new method in Java 1.5, except that the newer `scaleByPowerOfTen` may cause a negative scale. – Andreas Dec 01 '20 at 22:57
  • @Andreas Makes no odds here. But it makes more sense to me to admit negative scale in most circumstances. But I'm used to rounding by a negative number of places mean rounding into the integer value. I don't see the decimal point as some kind of boundary. Each as you wish. – Persixty Dec 01 '20 at 23:03
  • 1
    @Persixty I generally don't like scientific notation with positive exponent, i.e. `BigDecimal` with negative scale. I prefer that `5 * 100 = "500"` and `5.movePointRight(2) = "500"`, not the `"5E+2"` result of calling `5.scaleByPowerOfTen(2)` *(where `5` is a BigDecimal of course)*. All just personal preference, I guess. – Andreas Dec 01 '20 at 23:08
  • @Andreas Yes, it's just your mental model. I think scientific notation makes sense because it works in things like floating point (albeit the exponent is a binary base). – Persixty Dec 01 '20 at 23:16