0

I wanted to convert a number which is in string format to a percentage value with one decimal point. Below is my sample input and expected output.

Expected results:

"0.0195" => "2.0%"

"0.0401" => "4.0%"

I know this may be a simple question but I am not able to find the exact solution for this using java APIs, I tried all the rounding modes present under RoundingMode enum, but no rounding mode gives my expected result. Could you please help, I may be missing something.


import java.math.RoundingMode;
import java.text.NumberFormat;

public class RoundingModeExample {
    public static void main(String[] args) {
        System.out.println(formatPercentage("0.0195") + "(expected 2.0%)");
        System.out.println(formatPercentage("0.0401") + "(expected 4.0%)");
    }

    private static String formatPercentage(String number) {
        String formattedValue = "";
        NumberFormat numberFormat = NumberFormat.getPercentInstance();
        numberFormat.setMinimumFractionDigits(1);
        numberFormat.setRoundingMode(RoundingMode.HALF_UP);
        try {
            formattedValue = numberFormat.format(Double.valueOf(number));
        } catch (NumberFormatException e) {
            formattedValue = number;
        }
        return formattedValue;
    }


}

Output of the above program:

1.9%(expected 2.0%)

4.0%(expected 4.0%)

JavaCodeNet
  • 1,115
  • 1
  • 15
  • 21
  • Proposal: parse the `String` into a `double` ([`Double.parseDouble(String)`](https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/Double.html#parseDouble(java.lang.String))), multiply this `double` by `100.0`, round it to nearest even ([`Math.round(double)`](https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/lang/Math.html#round(double))), print it out. – Turing85 Aug 25 '20 at 22:27
  • 1
    [double values are not exact.](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) The compiler and runtime cannot represent 0.0195 exactly in IEEE format. Instead, it uses 0.0194999999999999999722444243843710864894092082977294921875. – VGR Aug 25 '20 at 22:53
  • @Turing85 That won't give you the 1dp. Multiplying by 1000, rounding, then dividing by 10 should work but it feels like a kludge. – Dawood ibn Kareem Aug 25 '20 at 23:24

1 Answers1

6

The problem with 0.0195 is that there is no double precision number that is exactly mathematically equal to it. When you write 0.0195 in program source code or parse the string "0.0195" into double, the number you get is actually a little bit less. That's why the formatter rounds it to 1.9%.

You can get around this by not using the double data type at all:

formattedValue = numberFormat.format(new BigDecimal(number));
Joni
  • 108,737
  • 14
  • 143
  • 193