The following code should work for a lot of simple use cases with relatively small numbers and small precision inputs. However, it may not work for some uses cases because of numbers overflowing out of the range of float64 numbers, as well as IEEE-754 rounding errors (other languages have this issue as well).

If you care about using larger numbers or need more precision, the following code may not work for your needs, and you should use a helper library (e.g. https://github.com/shopspring/decimal).

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)
Answer from David Calhoun on Stack Overflow
🌐
YourBasic
yourbasic.org › golang › round-float-2-decimal-places
Round float to 2 decimal places · YourBasic Go
x := 12.3456 fmt.Println(math.Floor(x*100)/100) // 12.34 (round down) fmt.Println(math.Round(x*100)/100) // 12.35 (round to nearest) fmt.Println(math.Ceil(x*100)/100) // 12.35 (round up) Due to the quirks of floating point representation, these rounded values may be slightly off.
Discussions

How to round big.Float to two decimal places

https://play.golang.org/p/SDNoJTT2tsS

More on reddit.com
🌐 r/golang
8
5
June 13, 2018
math - Golang Round to Nearest 0.05 - Stack Overflow
If you have a rounding function that gives correct result, all you need to do is manage the result's precision by truncating it. A sort of ham-fisted approach for that would be play.golang.org/p/DRTTkQQI42 (not edge tested) ... As the accepted answer says, rounding a binary floating-point value ... More on stackoverflow.com
🌐 stackoverflow.com
math: add Round
What version of Go are you using (go version)? 1.8 What did you expect to see? A rounding method for floats in the standard library What did you see instead? There is no standard library method for rounding a float64 to int/int32 I would... More on github.com
🌐 github.com
38
April 24, 2017
How to round to nearest int when casting float to int in go - Stack Overflow
When casting float to int the decimal is discarded. What's a clean way to cast so that it rounds to the nearest whole number instead. x := int(3.6) should equal 4 instead of 3. More on stackoverflow.com
🌐 stackoverflow.com
🌐
Boot.dev
blog.boot.dev › golang › round-float-golang
How to Round a Float in Go | Boot.dev
November 13, 2022 - heightInMeters := 1.76234 roundedToNearest := int(math.Round(x*100)/100) // 2 · PS: I’ve got a fully interactive Golang course here if you’re interested in learning more about Go.
🌐
gosamples
gosamples.dev › tutorials › round float to any precision in go
🎠 Round float to any precision in Go
April 24, 2023 - To round a float in this way, you must set the formatting verb %f as an argument to these functions with a precision value of %.nf where n specifies the precision, that is, the number of decimal places.
🌐
YourBasic
yourbasic.org › golang › round-float-to-int
Round float to integer value · YourBasic Go
yourbasic.org/golang · Round away from zero · Round to even number · Convert to an int type · Before Go 1.10 · Use math.Round to return the nearest integer, as a float64, rounding ties away from zero. fmt.Println(math.Round(-0.6)) // -1 fmt.Println(math.Round(-0.4)) // -0 fmt.Println(...
🌐
Go
go.dev › src › math › big › float.go
float.go
1433 // 1434 // When the sum of two operands with opposite signs (or the difference of 1435 // two operands with like signs) is exactly zero, the sign of that sum (or 1436 // difference) shall be +0 in all rounding-direction attributes except 1437 // roundTowardNegative; under that attribute, the sign of an exact zero 1438 // sum (or difference) shall be −0. However, x+x = x−(−x) retains the same 1439 // sign as x even when x is zero. 1440 // 1441 // See also: https://play.golang.org/p/RtH3UCt5IH 1442 1443 // Add sets z to the rounded sum x+y and returns z.
🌐
Reddit
reddit.com › r/golang › how to round big.float to two decimal places
r/golang on Reddit: How to round big.Float to two decimal places
June 13, 2018 -

Hello, I'm couple of months into Go, but I'm struggling with a quite basic question. I need to precisely divide decimals and round them to two (or n) decimal places. I know there are external libraries to do calculations with decimals, but I'm looking to solve this with the standard library.

This is where I am so far: https://play.golang.org/p/i54VaI747nM

