go的 math
包只提供了简单的小数操作,像常用的四舍五入,保留几位小数这些常用的操作,却没有提供,那只好自己造轮子了。
四舍五入取整
1func Rounding(v float64) int {
2 return int(v + 0.5)
3}
四舍五入取整还是很简单的,直接 +0.5
然后取整就可以了。
保留指定小数位数
1func FloatRetainBit(v float64, bit int) float64 {
2 if bit == 0 {
3 return math.Floor(v)
4 }
5 pow10 := math.Pow10(bit)
6 return math.Floor(v*pow10) / pow10
7}
这个多了一点数学运算,其实就是 * 10 的 多少次方
,然后向下取整,再 ÷ 10 的 多少次方
就可以了
其中的数学知识:
* 10 的 多少次方
就是小数点 右 移多少位÷ 10 的 多少次方
就是小数点 左 移多少位
保留指定小数位数取整
1func FloatRoundingRetainBit(v float64, bit int) float64 {
2 if bit == 0 {
3 return math.Floor(v + 0.5)
4 }
5 pow10 := math.Pow10(bit)
6 return math.Floor(v*pow10+0.5) / pow10
7}
这个也没啥复杂的,就是在保留位数的基础上再加一个四舍五入就好了
测试一下
1package main
2
3import (
4 "fmt"
5 "math"
6 "math/rand"
7)
8
9func main() {
10 f := rand.Float64()
11 fmt.Println(f)
12 fmt.Println(Rounding(f))
13 fmt.Println(FloatRetainBit(f, 4))
14 fmt.Println(FloatRoundingRetainBit(f, 4))
15}
16
17func Rounding(v float64) int {
18 return int(v + 0.5)
19}
20
21func FloatRetainBit(v float64, bit int) float64 {
22 if bit == 0 {
23 return math.Floor(v)
24 }
25 pow10 := math.Pow10(bit)
26 return math.Floor(v*pow10) / pow10
27}
28
29func FloatRoundingRetainBit(v float64, bit int) float64 {
30 if bit == 0 {
31 return math.Floor(v + 0.5)
32 }
33 pow10 := math.Pow10(bit)
34 return math.Floor(v*pow10+0.5) / pow10
35}
看一下运行结果
10.6046602879796196
21
30.6046
40.6047
是符合逻辑的
benchmark
保留指定位数的小数,出了用这种数学计算的方式外,还可以用 fmt
包的函数来做
比如:
1sprintf := fmt.Sprintf("%.4f", f)
2float, = strconv.ParseFloat(sprintf, 64)
通过占位符 %.4f
来确定小数点后面保留几位
这个方式在性能上比数学计算的要差好多,用benchmark 测试一下
1package main
2
3import (
4 "fmt"
5 "math/rand"
6 "strconv"
7 "testing"
8)
9
10func BenchmarkFloatRetainBit(b *testing.B) {
11 f := rand.Float64()
12 for i := 0; i < b.N; i++ {
13 FloatRetainBit(f, 5)
14 }
15}
16
17func BenchmarkFloatRetainFmt(b *testing.B) {
18 f := rand.Float64()
19 for i := 0; i < b.N; i++ {
20 sprintf := fmt.Sprintf("%.4f", f)
21 _, _ = strconv.ParseFloat(sprintf, 64)
22 }
23}
执行:
1go test -bench . -benchmem
结果:
1goos: windows
2goarch: amd64
3pkg: test2
4cpu: AMD Ryzen 5 3500X 6-Core Processor
5BenchmarkFloatRetainBit-6 310487731 3.865 ns/op 0 B/op 0 allocs/op
6BenchmarkFloatRetainFmt-6 3773605 322.6 ns/op 16 B/op 2 allocs/op
7PASS
8ok test2 3.179s
可以看到,无论是速度还是内存使用上,都是数学计算更好