1

This question is related to this one and many others, but not a duplicate. I work with doubles, which are surely correct to say 6 decimal places and using

String.format("%f.6", x)

always returns the correct value. However,

String.valueOf(x)

does not. I'd need to "round" x, so that it'd produce the same (or shorter in case of trailing zeros) result as formatting to 6 decimal places. I don't want the exact representation of the decimal number and I know it does not exist. Using

x = Double.parseDouble(String.format("%.6f", x))

gives me what I want, but I'm looking for some more straightforward method (faster and producing no garbage). The obvious way for rounding

x = 1e-6 * Math.round(1e6 * x)

does not work.


As an example consider the following snipped

double wanted = 0.07;
double given = 0.07000000455421122;
double wrong = 1e-6 * Math.round(1e6 * given);
double slow = Double.parseDouble(String.format("%.6f", given));
double diff = wrong - wanted;
double ulp = Math.ulp(wrong);

computing these values

wanted 0.07
given 0.07000000455421122
wrong 0.06999999999999999
slow 0.07
diff -1.3877787807814457E-17
ulp 1.3877787807814457E-17

The problem seems to be that 1e-6 * 70000 produces the best possible result, but it's one ulp away from what I want.

Once again: I'm not asking how to round, I'm asking how to do it faster. So I'm afraid, BigDecimal is not the way to go.

Community
  • 1
  • 1
maaartinus
  • 44,714
  • 32
  • 161
  • 320
  • 1
    Sorry, but given the fact that `BigDecimal` has a method that does exactly what you're asking, I don't understand why that option is off the table. – Joe C Feb 12 '17 at 20:34
  • `double` cannot represent `0.07` accurately. The best you can "achieve" is `0.070000000000000007`, and for that you can simply do `double wanted = int(given*100)/100.0`. – barak manos Feb 12 '17 at 20:36
  • @JoeC Speed (and produced garbage). It doesn't matter that much in my real use case, but I'm curious. – maaartinus Feb 12 '17 at 20:46

1 Answers1

3

The problem is that 1e-6 is not exactly 10-6 (it is in fact 0.000000999999999999999954748111825886258685613938723690807819366455078125)

Instead of multiplying by this, you should divide by 1e6 which is exactly 106, then the result will be the closest floating point number to 0.07 (which is 0.07 or 0.070000000000000006661338147750939242541790008544921875).

Simon Byrne
  • 7,694
  • 1
  • 26
  • 50