Format a float to n decimal places and no trailing zeros
Asked Answered
C

5

42

I want to display a float with the entire integer part and up to two decimals for the fractional part, without trailing zeros.

http://play.golang.org/p/mAdQl6erWX:

// Desired output: 
// "1.9"
// "10.9"
// "100.9"

fmt.Println("2g:")
fmt.Println(fmt.Sprintf("%.2g", 1.900)) // outputs "1.9"
fmt.Println(fmt.Sprintf("%.2g", 10.900)) // outputs "11"
fmt.Println(fmt.Sprintf("%.2g", 100.900)) // outputs "1e+02"

fmt.Println("\n2f:")
fmt.Println(fmt.Sprintf("%.2f", 1.900)) // outputs "1.90"
fmt.Println(fmt.Sprintf("%.2f", 10.900)) // outputs "10.90"
fmt.Println(fmt.Sprintf("%.2f", 100.900)) // outputs "100.90"

Formatting with 2g has the problem that it starts rounding when the integer increases order of magnitudes. Also, it sometimes displays numbers with an e.

Formatting with 2f has the problem that it will display trailing zeros. I could write a post-processing function that removes trailing zeros, but I rather do this with Sprintf.

Can this be done in a generic way using Sprintf?
If not, what's a good way to do this?

Celik answered 8/7, 2015 at 10:3 Comment(1)
In %.Ng N is a total number of digits, not a precision. Unfortunately I don't think you can implement your requirements using Sprintf only.Overhasty
P
91

strconv.FormatFloat(10.900, 'f', -1, 64)

This will result in 10.9.

The -1 as the third parameter tells the function to print the fewest digits necessary to accurately represent the float.

See here: https://golang.org/pkg/strconv/#FormatFloat

Plod answered 11/11, 2016 at 19:56 Comment(1)
This does not strictly solve their problem, because they want a precision of 2 points.Nutritionist
O
7

Not sure for Sprintf but to make it worked. Just trim right, first 0 then ..

fmt.Println(strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.2f", 100.900), "0"), ".")) // 100.9
fmt.Println(strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.2f", 100.0), "0"), ".")) // 100
Oliverolivera answered 8/7, 2015 at 10:13 Comment(0)
L
6

I used the below func to achive the same:

//return 45.00 with "45" or 45.50 with "45.5"
func betterFormat(num float32) string {
    s := fmt.Sprintf("%.4f", num)
    return strings.TrimRight(strings.TrimRight(s, "0"), ".")
}
Louvar answered 17/1, 2019 at 21:15 Comment(2)
@SergeyPonomarev that won't work. In case the number is 10.0, it will become just 1Hemiterpene
@Hemiterpene you are right, I removed my comment to avoid confusionPlasmolysis
K
2

Use the below function to format and control the number of digits.

func FormatFloat(num float64, prc int) string {
    var (
        zero, dot = "0", "."

        str = fmt.Sprintf("%."+strconv.Itoa(prc)+"f", num)
    )
    
    return strings.TrimRight(strings.TrimRight(str, zero), dot)
}

Here is an example:

// Converts 18.24100100 to 18.24
fmt.Println(FormatFloat(18.24100100, 2))
Kelsy answered 13/6, 2020 at 18:34 Comment(0)
P
0

We must trim those zeros ourselves. We can use TrimRight(priceStr, "0."), but I've written a faster trimmer:

func formatPrice(price float32) string {
    // truncate to 3 digits after point
    priceStr := strconv.FormatFloat(float64(price), 'f', 3, 32)
    priceStr = trimFloatTrailingZeros(priceStr)
    return priceStr
}

// trimFloatTrailingZeros the FormatFloat add padding zeros e.g. 20.900 to 20.9 or 10.0 to 10
// Note: the number must contain the decimal dot e.g. as result of format
func trimFloatTrailingZeros2(s []byte) []byte {
    i := len(s) - 1
    for ; i >= 1; i-- {
        digit := s[i]
        if digit == '0' {
        } else {
            if digit == '.' {
                return s[:i]
            } else {
                return s[:i+1]
            }
        }
    }
    return s
}
Plasmolysis answered 24/10, 2022 at 20:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.