我想将1.234567
截断为3位数的浮点数,但结果不是我想要的。
例如:1.234567
=> 1.234
package main
import (
"strconv"
"fmt"
)
func main() {
f := 1.234567
fmt.Println(strconv.FormatFloat(f, 'f', 3, 64)) //1.235
fmt.Printf("%.3f", f) //1.235
}
有人可以告诉我如何在Go中执行此操作吗?
答案 0 :(得分:1)
对于截断,我们可以利用math.Trunc()
来丢弃小数位数。这并不是我们想要的,我们想保留一些小数位数。因此,为了实现所需的功能,我们可以先将输入乘以10的幂,以将所需的分数位数移至“整数”部分,然后在截断后(调用math.Trunc()
会丢弃剩余的分数位数),我们可以除以开始时乘以的10的幂:
f2 := math.Trunc(f*1000) / 1000
将其包装为函数:
func truncateNaive(f float64, unit float64) float64 {
return math.Trunc(f/unit) * unit
}
测试:
f := 1.234567
f2 := truncateNaive(f, 0.001)
fmt.Printf("%.10f\n", f2)
输出:
1.2340000000
到目前为止,还不错,但是请注意,我们在truncateNaive()
内执行算术运算,这可能会导致不需要的舍入,从而可能会改变函数的输出。
例如,如果输入为0.299999999999999988897769753748434595763683319091796875
(确切地由float64
值表示,请参见proof),则输出应为0.2999000000
,但它将为其他的东西:
f = 0.299999999999999988897769753748434595763683319091796875
f2 = truncateNaive(f, 0.001)
fmt.Printf("%.10f\n", f2)
输出:
0.3000000000
在Go Playground上尝试这些。
在大多数情况下,这种错误的输出可能是不可接受的(除非您以输入非常接近0.3
的方式查看它-差异小于10 -16 –输出为0.3
...)。
big.Float
要正确截断所有有效的float64
值,中间操作必须精确。为此,仅使用一个float64
是不够的。有几种方法可以将输入分成2个float64
值并对它们执行操作(这样就不会丢失精度),这样会更有效,或者我们可以使用更方便的方式big.Float
具有任意精度。
以下是使用truncateNaive()
的上述big.Float
函数的“成绩单”:
func truncate(f float64, unit float64) float64 {
bf := big.NewFloat(0).SetPrec(1000).SetFloat64(f)
bu := big.NewFloat(0).SetPrec(1000).SetFloat64(unit)
bf.Quo(bf, bu)
// Truncate:
i := big.NewInt(0)
bf.Int(i)
bf.SetInt(i)
f, _ = bf.Mul(bf, bu).Float64()
return f
}
测试:
f := 1.234567
f2 := truncate(f, 0.001)
fmt.Printf("%.10f\n", f2)
f = 0.299999999999999988897769753748434595763683319091796875
f2 = truncate(f, 0.001)
fmt.Printf("%.10f\n", f2)
输出现在有效(在Go Playground上尝试):
1.2340000000
0.2990000000
答案 1 :(得分:0)
您需要在字符串级别或使用https://play.golang.org/p/UP2gFx2iFru之类的math.Floor
来手动截断小数。