go的 math
包只提供了简单的小数操作,像常用的四舍五入,保留几位小数这些常用的操作,却没有提供,那只好自己造轮子了。
四舍五入取整
func Rounding(v float64) int {
return int(v + 0.5)
}
四舍五入取整还是很简单的,直接 +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
}
这个多了一点数学运算,其实就是 * 10 的 多少次方
,然后向下取整,再 ÷ 10 的 多少次方
就可以了
其中的数学知识:
-
* 10 的 多少次方
就是小数点 右 移多少位 -
÷ 10 的 多少次方
就是小数点 左 移多少位
保留指定小数位数取整
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
}
这个也没啥复杂的,就是在保留位数的基础上再加一个四舍五入就好了
测试一下
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
}
看一下运行结果
0.6046602879796196
1
0.6046
0.6047
是符合逻辑的
benchmark
保留指定位数的小数,出了用这种数学计算的方式外,还可以用 fmt
包的函数来做
比如:
sprintf := fmt.Sprintf("%.4f", f)
float, = strconv.ParseFloat(sprintf, 64)
通过占位符 %.4f
来确定小数点后面保留几位
这个方式在性能上比数学计算的要差好多,用benchmark 测试一下
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)
}
}
执行:
go test -bench . -benchmem
结果:
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
可以看到,无论是速度还是内存使用上,都是数学计算更好