Float subtractions issues


(Taalhach) #1

hey every gopher hope you will be fine
i am working on financial project and here i have float64 that stores user balance but when i subtract a balance it gives me lower value i want to fix that
code snippet
package main

import (
“fmt”
)
type Order struct {
amount,price,fee float64

}
const ( Fee=0.000141)
func main() {
a:=Order{
price: 0.5,
amount: 0.008,
}
a.amount-=Fee*0.0001
fmt.Println(a.amount)
}

result should be = 0.0079999859
but go compiler returns = 0.007999985900000001

is there any way i can fix that with float64 ?

link https://play.golang.org/p/FBHkx2qxsJQ


(Norbert Melzer) #2

No.

A float simply can’t represent the exact value, that’s why we have suggested multiple times to not use float for financial stuff.


(Taalhach) #3

what should i do use int or use big.Float ?


(Norbert Melzer) #4

A fixed point data type of your choice that is capable of representing any value in your expected domain.


(Jay Ts) #5

Hi,

As part of your coding project, I suggest you stop coding and study this issue carefully before continuing. (Especially if it is for actual use in business, rather than just a personal project or experiment.) There is no simple answer, and you will need to study and think about your options and your needs before developing code.

The best way I know of to handle financial calculations is to use a language with good support for them by doing arithmetic in decimal rather than binary. Once upon a time, that meant using COBOL, and it was one of the biggest reasons why COBOL was so popular and had such a long lifetime.

Even today, this is a difficult topic. Here are some web pages I found that may help you get started:

Short discussion of issue on Intel website: https://software.intel.com/en-us/blogs/2008/03/06/intel-decimal-floating-point-math-library/

Wikipedia on decimal floating-point: https://en.wikipedia.org/wiki/Decimal_floating_point

Discussions of proposals to include a decimal type in Go:


and I found a few libraries you can learn about:



Doing it “right” can be complicated and ugly.

Disclaimer: I am not recommending anything, and this is outside my usual area of expertise, so please don’t take anything I wrote as definitive.


(Taalhach) #6

@jayts thank you i am working on it no


(George Calianu) #7

I don’t know how useful is but this will do the job.

 fmt.Printf("%.10f",a.amount)

(Derek Kenney) #8

I’ve used this package for float to decimal casting. It works well. https://github.com/shopspring/decimal


(Onezino Moreira) #9

I, I have a application that store value as int, and as a requirement, only 4 decimal digits as valid decimal digit. So every operation is made in int value and presentation is in 2 decimal digits.


(Taalhach) #10

Thank you I @geosoft1 appreciate your help and your comment but i want to use floats into calculations so that this can’t be used there it can only be used to print decimal digits of a number


(Taalhach) #11

does this solve the issue of precision and exact value issues of float?


(Taalhach) #12

this is what exactly i did now i changed the float64 to unit amount as int64 now it works well but i have to divide these with total when i am saving them into db or sending values from server to clients


(Derek Kenney) #13

Write a unit test using the package, and find out.


(George Calianu) #14

A trivial solution and probably slow can be a function like this :man_facepalming:

func floatPrecision(n float64, precision int) float64 {
	format:=fmt.Sprintf("%%.%df",precision)
	r,_:=strconv.ParseFloat(fmt.Sprintf(format,n),64)
	return r
}

(Taalhach) #15

on it thanks btw <3


(Taalhach) #16

let me check this way
Thanks btw <3


(Norbert Melzer) #17

This will probably make things worse.

1.23 with a precision of 1 might get parsed as 1.19, because it’s printed as 1.2, and when parsing floats the IEEE specifies, that they have to be parsed into the next smaller number that can be represented.

If you are working with floats, there is no way around rounding issues, except not using floats!


(Taalhach) #18

exactly i tried this but that rounding came in to my way
so now i have gone into int64 and using unit of currencies instead of using bigger values
Thank you @NobbZ you always gave best advice :slight_smile: