-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Description
The following statements
fmt.Printf("x = %.1f\n", 0.35)
fmt.Printf("x = %.1f\n", 0.45)
fmt.Printf("x = %.1f\n", 0.55)
fmt.Printf("x = %.1f\n", 0.65)
produce
x = 0.3
x = 0.5
x = 0.6
x = 0.7
(https://play.golang.org/p/kLC7Ap0cpP).
However, assuming rounding to nearest even, one would expect the result to be
x = 0.4
x = 0.4
x = 0.6
x = 0.6
(The examples use fmt.Printf but the culprit is in the underlying strconv code. The documentation doesn't explicitly state that it rounds to nearest even, but that is definitively the intent of the implementation which contains code and comments to that effect.).
The problem of course is that these numbers cannot be accurately represented in binary form and when it comes to the rounding decision, what should be .5 is sometimes below or above that value.
That said, the correct result could in fact be obtained if rounding were done on the shortest decimal representation that produces the incoming number, that is if rounding where done on the output of using the "%g" format (or strconv.FormatFloat with precision -1). Unfortunately, computing that representation is much more expensive than what happens now.
We can probably not fix this. For one, it's been like this forever. Also, a corresponding C program
#include <stdio.h>
int main() {
printf("x = %.1f\n", 0.35);
printf("x = %.1f\n", 0.45);
printf("x = %.1f\n", 0.55);
printf("x = %.1f\n", 0.65);
return 0;
}
produces the same (incorrect) result. And so does math/big.Float formatting with the same arguments (since the code mirrors the strconv code).
But we should probably document it and perhaps even provide a "correct" routine for cases where this truly matters.