bodokaiser
bodokaiser

Reputation: 15752

How to count decimal places of float?

I want to check if a float32 has two decimal places or not. My javascript way to do this would look like:

step  := 0.01
value := 9.99

if int(value/step) % 1 == 0 {
    printf("has two decimal places!")
}

The above example also works. However it will not work when step is incorrect as go then cannot properly cast from float64 to int.

Example:

step  := 0.1
value := 9.99

if int(value/step) % 1 == 0 {
    printf("has two decimal places!")
}

Compiler Error: constant 9.99 truncated to integer

When we use dynamic values it will just return true for every case.

So what is the appropriate way to count decimal places?

Upvotes: 3

Views: 10542

Answers (3)

Wisdom Arerosuoghene
Wisdom Arerosuoghene

Reputation: 164

Here's a function to get the decimal portion of a float. Can use len(decimalPortion(n)) to get the number of decimal places.

func decimalPortion(n float64) string {
    decimalPlaces := fmt.Sprintf("%f", n-math.Floor(n)) // produces 0.xxxx0000
    decimalPlaces = strings.Replace(decimalPlaces, "0.", "", -1) // remove 0.
    decimalPlaces = strings.TrimRight(decimalPlaces, "0") // remove trailing 0s
    return decimalPlaces
}

Check it out in playground

Upvotes: 2

chendesheng
chendesheng

Reputation: 2129

int value % 1 is always zero!

I suggest an alternative way:

value := float32(9.99)
valuef := value*100
extra := valuef - float32(int(valuef))
if extra < 1e-5 {
    fmt.Println("has two decimal places!");
}

http://play.golang.org/p/LQQ8T6SIY2

Update

package main

import (
    "math"
)

func main() {
    value := float32(9.9990001)

    println(checkDecimalPlaces(3, value))
}

func checkDecimalPlaces(i int, value float32) bool {
    valuef := value * float32(math.Pow(10.0, float64(i)))
    println(valuef)
    extra := valuef - float32(int(valuef))

    return extra == 0
}

http://play.golang.org/p/jXRhHsCYL-

Upvotes: 1

OneOfOne
OneOfOne

Reputation: 99244

You have to trick it, add an extra variable:

step := 0.1
value := 9.99
steps := value / step
if int(steps)%1 == 0 {
    fmt.Println("has two decimal places!")
}

Or cast your steps before you convert it to int like:

int(float64(value / step))

playground

//edit

the hacky non-mathematical way is to convert it to a string and split it, example:

func NumDecPlaces(v float64) int {
    s := strconv.FormatFloat(v, 'f', -1, 64)
    i := strings.IndexByte(s, '.')
    if i > -1 {
        return len(s) - i - 1
    }
    return 0
}

playground

//updated with a minor optimization

Upvotes: 9

Related Questions