34

I originally tried this, however the % operator isn't defined for float64.

func main(){
    var a float64
    a = 1.23
    if a%1 == 0{
        fmt.Println("yay")
    }else{
        fmt.Println("you fail")
    }
}
John Calder
  • 619
  • 3
  • 9
  • 13

6 Answers6

39

Assuming that your numbers will fit into an int64, you can compare the float value with a converted integer value to see if they're the same:

if a == float64(int64(a)) { ... }

Alternatively, if you need the entire float64 domain, you can use the math.Trunc function, with something like:

if a == math.Trunc(a) { ... }

For example, the following code correctly outputs yay, on testing over at the Go playground:

package main

import (
    "fmt"
    "math"
)

func main() {
    var a float64 = 2.00
    if a == math.Trunc(a) {
        fmt.Println("yay")
    } else {
        fmt.Println("you fail")
    }
}
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • That doesn't seem like a well-typed Go expression. Go insists that both operands to `==` be of the exact same type. – Gian May 14 '13 at 04:05
  • 1
    In fact, having tried it, it is rejected as not-well-typed for the aforementioned reasons. One would need to cast back to float first. – Gian May 14 '13 at 04:07
  • As with Deepu's answer this fails when the integer part of the expression is over 2^63. @TimStClair and @Gian have the idea (keep it a float, but use `math` to separate the int and fractional part). – twotwotwo Feb 02 '16 at 21:48
  • @twotwotwo, yes, it will. That's why I have the bit about it being suitable for numbers within the range of an int64, and why I provided a link to the truncate function for situations where you want to use the full range. I'm not sure if you just missed that final paragraph or not so, if you have an issue that's not already covered in the anwser or if I've misunderstood (entirely possible), please let me know and I'll try to fix it up. – paxdiablo Feb 02 '16 at 22:58
  • D'oh, sorry, I did miss that last sentence. Casting still isn't what I'd suggest even spelling out the issue with it, but yes, my comment was redundant. – twotwotwo Feb 02 '16 at 23:14
  • No probs, @twotwotwo, just wanted to make sure I hadn't missed something. Cheers. – paxdiablo Feb 02 '16 at 23:17
  • The second example is wrong. If a is equal to 2.00, the code fails. – ZottoSL Feb 09 '23 at 15:54
  • @ZottoSL: I just checked that, and I've added the code I used to the answer. It *does* actually seem to work correctly for `2.00`. I'm not sure what method you're using to test but, if you let me know, I can try nut it out. – paxdiablo Feb 09 '23 at 21:10
5

You can use the math.Modf function:

const epsilon = 1e-9 // Margin of error
if _, frac := math.Modf(math.Abs(a)); frac < epsilon || frac > 1.0 - epsilon {
    // ...
}

epsilon is necessary here since floating point math is not precise (e.g. float64(.3)+float64(.6)+float64(.1) != 1)

From the godoc:

func Modf(f float64) (int float64, frac float64)

Modf returns integer and fractional floating-point numbers that sum to f. Both values have the same sign as f.

Tim Allclair
  • 7,347
  • 2
  • 27
  • 25
  • 1
    Because [floating point results usually aren't exact](https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems) I would use `Modf` but check if the number is _close_ to an integer, [like this](http://play.golang.org/p/uUZCt0brgl). Otherwise `float64(.3)+float64(.6)+float64(.1)` will be treated as a noninteger. – twotwotwo Feb 02 '16 at 21:46
  • (Note that the types in that sample "bad" float value are necessary to see the problem because Go [goes to extra trouble to make math on untyped constants more precise](https://blog.golang.org/constants).) – twotwotwo Feb 02 '16 at 21:54
0

How about math.Trunc? It truncates a float64 to its whole-number component.

For example, something like:

if a.Trunc() == a {
    // ...
}

Beware of the usual considerations about floating-point representation limitations. You might wish to check whether a.Trunc() is within some small range of a, to account for values like 1.00000000000000002.

Gian
  • 13,735
  • 44
  • 51
0

I solved it like so:

isWhole := int(value * 100) == int(value) * 100

Adjust the number of digits in the factor, e.g. multiply by 10000 to check 4 digits.

isapir
  • 21,295
  • 13
  • 115
  • 116
0

Just ceil or float your number and compare the result to origin value. The best solution for me:

var a float64 = 2.11
var b float64 = 3.00

fmt.Println(math.Ceil(a) == a) // 3.00 == 2.11; false; a is not a whole number
fmt.Println(math.Ceil(b) == b) // 3.00 == 3.00; true; b is a whole number

You can use a function:

func isWhole(x float64) bool {
  return math.Ceil(x) == x
}
Morani
  • 446
  • 5
  • 15
-1

I think the following code might be useful,

func main(){
    var (
          a float64
          b float64
          c float64
    ) 
    a = 1.23
    b = float64(int64(a))
    c = a - b
    if c > 0 {
        fmt.Println("Not a Whole Number")
    } else {
        fmt.Println("Whole Number")
    }
}
Deepu
  • 7,592
  • 4
  • 25
  • 47
  • There seems to be a danger of overflowing `b` here? – Gian May 14 '13 at 04:08
  • 1
    The problem is that `a` is a `float64` that is being coerced to an `int`, at which point it may overflow the (32-bit) `int` type and result in a wacky loss of precision (or indeed, a false negative). – Gian May 14 '13 at 04:21
  • Still overflows for, e.g. 1e30, just now the overflow is in the temporary value used in the calculation of `b`. Gian's and Tim St. Clair's answers seem like the approach (and Tim's compiles and shows how to handle rounding error, so it's my pick). – twotwotwo Feb 02 '16 at 22:58