我正在寻找要舍入到Golang中最接近的0.05的函数。
使用该函数的最终结果必须始终为0.05的因数。
这是我要查找的功能的一些输出示例:
(Round函数尚不存在,我希望它可以包含在答案中)
1 2 3 | Round(0.363636) // 0.35 Round(3.232) // 3.25 Round(0.4888) // 0.5 |
我已经搜索了很久了,但是没有找到任何答案。
- 香港专业教育学院在网上找到了一个,但并不能完全满足我在问题中的要求:/
- 相关:转到:使用乘数将float64转换为int
- 如果您具有舍入功能可以给出正确的结果,那么您所要做的就是通过截断来管理结果精度。 play.golang.org/p/DRTTkQQI42(未经边缘测试)是一种for脚的方法
-
正如公认的答案所说,将二进制浮点值四舍五入到小数点后一位(不是0)不是特别有用。 例如,值
0.05 不能准确表示。 在64位IEEE浮点数中,它可能会存储为0.05000000000000000277555756156289135105907917022705078125 。 对于大多数目的,请使浮点值保持全精度,并且仅在执行输出或转换为字符串时才对它们进行舍入。
Go 1.10已发布,并添加了
1 2 3 | func Round(x, unit float64) float64 { return math.Round(x/unit) * unit } |
测试它:
1 2 3 4 5 6 7 | fmt.Println(Round(0.363636, 0.05)) // 0.35 fmt.Println(Round(3.232, 0.05)) // 3.25 fmt.Println(Round(0.4888, 0.05)) // 0.5 fmt.Println(Round(-0.363636, 0.05)) // -0.35 fmt.Println(Round(-3.232, 0.05)) // -3.25 fmt.Println(Round(-0.4888, 0.05)) // -0.5 |
在Go Playground上尝试一下。
原始答案如下,该答案在Go 1.10之前在不存在
在Go1.10之前的时代,没有
舍入任务可以通过
例如:
1 2 3 4 5 | var f float64 f = 12.3 fmt.Println(int64(f)) // 12 f = 12.6 fmt.Println(int64(f)) // 12 |
在两种情况下,结果均为
1 2 3 4 | f = 12.3 fmt.Println(int64(f + 0.5)) // 12 f = 12.6 fmt.Println(int64(f + 0.5)) // 13 |
到目前为止,一切都很好。但是我们不想舍入到整数。如果要四舍五入到小数点后一位,则在添加
1 2 3 4 | f = 12.31 fmt.Println(float64(int64(f*10+0.5)) / 10) // 12.3 f = 12.66 fmt.Println(float64(int64(f*10+0.5)) / 10) // 12.7 |
因此,基本上,您要乘以要舍入的单位的倒数。要舍入到
1 2 3 4 | f = 12.31 fmt.Println(float64(int64(f*20+0.5)) / 20) // 12.3 f = 12.66 fmt.Println(float64(int64(f*20+0.5)) / 20) // 12.65 |
将其包装为一个函数:
1 2 3 | func Round(x, unit float64) float64 { return float64(int64(x/unit+0.5)) * unit } |
使用它:
1 2 3 | fmt.Println(Round(0.363636, 0.05)) // 0.35 fmt.Println(Round(3.232, 0.05)) // 3.25 fmt.Println(Round(0.4888, 0.05)) // 0.5 |
在Go Playground上尝试示例。
请注意,用
另请注意,
还要注意,当您用负数调用
1 2 3 | fmt.Println(Round(-0.363636, 0.05)) // -0.3 fmt.Println(Round(-3.232, 0.05)) // -3.2 fmt.Println(Round(-0.4888, 0.05)) // -0.45 |
这是因为-如前所述-转换将保??留整数部分,例如
如果希望
1 2 3 4 5 6 | func Round2(x, unit float64) float64 { if x > 0 { return float64(int64(x/unit+0.5)) * unit } return float64(int64(x/unit-0.5)) * unit } |
并使用它:
1 2 3 | fmt.Println(Round2(-0.363636, 0.05)) // -0.35 fmt.Println(Round2(-3.232, 0.05)) // -3.25 fmt.Println(Round2(-0.4888, 0.05)) // -0.5 |
为了解决您的评论:由于您不喜欢不精确的
1 | formatted, err := strconv.ParseFloat(fmt.Sprintf("%.2f", rounded), 64) |
而且,这种"貌似"的结果与打印出来的结果完全一样,它给出了
但这只是一个"幻想"。由于
但是,如果您尝试以更高的精度打印它:
1 2 3 4 5 6 | fmt.Printf("%.30f ", Round(0.363636, 0.05)) fmt.Printf("%.30f ", Round(3.232, 0.05)) fmt.Printf("%.30f ", Round(0.4888, 0.05)) |
输出:不好(可能更难看):在Go Playground上尝试:
1 2 3 | 0.349999999999999977795539507497 3.250000000000000000000000000000 0.500000000000000000000000000000 |
请注意,另一方面,
1 2 | 3.25 = 3 + 0.25 = 11.01binary 0.5 = 0.1binary |
有什么教训?不值得格式化和重新解析结果,因为它也不是精确的(只是一个不同的
1 2 3 4 5 6 7 8 9 10 11 12 | func main() { fmt.Printf("%.3f ", Round(0.363636, 0.05)) fmt.Printf("%.3f ", Round(3.232, 0.05)) fmt.Printf("%.3f ", Round(0.4888, 0.05)) } func Round(x, unit float64) float64 { return float64(int64(x/unit+0.5)) * unit } |
它将是准确的(在Go Playground上尝试):
1 2 3 | 0.350 3.250 0.500 |
或者只是将它们乘以
- 无非就是天才。 谢谢icza。
- @Acidic请参见有关将其应用于负数的修改。
- 是的,我明白了。 我已经编辑了您的函数来解决0.363636 = 0.35000000000000003的问题,该问题可以在play.golang.org/p/jxILFBYBEF中找到,以供有兴趣的人使用。
- @Acidic格式化和重新解析仅给您带来"幻觉"。 参见编辑后的答案。 不需要这样做。
- @icza怎么检查溢出?
- @PickBoy该答案未涵盖该内容,因为该问题与舍入(错误)有关。