[Solved] IEEE 754 binary floating-point numbers imprecise for money


The original question:


Incorrect floor number in golang

I have problem when use Math.Floor with float variable (round
down/truncate the precision part). How can i do it correctly?

package main

import (
    "fmt"
    "math"
)

func main() {
    var st float64 = 1980
    var salePrice1 = st * 0.1 / 1.1
    fmt.Printf("%T:%v\n", salePrice1, salePrice1)
    var salePrice2 = math.Floor(st * 0.1 / 1.1)
    fmt.Printf("%T:%v\n", salePrice2, salePrice2)
}

I expect the output of 1980 * 0.1 / 1.1 to be 180, but the actual
output is 179.”

Playground:

Output:

float64:179.99999999999997
float64:179

The XY problem is asking about your attempted solution rather than your actual problem: The XY Problem.


Clearly, this is a money calculation for salePrice1. Money calculations use precise decimal calculations, not imprecise binary floating-point calculations.

For money calculations use integers. For example,

package main

import "fmt"

func main() {
    var st int64 = 198000 // $1980.00 as cents

    fmt.Printf("%[1]T:%[1]v\n", st)
    fmt.Printf("$%d.%02d\n", st/100, st%100)

    var n, d int64 = 1, 11
    fmt.Printf("%d, %d\n", n, d)

    var salePrice1 int64 = (st * n) / d // round down

    fmt.Printf("%[1]T:%[1]v\n", salePrice1)
    fmt.Printf("$%d.%02d\n", salePrice1/100, salePrice1%100)

    var salePrice2 int64 = ((st*n)*10/d + 5) / 10 // round half up

    fmt.Printf("%[1]T:%[1]v\n", salePrice2)
    fmt.Printf("$%d.%02d\n", salePrice2/100, salePrice2%100)

    var salePrice3 int64 = (st*n + (d - 1)) / d // round up

    fmt.Printf("%[1]T:%[1]v\n", salePrice1)
    fmt.Printf("$%d.%02d\n", salePrice3/100, salePrice3%100)
}

Playground: https://play.golang.org/p/HbqVJUXXR-N

Output:

int64:198000
$1980.00
1, 11
int64:18000
$180.00
int64:18000
$180.00
int64:18000
$180.00

References:

What Every Computer Scientist Should Know About Floating-Point Arithmetic

How should we calc money (decimal, big.Float)

General Decimal Arithmetic

6

solved IEEE 754 binary floating-point numbers imprecise for money