Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang - float to int conversion

My problem looks like very simple, but I cat not solve it yet.. User enters a money amount xx.xx as a string. After that I convert string to float value (some dollars, some cents), for example, let it be 655.18 (float64) Then, I need to convert this amount to cents - 655.18*100 and the result is 65517.9999999, so when I cast this value to int, I get 65517, so 1 cent was lost. How can I avoid this behaviour?

Code:

package main

import (
    "fmt"
    "strconv"
)

func CheckParamsPur(sa string) (amount float64) {
    amount, _ = strconv.ParseFloat(sa, 64)
    return amount
}

func main() {

    fmt.Print("Enter a number: ")
    var input string
    fmt.Scanf("%s", &input)
    amount := int(CheckParamsPur(input) * (100))

    fmt.Println(amount)

}
like image 837
Олег Сидоров Avatar asked Dec 06 '22 13:12

Олег Сидоров


1 Answers

From string to float to integer

If you first want to start with parsing the amount to a float, then in the next step instead of converting, use rounding.

Since conversion keeps the integer part, add 0.5 to it before converting. So if the fraction part was less than 0.5, adding 0.5 will not increase the integer part and so after conversion the integer part will be the same (rounding down). If fraction part was greater than 0.5, adding 0.5 to it will increase the integer part, and after conversion we get 1 higher of the original integer part (rounding up).

In your case, after multiplying by 100, add 0.5 before doing the conversion :

f := 655.17
i := int(f*100 + 0.5)
fmt.Println(i)

Output (try it on the Go Playground):

65517

Read related question which covers this and more: Golang Round to Nearest 0.05

Parsing integer and fraction parts separately, as 2 integers

Another option is to skip floating point numbers entirely. To do that, we can parse the input string which supposed to hold a floating point number as 2 integers separated by a dot .: "dollars.cents" (where dollars and cents are both integers):

s := "655.17"

var dollars int64
var cents uint64
if _, err := fmt.Sscanf(s, "%d.%d", &dollars, &cents); err != nil {
    panic(err)
}
if cents > 99 {
    panic("cents cannot be greater than 99")
}

var total int64
if dollars >= 0 {
    total = dollars*100 + int64(cents)
} else {
    total = dollars*100 - int64(cents)
}
fmt.Println(total)

Output again is (try it on the Go Playground):

65517

Note: The above parsing code requires you to enter cents using 2 digits, e.g. 655.70, entering 655.7 would give bad results.

like image 145
icza Avatar answered Dec 20 '22 10:12

icza