Why do floating literals and variables give different results in Go?

In simple calculations below c

and d

end up with different values ​​(they are off by one bit). Why is this?

a := 4000.0
b := 1e-9
c := a / b
d := 4000.0 / 1e-9



source to share

1 answer


is assigned the next best value for 4000.0

, represented as float64

, which 0x40AF400000000000

matches exactly 4000.0



is the value for the next best 1e-9

shown how float64

that 0x3E112E0BE826D695

corresponds 1.00000000000000006228159145778E-9

. This is where you lost precision.

So, before calculating c

, you already have a small inaccuracy. Then, when c

actually computed, you lose some rounding precision.

In case d

, only one "next best" happens; when representing the total precision computed value 4000.0 / 1e-9

as float64


Variables aside: in C (and presumably C ++), a variable is assumed by default to be non-volatile, that is, not shared, and therefore optimizations often follow constant expressions, replacing everything with computed values. Go makes no assumptions about the scope of variables and therefore makes no guarantees about replacing constant expressions. This may change in the future, but there isn't much in this department today, so it is entirely possible that it is c

actually computed at runtime, rather than at compile time, as someone who has used C might think.

Edit: I took the program provided by @topskip:

package main

import "fmt"

func main() {
    a := 4000.0
    b := 1e-9
    c := a / b
    d := 4000.0 / 1e-9


And this is part of the assembly generated go tool 6g -S


0x0021 00033 (meh.go:6) MOVSD   $f64.40af400000000000+0(SB),X2
0x002a 00042 (meh.go:7) MOVSD   $f64.3e112e0be826d695+0(SB),X3
0x0033 00051 (meh.go:8) MOVAPD  X2,X0
0x0037 00055 (meh.go:8) MOVSD   X3,"".b+64(SP)
0x003d 00061 (meh.go:8) DIVSD   X3,X0


As you can see; c

computed at runtime based on the two constants I describe.



All Articles