0%

go小数四舍五入取整

go的 math 包只提供了简单的小数操作,像常用的四舍五入,保留几位小数这些常用的操作,却没有提供,那只好自己造轮子了。

四舍五入取整

1
2
3
func Rounding(v float64) int {
return int(v + 0.5)
}

四舍五入取整还是很简单的,直接 +0.5 然后取整就可以了。

保留指定小数位数

1
2
3
4
5
6
7
func FloatRetainBit(v float64, bit int) float64 {
if bit == 0 {
return math.Floor(v)
}
pow10 := math.Pow10(bit)
return math.Floor(v*pow10) / pow10
}

这个多了一点数学运算,其实就是 * 10 的 多少次方,然后向下取整,再 ÷ 10 的 多少次方就可以了

其中的数学知识:

  • * 10 的 多少次方 就是小数点 移多少位

  • ÷ 10 的 多少次方 就是小数点 移多少位

保留指定小数位数取整

1
2
3
4
5
6
7
func FloatRoundingRetainBit(v float64, bit int) float64 {
if bit == 0 {
return math.Floor(v + 0.5)
}
pow10 := math.Pow10(bit)
return math.Floor(v*pow10+0.5) / pow10
}

这个也没啥复杂的,就是在保留位数的基础上再加一个四舍五入就好了

测试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package main

import (
"fmt"
"math"
"math/rand"
)

func main() {
f := rand.Float64()
fmt.Println(f)
fmt.Println(Rounding(f))
fmt.Println(FloatRetainBit(f, 4))
fmt.Println(FloatRoundingRetainBit(f, 4))
}

func Rounding(v float64) int {
return int(v + 0.5)
}

func FloatRetainBit(v float64, bit int) float64 {
if bit == 0 {
return math.Floor(v)
}
pow10 := math.Pow10(bit)
return math.Floor(v*pow10) / pow10
}

func FloatRoundingRetainBit(v float64, bit int) float64 {
if bit == 0 {
return math.Floor(v + 0.5)
}
pow10 := math.Pow10(bit)
return math.Floor(v*pow10+0.5) / pow10
}

看一下运行结果

1
2
3
4
0.6046602879796196
1
0.6046
0.6047

是符合逻辑的

benchmark

保留指定位数的小数,出了用这种数学计算的方式外,还可以用 fmt 包的函数来做

比如:

1
2
sprintf := fmt.Sprintf("%.4f", f)
float, = strconv.ParseFloat(sprintf, 64)

通过占位符 %.4f 来确定小数点后面保留几位

这个方式在性能上比数学计算的要差好多,用benchmark 测试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
"fmt"
"math/rand"
"strconv"
"testing"
)

func BenchmarkFloatRetainBit(b *testing.B) {
f := rand.Float64()
for i := 0; i < b.N; i++ {
FloatRetainBit(f, 5)
}
}

func BenchmarkFloatRetainFmt(b *testing.B) {
f := rand.Float64()
for i := 0; i < b.N; i++ {
sprintf := fmt.Sprintf("%.4f", f)
_, _ = strconv.ParseFloat(sprintf, 64)
}
}

执行:

1
go test -bench . -benchmem

结果:

1
2
3
4
5
6
7
8
goos: windows
goarch: amd64
pkg: test2
cpu: AMD Ryzen 5 3500X 6-Core Processor
BenchmarkFloatRetainBit-6 310487731 3.865 ns/op 0 B/op 0 allocs/op
BenchmarkFloatRetainFmt-6 3773605 322.6 ns/op 16 B/op 2 allocs/op
PASS
ok test2 3.179s

可以看到,无论是速度还是内存使用上,都是数学计算更好