hello everyone, i have a question,When i use WalletUpdate of nakama interface, i save float64 into database, And i use “strconv.ParseFloat(fmt.Sprintf(”%.2f", value), 64)" to covert value keep 2 digits at the decimal point, But i found something like this :
Your code looks correct:
value := 38480.820000000001
s, err := strconv.ParseFloat(fmt.Sprintf("%.2f", value), 64)
fmt.Println(s)
fmt.Println(err)
which prints out
38480.82
<nil>
Are you sure this isn’t a stale value from previous generation of your code? Can you wipe your records/database and try again?
Thanks your answer, I’ll try again.
Hello,This situation still occurs.
When I use WalletUpdate to record game result
as this:
I got wallet in users as this:
{“expeGold”: 10000, “gameGold”: 5070.699999999999, “safeboxGameGold”: 10}
add image
If i use WalletUpdate.
I found 4970.8+99.9 = 5070.699999999 instead of 5070.7
Can you paste your entire function code, including the Nakama hook definition (init_module) function please?
func WalletCoinOut(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, gameType int, userID string, gameGold float64, expeGold float64, score int64, oldGameGold float64, newGameGold float64) error {
gameGold = Decimal(gameGold)
expeGold = Decimal(expeGold)
oldGameGold = Decimal(oldGameGold)
newGameGold = Decimal(newGameGold)
changeset := make(map[string]interface{})
metadata := make(map[string]interface{})
if gameGold > 0 {
changeset["gameGold"] = gameGold
metadata["goldType"] = 0
metadata["payType"] = 0
metadata["income"] = gameGold
metadata["expenditure"] = 0
metadata["beforeGold"] = oldGameGold
metadata["afterGold"] = newGameGold
metadata["reportType"] = 1
}
err := nk.WalletUpdate(ctx, userID, changeset, metadata, true)
return nil
}
func Decimal(value float64) float64 {
reValue, _ := strconv.ParseFloat(fmt.Sprintf(“%.2f”, value), 64)return reValue
}
func WalletCoinOut(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, gameType int, userID string, gameGold float64, expeGold float64, score int64, oldGameGold float64, newGameGold float64) error {gameGold = Decimal(gameGold)
expeGold = Decimal(expeGold)
oldGameGold = Decimal(oldGameGold)
newGameGold = Decimal(newGameGold)changeset := make(map[string]interface{})
metadata := make(map[string]interface{})changeset[“gameGold”] = gameGold
metadata[“goldType”] = 0
metadata[“payType”] = 0
metadata[“income”] = gameGold
metadata[“expenditure”] = 0
metadata[“beforeGold”] = oldGameGold
metadata[“afterGold”] = newGameGold
metadata[“reportType”] = 1err := nk.WalletUpdate(ctx, userID, changeset, metadata, true)
return nil
}
What you’re seeing is floating point rounding errors. Since the wallet is stored as JSON and Go’s standard numeric type for JSON encoding/decoding is float64
, you’ll see this pop up if you don’t either work around it or compensate.
A good rule of thumb is to avoid storing decimals wherever possible. For example if you want to store a money amount of $1.73 store it in the wallet as whole cents (ie. 173
instead of 1.73
) and make sure transactions do not use fractions of cents. You can then handle conversion to dollars.cents
at display time.