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

package main

import (
    "fmt"
    "strconv"
    )

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

I had to write the program above to decrease the precision of a go float64 variable to 2. In this case I was using both strconv and fmt. Is there some other logical method by which it can be done ?

You don't need any extra code ... its as simple as

import (
    "fmt"
)

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

Test Code

I really don't see the point, but you could do something like this without strconv:

package main

import (
    "fmt"
)

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

modify from @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)
}

I'm just starting in Go and found it surprising that it has neither a "toFixed" function (as in JavaScript), which would accomplish what you want, nor even a "round" function.

I picked up a one-liner round function from elsewhere, and also made toFixed() which depends on 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
}

Usage:

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)

No one has mentioned using math/big. The results as pertains to the original question are the same as the accepted answer, but if you are working with floats that require a degree of precision ($money$), then you should use big.Float.

Per the original question:

package main

import (
    "math/big"
    "fmt"
)

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

Unfortunately, you can see that .Text does not use the defined rounding mode (otherwise this answer might be more useful), but rather always seems to round toward zero:

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

// out -> 0.04

Nevertheless, there are certain advantages to having your float stored as a big.Float.

This is a little workaround how can you round float using type conversion to int back and forth:

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

The answer by threeve brought me to this issue on GitHub where a solution based on math/big for rounding values is presented - this way the rounding method is used correctly:

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
", f)
}

The rounding mode is also respected in threeve's example:

j := 0.045

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

-> correctly yields 0.05

Also, Go 1.10 has been released and added a math.Round() function, see this excellent answer by 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
}

However, one should not use float for storing monetary values. (See: Why not use Double or Float to represent currency?) One way around this is using a library that implements decimal like https://github.com/ericlagergren/decimal or https://github.com/shopspring/decimal

Be careful with longitude and latitude float as truncating and rounding can yield completely different results... as it can put you on the wrong side of a latitude boundary.

The simplest solution is numeric truncation (assuming i is a float and you want a precision of 2 decimal points):

float64(int(i * 100)) / 100

For example:

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

BEWARE!

If you're dealing with large numbers (numbers that can cross the max value boundaries), you should know that the above can lead to serious floating point accuracy issues:

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

Prints: 9.223372036854776e+18 -9.223372036854776e+17

See also:

  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