1

My project mission is to find out if an integer is power of three. My code can pass 0 ,1, 3,9,27,81 test cases, but 243. And when I try to print out to debug, I found a weird thing. When I input 243, I print out log3(243), it gives me 5.0, which is correct. But I tried to print log3(243) % 1, it gives me 0.99999999999, which is so weird.

class Solution {
func isPowerOfThree(n: Int) -> Bool
{
    //print("log3(n): \(log3(Double(n)))")

    if n == 0
    {
        return true
    }

    if n == 1
    {
        return true
    }

    //print("weird here: \(log3(Double(n)) % 1)" )

    if log3(Double(n)) % 1 == 0.0
    {

        return true
    }
    //print("log3: \(log3(Double(n)))")
    //print("floor log3: \(floor(log3(Double(n))))")
    //print("log3: \(Int(log3(Double(n))))")
    return false
}

func log3(val: Double) -> Double
{
    return log(val)/log(3.0)
}

}

var test = Solution()
var result = test.isPowerOfThree(243)
print(result)
Tang
  • 351
  • 1
  • 4
  • 15
  • 1
    http://stackoverflow.com/questions/4915462/how-should-i-do-floating-point-comparison – Bryan Chen May 17 '16 at 01:06
  • For detailed information about this, see [What Every Computer Scientist Should Know About Floating-Point Arithmetic](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – NobodyNada May 17 '16 at 01:11

1 Answers1

3

This is due to the precision of Double. Numbers a coded in binary format and at some point the precision you expect can't reached.

I tried your program and log3(243) give me 4.9999999... So it make sense the modulo 1 fail.

If you change Double to Float, your program will works.

if log3(Float(n)) % 1 == 0.0

func log3(val: Float) -> Float
sonique
  • 4,539
  • 2
  • 30
  • 39
  • 1
    Generally though, to check if an int is a power of 3, you shouldn't change it to a float or a double. You should just leave it as an int. – Teepeemm May 17 '16 at 00:47
  • `log()` need a `Float` or `Double`, so he has to cast `Int` anyway. but I'm agree, less you cast better it is. – sonique May 17 '16 at 01:01
  • Yes. You guys are right! I just figure out. I will share my solution. Thank you so much! – Tang May 17 '16 at 02:16
  • 1
    I would expect that casting to `Float` will cause problems at the limits of precision. Casting from `Int` involves a loss of precision, and so should be avoided. Especially if there's a non-casting version (`while(n%3==0)n/=3;return n==1;`, or just precompute the 20some powers of 3 that fit in an `Int`). If you must cast, at least use a version that's more robust against floating point arithmetic: `pow(3,round(log3(Double(n))))==n`. – Teepeemm May 17 '16 at 13:47