🌐
Programming.Guide
programming.guide › go › round-float-2-decimal-places.html
Go: Round float to 2 decimal places | Programming.Guide
f := 12.3456 fmt.Println(math.Floor(f*100)/100, // 12.34 (round down) math.Round(f*100)/100, // 12.35 (round to nearest) math.Ceil(f*100)/100) // 12.35 (round up) Due to the quirks of floating point representation, these rounded values may be slightly off.
Find elsewhere
🌐
DEV Community
dev.to › natamacm › round-numbers-in-go-5c01
Round numbers in Go - DEV Community
May 10, 2020 - func round(x float64){ return int(math.Floor(x + 0.5)) } ... package main import ( "fmt" "math" ) func round(x float64) int{ return int(math.Floor(x + 0.5)) } func main(){ fmt.Println(round(1.4)) fmt.Println(round(1.5)) fmt.Println(round(1.6)) }
🌐
Cockroach Labs
cockroachlabs.com › home › resources › blog › survey of rounding implementations in go
Survey of rounding implementations in Go
July 6, 2017 - That is, given a float64, truncate the fractional part (anything right of the decimal point), and add one to the truncated value if the fractional part was >= 0.5. This problem doesn't come up often, but it does enough that as of this writing, ...
🌐
Google Groups
groups.google.com › g › golang-nuts › c › JlUWmeDtkZY
keep just 2 decimal places in a float64
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/46cadc14-9c8e-4c3a-9c6b-d0af7b621061@googlegroups.com. ... Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message ... Even if fixed supports 7 decimal places, those 7 decimal places should have the same value (after rounding) as the result provided by math.Big.
Top answer
1 of 1
109

Foreword: I released this utility in github.com/icza/gox, see mathx.Round().


Go 1.10 has been released, and it adds a math.Round() function. This function rounds to the nearest integer (which is basically a "round to nearest 1.0" operation), and using that we can very easily construct a function that rounds to the unit of our choice:

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

Testing it:

fmt.Println(Round(0.363636, 0.05)) // 0.35
fmt.Println(Round(3.232, 0.05))    // 3.25
fmt.Println(Round(0.4888, 0.05))   // 0.5

fmt.Println(Round(-0.363636, 0.05)) // -0.35
fmt.Println(Round(-3.232, 0.05))    // -3.25
fmt.Println(Round(-0.4888, 0.05))   // -0.5

Try it on the Go Playground.

The original answer follows which was created before Go 1.10 when no math.Round() existed, and which also details the logic behind our custom Round() function. It's here for educational purposes.


In the pre-Go1.10 era there was no math.Round(). But...

Rounding tasks can easily be implemented by a float64 => int64 converison, but care must be taken as float to int conversion is not rounding but keeping the integer part (see details in Go: Converting float64 to int with multiplier).

For example:

var f float64
f = 12.3
fmt.Println(int64(f)) // 12
f = 12.6
fmt.Println(int64(f)) // 12

Result is 12 in both cases, the integer part. To get the rounding "functionality", simply add 0.5:

f = 12.3
fmt.Println(int64(f + 0.5)) // 12
f = 12.6
fmt.Println(int64(f + 0.5)) // 13

So far so good. But we don't want to round to integers. If we'd wanted to round to 1 fraction digit, we would multiply by 10 before adding 0.5 and converting:

f = 12.31
fmt.Println(float64(int64(f*10+0.5)) / 10) // 12.3
f = 12.66
fmt.Println(float64(int64(f*10+0.5)) / 10) // 12.7

So basically you multiply by the reciprocal of the unit you want to round to. To round to 0.05 units, multiply by 1/0.05 = 20:

f = 12.31
fmt.Println(float64(int64(f*20+0.5)) / 20) // 12.3
f = 12.66
fmt.Println(float64(int64(f*20+0.5)) / 20) // 12.65

Wrapping this into a function:

func Round(x, unit float64) float64 {
    return float64(int64(x/unit+0.5)) * unit
}

Using it:

fmt.Println(Round(0.363636, 0.05)) // 0.35
fmt.Println(Round(3.232, 0.05))    // 3.25
fmt.Println(Round(0.4888, 0.05))   // 0.5

Try the examples on the Go Playground.

Note that rounding 3.232 with unit=0.05 will not print exactly 3.25 but 0.35000000000000003. This is because float64 numbers are stored using finite precision, called the IEEE-754 standard. For details see Golang converting float64 to int error.

Also note that unit may be "any" number. If it's 1, then Round() basically rounds to nearest integer number. If it's 10, it rounds to tens, if it's 0.01, it rounds to 2 fraction digits.

Also note that when you call Round() with a negative number, you might get surprising result:

fmt.Println(Round(-0.363636, 0.05)) // -0.3
fmt.Println(Round(-3.232, 0.05))    // -3.2
fmt.Println(Round(-0.4888, 0.05))   // -0.45

This is because –as said earlier– conversion is keeping the integer part, and for example integer part of -1.6 is -1 (which is greater than -1.6; while integer part of 1.6 is 1 which is less than 1.6).

If you want -0.363636 to become -0.35 instead of -0.30, then in case of negative numbers add -0.5 instead of 0.5 inside the Round() function. See our improved Round2() function:

func Round2(x, unit float64) float64 {
    if x > 0 {
        return float64(int64(x/unit+0.5)) * unit
    }
    return float64(int64(x/unit-0.5)) * unit
}

And using it:

fmt.Println(Round2(-0.363636, 0.05)) // -0.35
fmt.Println(Round2(-3.232, 0.05))    // -3.25
fmt.Println(Round2(-0.4888, 0.05))   // -0.5

EDIT:

To address your comment: because you don't "like" the non-exact 0.35000000000000003, you proposed to format it and re-parse it like:

formatted, err := strconv.ParseFloat(fmt.Sprintf("%.2f", rounded), 64)

And this "seemingly" results in the exact result as printing it gives 0.35 exactly.

But this is just an "illusion". Since 0.35 cannot be represented with finite bits using IEEE-754 standard, doesn't matter what you do with the number, if you store it in a value of type float64, it won't be exactly 0.35 (but an IEEE-754 number being very close to it). What you see is fmt.Println() printing it as 0.35 because fmt.Println() already does some rounding.

But if you attempt to print it with higher precision:

fmt.Printf("%.30f\n", Round(0.363636, 0.05))
fmt.Printf("%.30f\n", Round(3.232, 0.05))
fmt.Printf("%.30f\n", Round(0.4888, 0.05))

Output: it's not nicer (might be even uglier): try it on the Go Playground:

0.349999999999999977795539507497
3.250000000000000000000000000000
0.500000000000000000000000000000

Note that on the other hand 3.25 and 0.5 are exact because they can be represented with finite bits exactly, because representing in binary:

3.25 = 3 + 0.25 = 11.01binary
0.5 = 0.1binary

What's the lesson? It's not worth formatting and re-parsing the result, as it won't be exact either (just a different float64 value which –according to default fmt.Println() formatting rules– might be nicer in printing). If you want nice printed format, just format with precision, like:

func main() {
    fmt.Printf("%.3f\n", Round(0.363636, 0.05))
    fmt.Printf("%.3f\n", Round(3.232, 0.05))
    fmt.Printf("%.3f\n", Round(0.4888, 0.05))
}

func Round(x, unit float64) float64 {
    return float64(int64(x/unit+0.5)) * unit
}

And it will be exact (try it on the Go Playground):

0.350
3.250
0.500

Or just multiply them by 100 and work with integer numbers, so that no representation or rounding error may occur.

🌐
Linux Hint
linuxhint.com › round-float-values-golang
Golang Round
The math.Round() function allows you to round a float to the nearest integer, rounding halfway from zero.
🌐
GitHub
github.com › mhale › round
GitHub - mhale/round: A floating-point number rounding package for Go. · GitHub
A floating-point number rounding package for Go. Contribute to mhale/round development by creating an account on GitHub.
Author   mhale
🌐
GeeksforGeeks
geeksforgeeks.org › math-round-function-in-golang-with-examples
math.Round() Function in Golang With Examples - GeeksforGeeks
April 13, 2020 - func Round(a float64) float64 · If you pass -Inf or +Inf in this function like Round(-Inf) or Round(+Inf), then this function will return -Inf or +Inf. If you pass -0 or +0 in this function like Round(-0) or Round(+0), then this function will return -0 or +0. If you pass NaN in this function like Round(NaN), then this function will return NaN. Example 1: C · // Golang program to illustrate how to // round off the given number to the // nearest integer package main import ( "fmt" "math" ) // Main function func main() { // Finding the nearest integer // of the given numbers // Using Round() fu
🌐
GitHub
github.com › golang › go › issues › 20100
math: add Round · Issue #20100 · golang/go
April 24, 2017 - What version of Go are you using (go version)? 1.8 What did you expect to see? A rounding method for floats in the standard library What did you see instead? There is no standard library method for rounding a float64 to int/int32 I would...
Author   DavidR91
🌐
Golang.cafe
golang.cafe › blog › golang-round-float-to-int-example
Golang Round Float To Int Example | Golang.cafe
April 27, 2022 - In this article we are going to see how to round a float64 or float32 to integer value in Go
🌐
Go
go.dev › play › p › z6KIWcUNnT
Go Playground - The Go Programming Language
Any requests for content removal should be directed to security@golang.org.
🌐
GitHub
github.com › golang › go › issues › 4594
math: add a Round function · Issue #4594 · golang/go
December 28, 2012 - by bunge@google.com: Would it be possible to add a math.Round(n float64, digits uint) float64 function that rounds a floating point number to the specified number of digits? This has been discussed on golang-nuts here: https://groups.goo...
Author   gopherbot