如何在golang中将float64类型截断为特定的精度?

时间:2013-08-22 20:29:58

标签: floating-point go

package main

import (
    "fmt"
    "strconv"
    )

func main() {
    k := 10/3.0
    i := fmt.Sprintf("%.2f", k)
    f,_ := strconv.ParseFloat(i, 2)
    fmt.Println(f)
}

我必须编写上面的程序,以将go float64变量的精度降低到2。 在这种情况下,我使用strconv和fmt。是否有其他逻辑方法可以完成它?

12 个答案:

答案 0 :(得分:58)

您不需要任何额外的代码......它就像

一样简单
import (
    "fmt"
)

func main() {
    k := 10 / 3.0
    fmt.Printf("%.2f", k)
}

Test Code

答案 1 :(得分:58)

我刚开始使用Go,发现令人惊讶的是它既没有“toFixed”功能(如在JavaScript中),它可以实现你想要的功能,甚至也不是“圆形”功能。

我从其他地方获取了一个单行轮函数,并且还使用了取决于round()的固定():

func round(num float64) int {
    return int(num + math.Copysign(0.5, num))
}

func toFixed(num float64, precision int) float64 {
    output := math.Pow(10, float64(precision))
    return float64(round(num * output)) / output
}

用法:

fmt.Println(toFixed(1.2345678, 0))  // 1
fmt.Println(toFixed(1.2345678, 1))  // 1.2
fmt.Println(toFixed(1.2345678, 2))  // 1.23
fmt.Println(toFixed(1.2345678, 3))  // 1.235 (rounded up)

答案 2 :(得分:16)

我真的没有看到这一点,但你可以在没有strconv的情况下做这样的事情:

package main

import (
    "fmt"
)

func main() {
    untruncated := 10 / 3.0
    truncated := float64(int(untruncated * 100)) / 100
    fmt.Println(untruncated, truncated)
}

答案 3 :(得分:6)

没有人提到使用math/big。与原始问题相关的结果与接受的答案相同,但如果您正在使用需要一定精度($ money $)的浮点数,那么您应该使用big.Float

根据原始问题:

package main

import (
    "math/big"
    "fmt"
)

func main() {
    // original question
    k := 10 / 3.0
    fmt.Println(big.NewFloat(k).Text('f', 2))
}

不幸的是,你可以看到.Text没有使用定义的舍入模式(否则这个答案可能会更有用),但似乎总是向零舍入:

j := 0.045
fmt.Println(big.NewFloat(j).SetMode(big.AwayFromZero).Text('f', 2)

// out -> 0.04

尽管如此,将浮动存储为big.Float

也有一定的优势

答案 4 :(得分:3)

三个人answer将我带到GitHub上的this issue,其中显示了基于math/big的舍入值的解决方案 - 这样就可以正确使用舍入方法:

package main

import (
    "fmt"
    "math/big"
)

func main() {
    f := new(big.Float).SetMode(big.ToNearestEven).SetFloat64(10/3.0)
    // Round to 2 digits using formatting.
    f.SetPrec(8)
    fmt.Printf("%.2f\n", f)
}

在三个例子中也考虑了舍入模式:

j := 0.045

f := new(big.Float).SetMode(big.AwayFromZero).SetFloat64(j)
// Round to 2 digits using formatting.
f.SetPrec(8)
fmt.Printf("%.2f\n", f)

->正确地产生了0.05

此外,Go 1.10已经发布并添加了math.Round()功能,请参阅icza的这个优秀答案:Golang Round to Nearest 0.05

package main

import (
    "fmt"
    "math"
)

func main() {

    fmt.Println(Round(10/3.0, 0.01))

}

func Round(x, unit float64) float64 {
    return math.Round(x/unit) * unit
}

但是,不应使用float来存储货币值。 (见:Why not use Double or Float to represent currency?) 解决此问题的一种方法是使用实​​现decimal的库https://github.com/ericlagergren/decimalhttps://github.com/shopspring/decimal

答案 5 :(得分:3)

最简单的解决方案是数字截断(假设i是浮点型,并且您希望精度为2个小数点):

float64(int(i * 100)) / 100

例如:

i := 123456.789
x := float64(int(i * 100)) / 100
// x = 123456.78

当心!

如果您要处理大量数字(可以跨越最大值边界的数字),则应该知道上述内容可能导致serious floating point accuracy issues

i := float64(1<<63) // 9223372036854775808.0
fmt.Println(i, float64(int64(i * 10)) / 10)

打印:9.223372036854776e+18 -9.223372036854776e+17

另请参阅:

  1. how 32 bit floating point numbers work
  2. how 64 bit floating point numbers work
  3. golang math numeric value range constants
  4. golang math/big

答案 6 :(得分:1)

这是一个小小的解决方法,如何使用类型转换来循环浮动到int:

package main

import (
    "fmt"
)

func main() {
    k := 10 / 3.0
    k = float64(int(k*100)) / 100
    fmt.Println(k)  // output 3.33
}

https://play.golang.org/p/yg2QYcZ-2u

答案 7 :(得分:1)

小心经度和纬度浮动,因为截断和舍入会产生完全不同的结果......因为它可能会使你位于纬度边界的错误一侧。

答案 8 :(得分:1)

无需检查大浮点数的功能

// Rounds like 12.3416 -> 12.35
func RoundUp(val float64, precision int) float64 {
    return math.Ceil(val*(math.Pow10(precision))) / math.Pow10(precision)
}

// Rounds like 12.3496 -> 12.34
func RoundDown(val float64, precision int) float64 {
    return math.Floor(val*(math.Pow10(precision))) / math.Pow10(precision)
}

// Rounds to nearest like 12.3456 -> 12.35
func Round(val float64, precision int) float64 {
    return math.Round(val*(math.Pow10(precision))) / math.Pow10(precision)
}

答案 9 :(得分:0)

func FloatPrecision(num float64, precision int) float64 {
    p := math.Pow10(precision)
    value := float64(int(num*p)) / p
    return value
}

答案 10 :(得分:0)

因此,经过反复摸索,多次访问该线程,我终于找到了一个非常简单的解决方案,该解决方案使您可以非常简单地控制浮点数的精度,而无需任何怪异的数学运算!

package main

import (
    "fmt"
    "github.com/shopspring/decimal"
)

func main() {
    k := 101.3874927181298723478
    p := 5

    v := decimal.NewFromFloat(k).Round(int32(p))
    fmt.Println(v)
}
// 101.38749

来源:https://godoc.org/github.com/shopspring/decimal#Decimal.Round

虽然我喜欢一些简单的方法,例如"%.3f\n", k选项,但是它们产生了一个字符串,然后我不得不使用另一个我不想做的strconv命令将其转换回浮点数。

答案 11 :(得分:-2)

从@creack修改

package main

import (
    "fmt"
)

func main() {

    //untruncated := 10/3.0
    untruncated := 4.565
    tmp := int(untruncated*100)
    last := int(untruncated*1000)-tmp*10
    if last>=5{
        tmp += 1
    }
    truncated := float64(tmp)/100

    fmt.Println(untruncated, truncated)
}