0

I was very surprised when started to work with the type of floating-point (float32 & float64). In this example, I have collected only a few options from the set:

package main

import (
    "fmt"
)

func main() {
    var sum, price, count float64
    sum, price, count = 1000, 166.67, 5
    fmt.Printf("%v - %v * %v = %v\n", sum, price, count, sum-price*count)
    price, count = 7.35, 3
    fmt.Printf("%v * %v = %v\n", price, count, price*count)
    var a, b, c float64
    a, b = 2, 1.1
    fmt.Printf("%v - %v = %v\n", a, b, a-b)
    a, b, c = 0.1, 0.2, 0.3
    fmt.Printf("%v + %v - %v = %v\n", a, b, c, a+b-c)
}

It prints:

1000 - 166.67 * 5 = 166.6500000000001
7.35 * 3 = 22.049999999999997
2 - 1.1 = 0.8999999999999999
0.1 + 0.2 - 0.3 = 5.551115123125783e-17
2.4 / 0.1 = 23.999999999999996

The problem occurs after the execution of arithmetic operations: +, -, *, /

Now I'm absolutely not sure that my algorithm would give me the correct result.

I solved the problem by normalized the value after each operation - rounded up to the lower accuracy than the error:

package main

import (
    "fmt"
    "math"
)

func main() {
    var sum, price, count float64
    sum, price, count = 1000, 166.67, 5
    fmt.Printf("%v - %v * %v = %v\n", sum, price, count, Normalize(sum-price*count))
    price, count = 7.35, 3
    fmt.Printf("%v * %v = %v\n", price, count, Normalize(price*count))
    var a, b, c float64
    a, b = 2, 1.1
    fmt.Printf("%v - %v = %v\n", a, b, Normalize(a-b))
    a, b, c = 0.1, 0.2, 0.3
    fmt.Printf("%v + %v - %v = %v\n", a, b, c, Normalize(a+b-c))
    a, b = 2.4, 0.1
    fmt.Printf("%v / %v = %v\n", a, b, Normalize(a/b))
}

func Normalize(value float64) float64 {
    return RoundViaFloat(value, 4)
}

func RoundViaFloat(x float64, prec int) float64 {
    var rounder float64
    pow := math.Pow(10, float64(prec))
    intermed := x * pow
    _, frac := math.Modf(intermed)
    x = .5
    if frac < 0.0 {
        x = -.5
    }
    if frac >= x {
        rounder = math.Ceil(intermed)
    } else {
        rounder = math.Floor(intermed)
    }
    return rounder / pow
}

It prints:

1000 - 166.67 * 5 = 166.65
7.35 * 3 = 22.05
2 - 1.1 = 0.9
0.1 + 0.2 - 0.3 = 0
2.4 / 0.1 = 24

But it seems to me, is not normal :-(

Can anyone help me solve this problem?

thanx

  • 2
    This is a standard rounding error that is fundamental to any implementation of binary floating point (or any base other than 10). For a deeper background see http://floating-point-gui.de/ – Rob Napier Nov 20 '15 at 16:49
  • I thought that if you write a number on the base 10, the program must keep it and perform operations in the same format? – user5586250 Nov 21 '15 at 20:57
  • That was your mistake. Hopefully the links will help you understand floating point better. Good luck! – Rob Napier Nov 21 '15 at 21:48

0 Answers0