go - 如何将 float64 数字截断为特定精度?
问题描述
我想截断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 中做到这一点?
解决方案
天真的方式(并不总是正确的)
对于截断,我们可以利用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
精确地用一个值表示,见证明),输出应该是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
推荐阅读
- excel - Excel:x天前的条件格式
- javascript - js 两个对象合二为一
- java - Cassandra Write Timeout - 尝试了我认为可以调试/分析的任何东西,但仍然没有运气。帮助我了解您的意见/方向
- javascript - 使用 findById 在数组中查找模式的 id
- javascript - 如何在不记录错误的情况下检查 Firebase 存储中的文件是否存在?
- javascript - XSL + XSD + XML + PHP 进程中的错误
- haskell - 如何在 Haskell 的 Lambda 演算中转换整数列表生成器 [m ...]
- json - Kotlin 无法请求 URL 中包含多个目录的 JSON 文件?
- reactjs - Javascript 队列页面更改(等待用户操作)
- swift - 您如何检测 AppKit 应用程序是否已随文档一起启动?