0

For getting a String with exactly 2 digits after the "." I can do something like:

        DecimalFormat df = (DecimalFormat)DecimalFormat.getInstance(Locale.US);
        df.applyPattern("0.00");
        df.setRoundingMode(RoundingMode.HALF_UP);
        String output = df.format(value);

When I have a number such as 828.054999999702d, it will format it to 828.05 what is so far correct, since the next digit says "4" and it will round that down to nothing.

But what if I need to preserve more digits precision, just don't want to show it?

What I quickly created is this working code:

        double prettyValue = value;
        prettyValue = Math.round(prettyValue * 1000000d) / 1000000d;
        prettyValue = Math.round(prettyValue * 100000d) / 100000d;
        prettyValue = Math.round(prettyValue * 10000d) / 10000d;
        prettyValue = Math.round(prettyValue * 1000d) / 1000d;
        prettyValue = Math.round(prettyValue * 100d) / 100d; 
        DecimalFormat df = (DecimalFormat)DecimalFormat.getInstance(Locale.US);
        df.applyPattern("0.00");
        df.setRoundingMode(RoundingMode.HALF_UP);
        String output = df.format(prettyValue);

This will round the 6th, 5th, 4th, 3th and then the second place, NumberFormat will not have to do anything but just print the 2 remaining digits, after that there will be zeroes.

But I think there should be already an out-of-the-box rounding that I just don't see. Trying to do the same with BigDecimals leads to exactly the same issue for me.

The result I want is to get 828.054999999702 rounded to 828.06.

Jens
  • 495
  • 1
  • 6
  • 28
  • Try rounding down when formatting the output. – Thomas Feb 09 '17 at 17:09
  • What does *"what if I need to preserve more digits precision, just don't want to show it?"* mean? What does formatting for display have to do with preservation of precision? If your formatted text is your preservation, then you must show all digits necessary for preservation. If value is preserved otherwise, what is the problem you're having? I'm confused. – Andreas Feb 09 '17 at 17:21

2 Answers2

3

I'm not sure I fully understand your question so let me recap:

  • You have some double value with potentially more than 6 significant fraction digits.
  • You want to round that value to 6 fraction digits and use the HALF_UP mode.
  • You want to display only the first 2 fraction digits (I don't understand why but I won't question it).

In that case I'd suggest you first use BigDecimal for the rounding since otherwise you could get precision errors:

double value = 1.23456789;
BigDecimal rounded = BigDecimal.valueOf( value ).setScale(6, RoundingMode.HALF_UP);

That should result in the value 1.234568.

Then use NumberFormat like you did but always round down:

DecimalFormat df = (DecimalFormat)DecimalFormat.getInstance(Locale.US);
df.applyPattern("#.##");
df.setRoundingMode(RoundingMode.DOWN);
String output = df.format( rounded );

That should result in 1.23.

With your input value of 4.23499999999235 you'd then get 4.235000 (rounded to 6 digits) and 4.23.

Edit: I'm not aware of any rounding mode that rounds 4.23499999999235 to 4.24 but you should be able to achieve it by chaining multiple setScale() calls:

BigDecimal rounded = BigDecimal.valueOf( value );
for( int digit = 6; digit >= 2; digit--) {
  rounded = rounded .setScale( digit, RoundingMode.HALF_UP );
}

That should apply rounding to fraction digit 6, then 5 etc. and finally round to 4.24. I'm still not sure that's the right way to round but you know your requirements better than me :)

Thomas
  • 87,414
  • 12
  • 119
  • 157
  • This seems to be the right idea. But I will still need to use HALF_UP. Then the result would be 4.24 what is what I wanted. I clarified it by editing the question, also using another number (real example from debugging). – Jens Feb 09 '17 at 17:31
  • @Jens you might want to edit your question once more since `828.xx` won't round to `4.23` in any case ;) – Thomas Feb 10 '17 at 08:44
  • @Jens see my edit for at least one way to round like you described. – Thomas Feb 10 '17 at 09:46
  • Thats quite what I did in my question, rounding multiple times. But you put it in a for-loop instead of 5 lines and there is no better answer so I put a check on this. I hoped there is a out-of-the-box solution for this, but maybe I need a math library for this, either myself or 3rd party. :) – Jens Feb 13 '17 at 09:53
  • @Jens The problem might be that the normal mode of rounding just involves looking at the next digit, i.e. when roundig `4.234999` to 2 fraction digits only the 3rd fraction digit (4) will be considered. Thus most math libraries (as well as the built-in functionality) contain only that method. – Thomas Feb 13 '17 at 13:12
0

Considering you are outputting this to a string, why not use

String output = String.format(java.util.Locale.US,"%.2f", doubleValue);

instead of all of the DecimalFormat stuff? This will leave doubleValue as the original value, keeping the precision.

igoldthwaite
  • 289
  • 1
  • 8
  • Even that this shortens my examplecode it wont change anything. The String "output" will contain a number that is not rounded with a precision of more than 2 digits. String format will just look at position 3 and round that 4 down instead of considering all those 9999. – Jens Feb 09 '17 at 17:20
  • So you want 4.2349999 to "round up" to 4.24? This seems like you're just rounding incorrectly. Otherwise I would have done what you did and rounded from higher to lower digits until I reached 2. – igoldthwaite Feb 09 '17 at 17:23
  • I think it is not a wrong rounding. For example financial systems often are constraint to calculate everything with 6 digits precision but then only show 2 digits. But for financial you also use BigDecimal. – Jens Feb 09 '17 at 17:36