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
🌐
Reddit
reddit.com › r/golang › float64 precision
r/golang on Reddit: float64 precision
February 5, 2017 -

Sorry, this feels like something really simple that I'm missing. And it is something that happens in other languages, like js... but it doesn't hurt to ask.

So I have the following (I'm adding 0.01 to a variable in a loop):

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

I understand what is going on, there's a loss of precision, but how can I avoid it?

EDIT: in golang we don't have a toFixed(). I managed to fix it but I was checking if you guys know what is the best way to solve this issue.

Edit2: thank you guys for the answers. I ended up using David Calhoun's answer here: http://stackoverflow.com/questions/18390266/how-can-we-truncate-float64-type-to-a-particular-precision-in-golang

Discussions

go - Golang floating point precision float32 vs float64 - Stack Overflow
I wrote a program to demonstrate floating point error in Go: func main() { a := float64(0.2) a += 0.1 a -= 0.3 var i int for i = 0; a More on stackoverflow.com
🌐 stackoverflow.com
Use postgres double precision for Golang float64
It looks like fields declared as float without a scale or precision are migrated/created as SQL decimal: postgres/postgres.go Lines 140 to 147 in e552243 case schema.Float: if field.Precision > ... More on github.com
🌐 github.com
3
December 30, 2020
How do you handle decimals in go?
Float64 will lose precision. struct of ints? More on reddit.com
🌐 r/golang
10
0
February 9, 2024
Why are my floats sometimes getting calculated and formatted differently?
Congratulations, you've discovered that floating-point math is weird! https://0.30000000000000004.com/ The short answer is that floats store an approximation of the number, and the formatter sometimes is able to truncate it to look like all that extra precision isn't there, but over time the inaccuracy adds up. More on reddit.com
🌐 r/golang
6
0
August 3, 2023
🌐
Go
go.dev › src › math › big › float.go
- The Go Programming Language
545 return z.setBits64(x < 0, uint64(u)) 546 } 547 548 // SetFloat64 sets z to the (possibly rounded) value of x and returns z. 549 // If z's precision is 0, it is changed to 53 (and rounding will have 550 // no effect). SetFloat64 panics with [ErrNaN] if x is a NaN.
🌐
Leapcell
leapcell.io › blog › understanding-floating-point-numbers-in-go
Understanding Floating-Point Numbers in Go | Leapcell
July 25, 2025 - By utilizing the decimal package, the addition of 0.1 and 0.2 yields the expected result of 0.3, ensuring precision in calculations. Prefer float64 over float32: Due to its higher precision and wider range, float64 is generally the preferred ...
🌐
gosamples
gosamples.dev › tutorials › round float to any precision in go
🎠 Round float to any precision in Go
April 24, 2023 - package main import ( "fmt" "math" ) func roundFloat(val float64, precision uint) float64 { ratio := math.Pow(10, float64(precision)) return math.Round(val*ratio) / ratio } func main() { number := 12.3456789 fmt.Println(roundFloat(number, 3)) }
🌐
Medium
waclawthedev.medium.com › inaccurate-float32-and-float64-how-to-avoid-the-trap-in-go-golang-6de59e66aed9
Inaccurate float32 and float64: how to avoid the trap in Go (golang) | by Wacław The Developer | Medium
December 14, 2021 - var progressPercentage float64 = 0 for ; ; { //Do some work and add to overall progress 1% progressPercentage += 0.01 //Check if 100% reached (1 will never be reached.
🌐
Go Packages
pkg.go.dev › math › big
big package - math/big - Go Packages
Float64 returns the float64 value nearest to x. If x is too small to be represented by a float64 (|x| < math.SmallestNonzeroFloat64), the result is (0, Below) or (-0, Above), respectively, depending on the sign of x. If x is too large to be represented by a float64 (|x| > math.MaxFloat64), ...
🌐
ZetCode
zetcode.com › golang › builtins-float64-type
Understanding the float64 Type in Golang
May 8, 2025 - The float64 type represents 64-bit floating-point numbers in Go. It provides about 15 decimal digits of precision and is the default type for floating-point literals.
Find elsewhere
🌐
Exercism
exercism.org › tracks › go › concepts › floating-point-numbers
Floating-Point Numbers in Go on Exercism
Different floating-point types can store different numbers of digits after the digit separator - this is referred to as its precision. ... As can be seen, both types can store a different number of digits.
Top answer
1 of 2
36

Using math.Float32bits and math.Float64bits, you can see how Go represents the different decimal values as a IEEE 754 binary value:

Playground: https://play.golang.org/p/ZqzdCZLfvC

Result:

float32(0.1): 00111101110011001100110011001101
float32(0.2): 00111110010011001100110011001101
float32(0.3): 00111110100110011001100110011010
float64(0.1): 0011111110111001100110011001100110011001100110011001100110011010
float64(0.2): 0011111111001001100110011001100110011001100110011001100110011010
float64(0.3): 0011111111010011001100110011001100110011001100110011001100110011

If you convert these binary representation to decimal values and do your loop, you can see that for float32, the initial value of a will be:

0.20000000298023224
+ 0.10000000149011612
- 0.30000001192092896
= -7.4505806e-9

a negative value that can never never sum up to 1.

So, why does C behave different?

If you look at the binary pattern (and know slightly about how to represent binary values), you can see that Go rounds the last bit while I assume C just crops it instead.

So, in a sense, while neither Go nor C can represent 0.1 exactly in a float, Go uses the value closest to 0.1:

Go:   00111101110011001100110011001101 => 0.10000000149011612
C(?): 00111101110011001100110011001100 => 0.09999999403953552

Edit:

I posted a question about how C handles float constants, and from the answer it seems that any implementation of the C standard is allowed to do either. The implementation you tried it with just did it differently than Go.

2 of 2
18

Agree with ANisus, go is doing the right thing. Concerning C, I'm not convinced by his guess.

The C standard does not dictate, but most implementations of libc will convert the decimal representation to nearest float (at least to comply with IEEE-754 2008 or ISO 10967), so I don't think this is the most probable explanation.

There are several reasons why the C program behavior might differ... Especially, some intermediate computations might be performed with excess precision (double or long double).

The most probable thing I can think of, is if ever you wrote 0.1 instead of 0.1f in C.
In which case, you might have cause excess precision in initialization
(you sum float a+double 0.1 => the float is converted to double, then result is converted back to float)

If I emulate these operations

float32(float32(float32(0.2) + float64(0.1)) - float64(0.3))

Then I find something near 1.1920929e-8f

After 27 iterations, this sums to 1.6f

🌐
Medium
medium.com › pragmatic-programmers › testing-floating-point-numbers-in-go-9872fe6de17f
Testing Floating Point Numbers in Go | by Ricardo Gerardi | The Pragmatic Programmers | Medium
December 21, 2021 - Floating point notation, based on the IEEE-754 standard, is a way to represent real numbers using 32 or 64 bits encoding. However, even using 64-bit precision it’s impossible to store an infinite number of digits, which means these numbers ...
🌐
GitHub
github.com › go-gorm › postgres › issues › 28
Use postgres double precision for Golang float64 · Issue #28 · go-gorm/postgres
December 30, 2020 - It looks like fields declared as float without a scale or precision are migrated/created as SQL decimal: postgres/postgres.go Lines 140 to 147 in e552243 case schema.Float: if field.Precision > 0 { if field.Scale > 0 { fmt.Sprintf("numer...
Author   onwsk8r
🌐
YourBasic
yourbasic.org › golang › round-float-2-decimal-places
Round float to 2 decimal places · YourBasic Go
Round float to integer value has further details on how to round a float64 to an integer (away from zero, to even number, converted to an int type).
🌐
Educative
educative.io › answers › what-is-type-float64-in-golang
What is type float64 in Golang?
The numeric data type of float has one other version besides float64, float32. Compared to its 32-bit version, float64 can hold much larger decimal values and at far greater precision.
🌐
Go Packages
pkg.go.dev › github.com › shopspring › decimal
decimal package - github.com/shopspring/decimal - Go Packages
April 12, 2024 - InexactFloat64 returns the nearest float64 value for d. It doesn't indicate if the returned value represents d exactly. ... IntPart returns the integer component of the decimal. ... IsInteger returns true when decimal can be represented as an integer value, otherwise, it returns false. ... LessThan (LT) returns true when d is less than d2. ... LessThanOrEqual (LTE) returns true when d is less than or equal to d2. func (d Decimal) Ln(precision int32) (Decimal, error)
🌐
LabEx
labex.io › tutorials › go-how-to-control-float-number-formatting-419737
How to control float number formatting | LabEx
The float32 type has a precision of approximately 7 decimal digits, while the float64 type has a precision of approximately 15 decimal digits.
🌐
Google Groups
groups.google.com › g › golang-nuts › c › JlUWmeDtkZY
keep just 2 decimal places in a float64
... 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. I suspect ...
🌐
IncludeHelp
includehelp.com › golang › how-can-we-truncate-float-value-float32-float64-to-a-particular-precision-in-golang.aspx
How can we truncate float value (float32, float64) to a particular precision in Golang?
October 24, 2021 - Given a floating-point value, we have to truncate it to a particular precision in Golang. Submitted by IncludeHelp, on October 24, 2021 · In the Go programming language, a float value (float32, float64) can be truncated by using the format verb %f with precision value (i.e., %.nf – n is ...
🌐
Cockroach Labs
cockroachlabs.com › home › resources › blog › survey of rounding implementations in go
Survey of rounding implementations in Go
July 6, 2017 - Even when specifying 0 precision, it fails with: round(-0.49999999999999994): got: -1, want -0 round(0.49999999999999994): got: 1, want 0 · So still isn't usable. This is an old implementation from CockroachDB, before we used the Postgres algorithm.
🌐
Medium
medium.com › techtrends-digest › golang-why-float64-betrays-you-and-when-to-use-decimal-instead-41194e13601a
Golang: Why float64 Betrays You and When to Use Decimal Instead
December 2, 2025 - float64 uses binary floating-point representation. Many decimal values can't be represented exactly in binary.