-5

in the following snippet of go code I struggle to understand why the results are different:

func main() {
    a := -0.2; b := -0.1; 
    fmt.Println(a+b)
    //Outputs expected float value with rounding error  : -0.30000000000000004
    c := (-0.2)+(-0.1)
    fmt.Println(c)
    //Will ouput -0.3 (the actual exact constant).
}

What is happening exactly, does go somehow performs the c operation as constant instead of float64 operation when these constants are not used to instantiate floats? Full working version : https://play.golang.org/p/kUICDGFiMvf

Any insights would be appreciated, thanks.

Lou-adrien
  • 71
  • 5
  • 2
    Most likely because the *compiler* calculates the result during compilation in the second case. That's a very common optimization. In any case, the rounding error appears in the *second* case, not the first. The compiler rounds the result before generating the assignment operation. Numbers like `0.1`, `0.2` and `0.3` `0.3` [can't be represented accuratelly](https://floating-point-gui.de/basic/) using floating points – Panagiotis Kanavos Aug 13 '19 at 10:00
  • 1
    https://0.30000000000000004.com/ for the first part and for the second: Read how Go handles constants: They are (almost) arbitrary precision. – Volker Aug 13 '19 at 10:07
  • 1
    Also `fmt.Println()` performs some rounding, if you print it like `fmt.Printf("%.20f", c)`, you'll see a result of `-0.29999999999999998890`. – icza Aug 13 '19 at 10:08
  • 1
    Also see related: [Does Go compiler's evaluation differ for constant expression and other expression](https://stackoverflow.com/questions/39444852/does-go-compilers-evaluation-differ-for-constant-expression-and-other-expressio/39445372#39445372) – icza Aug 13 '19 at 10:17
  • I have updated the golang playground. Indeed using the formatted printf show the difference, so it seems that c was assigned the constant value -0.3 statically (by the compiler?) which was then approximated to the closest float64, instead of following the normal float operations flow which would aggregate rounding errors – Lou-adrien Aug 13 '19 at 10:18
  • 3
    The Playground use a normal Go compiler which follows the Go language spec. So Yes, `(-0.2)+(-0.1)` was evaluated to -0.3 during compilation and that value was assigned to c. Everything is done 100% according to the language spec. What do you mean when you say "instead of following the normal float operations flow". What is "normal float operation" except what the language spec says? – Volker Aug 13 '19 at 11:07
  • @Volker sorry "normal float operation" was not accurate, I meant "my assumption about how this operation would be handled", i.e both (-0.2)+(-0.1) would be treated as a float operation at runtime, instead of a compile time operation to replace this value by the correct resulting constant. Could you point me out to the specs specifying this compiling behaviour? – Lou-adrien Aug 13 '19 at 11:40
  • 2
    https://golang.org/ref/spec#Constant_expressions The spec is short, readable and searchable: The first three search results for "const" are all relevant entries in the table of contents. Go really is different from other languages. In most languages you have to ask an expert, in Go you can search the spec and this is often faster. – Volker Aug 13 '19 at 12:20
  • @Volker could have done without the down-looking tone (whether a search is obvious or not is extremely subjective), but thanks anyways, your answers cleared my doubts. Have a nice day! – Lou-adrien Aug 13 '19 at 13:02

1 Answers1

-2

I try to use Java and the result is:

public class StringTest {
    public static void main(String[] args) {

        double a = -0.2;
        double b = -0.1;
        System.out.println(a + b);
       //  -0.30000000000000004

        double c = a + b;
        System.out.println(c);
      // -0.30000000000000004

    }
}

It seems that the any programming language that uses binary floating point numbers will have this problem. Some language's Number type used IEEE754 standard to represent number. And what is IEEE-745 float, you can see it.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
  • 2
    Go's rules for evaluating constants are quite different from those of most other mainstream programming languages. What happens in Java isn't really useful for understanding what's happening in the OP's Go example. – Mark Dickinson Aug 13 '19 at 17:11
  • yeah, i just give an example – youze liang Aug 14 '19 at 09:40