The expression y := ((3251 - 1000) / 1000) * 1000
is a constant expression, i.e. has only constant untyped literal operands, and it's evaluated at compile time. In particular:
If the untyped operands of a binary operation (other than a shift) are of different kinds, the result is of the operand's kind that appears later in this list
The last operands 1000
(of both the division and multiplication) are an untyped int
, therefore the result of the division is also an int
, and truncated to integer precision as you were expecting:
// (3251 - 1000) -> int 2251
// (3251 - 1000) / 1000 -> int 2
// ((3251 - 1000) / 1000) * 1000 -> int 2000
y := ((3251 - 1000) / 1000) * 1000
fmt.Println(reflect.TypeOf(y)) // int
With math.Pow
instead the expression is not constant anymore (it's the result of a function call), and now you have a typed float64
variable resulting from the return type of Pow
:
// (3251 - 1000) -> 2251 int
// (3251 - 1000) / x -> 2.251 float64
// ((3251 - 1000) / x) * x -> 2251 float64
y := (((3251 - 1000) / x) * x)
fmt.Println(reflect.TypeOf(y)) // float64
So in the latter case, the decimal that results from the division is preserved and you get it back after you multiply it again.
Playground: https://play.golang.org/p/v_mX3mnM6tT
To round to the nearest thousand you can use the trick suggested by @icza in this answer:
func Round(x, unit float64) float64 {
return math.Round(x/unit) * unit
}
func main() {
x := Round(3251-1000, 1000.)
fmt.Println(x) // 2000
}