使用 math.Pow 四舍五入到最接近的千位时的不同结果

Different results while rounding to nearest thousand using math.Pow

我试图将数字四舍五入到最接近的千位,但当我使用 math.Pow 时通常会得到不同的结果。示例:

fmt.Println(math.Pow(10., 3.))
x := math.Pow(10, 3)
y := (((3251 - 1000) / x) * x)
fmt.Println(y)

Output: 1000
Output: 2251

GoPlayGround

当我改用 1000 时 math.Pow(10., 3.) 我得到了我想要的:

y := (((3251 - 1000) / 1000) * 1000)
fmt.Println(y)

Output: 2000

Go PlayGround

我做错了什么?我将不胜感激。

表达式 y := ((3251 - 1000) / 1000) * 1000 是一个 constant expression,即只有常量无类型文字操作数,它在编译时求值。特别是:

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

(除法和乘法的)最后一个操作数 1000 是一个 未类型化的 int,因此除法的结果也是一个 int,并按照您的预期截断为整数精度:

    // (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

使用 math.Pow 而不是表达式不再是常数(它是函数调用的结果),现在你有一个 typed float64 变量由 Pow 的 return 类型产生:

    // (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

所以在后一种情况下,除法得到的小数会被保留下来,你再乘一次就可以得到它。

游乐场:https://play.golang.org/p/v_mX3mnM6tT


要四舍五入到最接近的千位,您可以使用 @icza in :

建议的技巧
func Round(x, unit float64) float64 {
    return math.Round(x/unit) * unit
}

func main() {
    x := Round(3251-1000, 1000.)
    fmt.Println(x) // 2000
}

根据建议:

package main

import (
    "fmt"
    "math"
)

func main() {
    fmt.Println(math.Pow(10, 3))
    x := math.Pow(10, 3)
    y := (((3251 - 1000) / x) * x)
    fmt.Println(y)
    fmt.Println(Round(y, 1000))
}
func Round(x, unit float64) float64 {
    return math.Round(x/unit) * unit
}

输出:

1000
2251
2000