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
|
可以看到,无论是速度还是内存使用上,都是数学计算更好