英文:
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)
输出:1000
输出:2251
当我使用1000而不是math.Pow(10., 3.)时,我得到了我想要的结果:
y := (((3251 - 1000) / 1000) * 1000)
fmt.Println(y)
输出:2000
我做错了什么?我希望能得到一些帮助。
英文:
I was trying to round a number to the nearest thousand but I usually get a different result when I use math.Pow. Examples:
fmt.Println(math.Pow(10., 3.))
x := math.Pow(10, 3)
y := (((3251 - 1000) / x) * x)
fmt.Println(y)
Output: 1000
Output: 2251
When I use 1000 instead math.Pow(10., 3.) I get what I want:
y := (((3251 - 1000) / 1000) * 1000)
fmt.Println(y)
Output: 2000
What am I doing wrong? I would appreciate some help.
答案1
得分: 3
表达式 y := ((3251 - 1000) / 1000) * 1000
是一个常量表达式,即只有常量无类型字面操作数,并且在编译时计算。特别是:
> 如果二元操作(除移位操作外)的无类型操作数属于不同的种类,则结果是出现在此列表中较后的操作数的种类。
最后的操作数 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
替代后,表达式不再是常量(它是函数调用的结果),现在你有一个由 Pow
的返回类型确定的有类型 float64
变量:
// (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
因此,在后一种情况下,除法得到的小数部分被保留,并在乘以后再次得到。
Playground: https://play.golang.org/p/v_mX3mnM6tT
<hr>
要四舍五入到最接近的千位数,你可以使用 @icza 在这个答案中提到的技巧:
func Round(x, unit float64) float64 {
return math.Round(x/unit) * unit
}
func main() {
x := Round(3251-1000, 1000.)
fmt.Println(x) // 2000
}
英文:
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
<hr>
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
}
答案2
得分: 0
根据建议:
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
英文:
Based on the suggestions:
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
}
Output:
1000
2251
2000
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论