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
CODE EXAMPLE How to round a float to a string/float with 2 decimal places in Go.
Discussions

float64 precision

Because it isn't a language problem but a problem with how floats are represented in general.

https://stackoverflow.com/questions/21895756/why-are-floating-point-numbers-inaccurate

More on reddit.com
🌐 r/golang
15
3
February 5, 2017
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
🌐
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 - 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 the number of precisions). ... // Golang program to truncate float value // to a particular precision package main import ( "fmt" ) func main() ...
🌐
Google Groups
groups.google.com › g › golang-nuts › c › JlUWmeDtkZY
keep just 2 decimal places in a float64
I was not aware of URL https://0.30000000000000004.com/. Like the XY problem URL, http://xyproblem.info/, the URL you cited is another one to remember to cite when a FAQ about floating point values occurs :-) ... Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message ... > https://play.golang.org/p/87bDubJxjHO > > I'd like to truncate a float64 to just 2 decimal places (in base 10), > but math.Trunc is not helping me here...
🌐
Go
go.dev › play › p › KNhgeuU5sT
Go Playground - The Go Programming Language
Any requests for content removal should be directed to security@golang.org.
🌐
Ispycode
ispycode.com › Blog › golang › 2016-10 › Truncating-floats-to-a-particular-precision-in-golang
Truncating floats to a particular precision in golang | golang blog
Here is a go lang example that shows how to truncate floats in go lang: package main import ( "fmt" "strconv" ) func main() { f := 10 / 3.0 fmt.Println(f) // 2 decimal points using string format float precision fmt.Printf("%.2f \n", f) // 3 decimal points using strconv.FormatFloat str := strconv.FormatFloat(f, 'f', 3, 64) fmt.Println(str) }
🌐
gosamples
gosamples.dev › tutorials › round float to any precision in go
🎠 Round float to any precision in Go
April 24, 2023 - In Go, there is another way of rounding numbers often called float truncation. The difference from classical rounding is that you get the result in the form of a string, as truncating is carried out by the formatting function fmt.Sprintf() or fmt.Printf().
Top answer
1 of 2
11

The naive way (not always correct)

For truncation, we could take advantage of math.Trunc() which throws away the fraction digits. This is not exactly what we want, we want to keep some fraction digits. So in order to achieve what we want, we may first multiply the input by a power of 10 to shift the wanted fraction digits to the "integer" part, and after truncation (calling math.Trunc() which will throw away the remaining fraction digits), we can divide by the same power of 10 we multiplied in the beginning:

f2 := math.Trunc(f*1000) / 1000

Wrapping this into a function:

func truncateNaive(f float64, unit float64) float64 {
    return math.Trunc(f/unit) * unit
}

Testing it:

f := 1.234567
f2 := truncateNaive(f, 0.001)
fmt.Printf("%.10f\n", f2)

Output:

1.2340000000

So far so good, but note that we perform arithmetic operations inside truncateNaive() which may result in unwanted roundings, which could alter the output of the function.

For example, if the input is 0.299999999999999988897769753748434595763683319091796875 (it's representable by a float64 value exactly, see proof), the output should be 0.2999000000, but it will be something else:

f = 0.299999999999999988897769753748434595763683319091796875
f2 = truncateNaive(f, 0.001)
fmt.Printf("%.10f\n", f2)

Output:

0.3000000000

Try these on the Go Playground.

This wrong output is probably not acceptable in most cases (except if you look at it from a way that the input is very close to 0.3–difference is less than 10-16–to which the output is 0.3...).

Using big.Float

To properly truncate all valid float64 values, the intermediate operations must be precise. To achieve that, using a single float64 is insufficient. There are ways to split the input into 2 float64 values and perform operations on them (so precision is not lost) which would be more efficient, or we could use a more convenient way, big.Float which can be of arbitrary precision.

Here's the "transcript" of the above truncateNaive() function using big.Float:

func truncate(f float64, unit float64) float64 {
    bf := big.NewFloat(0).SetPrec(1000).SetFloat64(f)
    bu := big.NewFloat(0).SetPrec(1000).SetFloat64(unit)

    bf.Quo(bf, bu)

    // Truncate:
    i := big.NewInt(0)
    bf.Int(i)
    bf.SetInt(i)

    f, _ = bf.Mul(bf, bu).Float64()
    return f
}

Testing it:

f := 1.234567
f2 := truncate(f, 0.001)
fmt.Printf("%.10f\n", f2)

f = 0.299999999999999988897769753748434595763683319091796875
f2 = truncate(f, 0.001)
fmt.Printf("%.10f\n", f2)

Output is now valid (try it on the Go Playground):

1.2340000000
0.2990000000
2 of 2
0

You need to truncate decimals manually, either on string level or with math.Floor like https://play.golang.org/p/UP2gFx2iFru.

Find elsewhere
🌐
GitHub
github.com › Mohitp98 › Golang-Course › blob › main › Course-01 › Week-02 › trunc.go
Golang-Course/Course-01/Week-02/trunc.go at main · Mohitp98/Golang-Course
fmt.Println("Enter a Float number:=>") _, err := fmt.Scan(&inputNumber) if err != nil { log.Printf("[Error] Invalid input !") } · fmt.Printf("The number you've entered is '%v'.\n", inputNumber) fmt.Printf("Truncated version of '%v' is '%v'.\n", inputNumber, int64(inputNumber)) }
Author   Mohitp98
🌐
Google Groups
groups.google.com › g › golang-nuts › c › P51atQ_XCyE
truncate float32 to lesser precision (22 bit mantissa)
However, to answer your specific question, yes you can easily truncate float32 to a lower precision. Just force the bits you want to truncate to zero. ... Mask would be used to discard the lower bits of the word and thus precision. ... -- You received this message because you are subscribed ...
🌐
Programming Idioms
programming-idioms.org › idiom › 80 › truncate-floating-point-number-to-integer › 1178 › go
Truncate floating point number to integer, in Go
Declare integer y and initialize it with the value of floating point number x . Ignore non-integer digits of x . Make sure to truncate towards zero: a negative x must yield the closest greater integer (not lesser).
🌐
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, ...
🌐
Boot.dev
blog.boot.dev › golang › round-float-golang
How to Round a Float in Go | Boot.dev
November 13, 2022 - If you’re rounding a floating point number in Go, it’s most likely you want to format it in a string. Use the built-in fmt.Sprintf() function.
🌐
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

🌐
Reddit
reddit.com › r/golang › why are my floats sometimes getting calculated and formatted differently?
r/golang on Reddit: Why are my floats sometimes getting calculated and formatted differently?
August 3, 2023 -

Hi,

I have a block of code that creates pairs of min and max values based on a given major and minor increment and a starting value. Oddly enough, certain floats are calculated differently, which doesn't make sense to me. Can someone explain why this is happening and how I can prevent it?

-10 -9.1-9 -8.1-8 -7.1-7 -6.1-6 -5.1-5 -4.1-3.9999999999999996 -3.0999999999999996-2.9999999999999996 -2.0999999999999996-1.9999999999999996 -1.0999999999999996-0.9999999999999997 -0.09999999999999964

In my example, the floats in the output after (-5, -4.1) get rendered with 16 decimal places whereas all of the previous floats only get rendered with a maximum of 1 decimal place. Also, the float variables have those decimal places (so I don't think that the fmt printf call is skewing the numbers), which is throwing off some of my downstream logic.

minValueExclNaN := float64(-10)
minValue := math.NaN()
maxValue := float64(0)
incrementMinor := float64(0.1)
incrementMajor := float64(1)

for i := 0; i < 11; i++ {
	if i == 0 {
		maxValue = minValueExclNaN - incrementMinor
	} else {
		if math.IsNaN(minValue) {
			minValue = minValueExclNaN
		} else {
			minValue = maxValue + incrementMinor
		}

		maxValue += incrementMajor

		// swap minValue and maxValue
		if minValue > maxValue {
			maxValue, minValue = minValue, maxValue
		}

		fmt.Printf("%v %v\n", minValue, maxValue)
	}
}

I have a Go Playground repro here: https://play.golang.com/p/AtlyAeMankv

Thanks!

🌐
YourBasic
yourbasic.org › golang › round-float-to-int
Round float to integer value · YourBasic Go
Note that when converting a floating-point number to an int type, the fraction is discarded (truncation towards zero).
🌐
Go
go.dev › src › math › big › float.go
float.go
163 // If prec > [MaxPrec], it is set to [MaxPrec]. 164 func (z *Float) SetPrec(prec uint) *Float { 165 z.acc = Exact // optimistically assume no rounding is needed 166 167 // special case 168 if prec == 0 { 169 z.prec = 0 170 if z.form == finite { 171 // truncate z to 0 172 z.acc = makeAcc(z.neg) 173 z.form = zero 174 } 175 return z 176 } 177 178 // general case 179 if prec > MaxPrec { 180 prec = MaxPrec 181 } 182 old := z.prec 183 z.prec = uint32(prec) 184 if z.prec < old { 185 z.round(0) 186 } 187 return z 188 } 189 190 func makeAcc(above bool) Accuracy { 191 if above { 192 return Above 193 } 194 return Below 195 } 196 197 // SetMode sets z's rounding mode to mode and returns an exact z.
🌐
GitHub
gist.github.com › Cerebrovinny › 6d7394b5d2e80fc2a2cb0249e7995678
Get user input in float64 and truncate to integer · GitHub
Get user input in float64 and truncate to integer · Raw · trunc.go · This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
🌐
GitHub
github.com › golang › go › blob › master › src › math › big › float.go
go/src/math/big/float.go at master · golang/go
func (z *Float) SetPrec(prec uint) *Float { z.acc = Exact // optimistically assume no rounding is needed · · // special case · if prec == 0 { z.prec = 0 · if z.form == finite { // truncate z to 0 · z.acc = makeAcc(z.neg) z.form = zero ·
Author   golang