How to check if an integer is a power of 3?

前端 未结 23 1093
没有蜡笔的小新
没有蜡笔的小新 2020-12-02 08:15

I saw this question, and pop up this idea.

相关标签:
23条回答
  • #include<iostream>
    #include<string>
    #include<cmath>
    using namespace std;
    int main()
    {
         int n, power=0;
          cout<<"enter a number"<<endl;
          cin>>n;
      if (n>0){
    
         for(int i=0; i<=n; i++)
         {
    
             int r=n%3;
    
                n=n/3;
             if (r==0){
                power++;
             }
    
             else{
                   cout<<"not exactly power of 3";
                    return 0;
    
                 }
         }
    
       }
    
             cout<<"the power is "<<power<<endl;
      }
    
    0 讨论(0)
  • 2020-12-02 08:25
    while (n % 3 == 0) {
        n /= 3;
    }
    return n == 1;
    

    Note that 1 is the zeroth power of three.

    Edit: You also need to check for zero before the loop, as the loop will not terminate for n = 0 (thanks to Bruno Rothgiesser).

    0 讨论(0)
  • 2020-12-02 08:25

    Very interesting question, I like the answer from starblue, and this is a variation of his algorithm which will converge little bit faster to the solution:

    private bool IsPow3(int n)
    {
        if (n == 0) return false;
        while (n % 9 == 0)
        {
            n /= 9;
        }
        return (n == 1 || n == 3);
    }
    
    0 讨论(0)
  • 2020-12-02 08:25

    The fastest solution is either testing if n > 0 && 3**19 % n == 0 as given in another answer or perfect hashing (below). First I'm giving two multiplication-based solutions.

    Multiplication

    I wonder why everybody missed that multiplication is much faster than division:

    for (int i=0, pow=1; i<=19, pow*=3; ++i) {
        if (pow >= n) {
            return pow == n;
        }
    }
    return false;
    

    Just try all powers, stop when it grew too big. Avoid overflow as 3**19 = 0x4546B3DB is the biggest power fitting in signed 32-bit int.

    Multiplication with binary search

    Binary search could look like

    int pow = 1;
    int next = pow * 6561; // 3**8
    if (n >= next) pow = next;
    next = pow * 81; // 3**4
    if (n >= next) pow = next;
    next = pow * 81; // 3**4; REPEATED
    if (n >= next) pow = next;
    next = pow * 9; // 3**2
    if (n >= next) pow = next;
    next = pow * 3; // 3**1
    if (n >= next) pow = next;
    return pow == next;
    

    One step is repeated, so that the maximum exponent 19 = 8+4+4+2+1 can exactly be reached.

    Perfect hashing

    There are 20 powers of three fitting into a signed 32-bit int, so we take a table of 32 elements. With some experimentation, I found the perfect hash function

    def hash(x):
        return (x ^ (x>>1) ^ (x>>2)) & 31;
    

    mapping each power to a distinct index between 0 and 31. The remaining stuff is trivial:

    // Create a table and fill it with some power of three.
    table = [1 for i in range(32)]
    // Fill the buckets.
    for n in range(20): table[hash(3**n)] = 3**n;
    

    Now we have

    table = [
         1162261467, 1, 3, 729, 14348907, 1, 1, 1,
         1, 1, 19683, 1, 2187, 81, 1594323, 9,
         27, 43046721, 129140163, 1, 1, 531441, 243, 59049,
         177147, 6561, 1, 4782969, 1, 1, 1, 387420489]
    

    and can test very fast via

    def isPowerOfThree(x):
        return table[hash(x)] == x
    
    0 讨论(0)
  • 2020-12-02 08:27

    How large is your input? With O(log(N)) memory you can do faster, O(log(log(N)). Precompute the powers of 3 and then do a binary search on the precomputed values.

    0 讨论(0)
  • 2020-12-02 08:32

    I find myself slightly thinking that if by 'integer' you mean 'signed 32-bit integer', then (pseudocode)

    return (n == 1) 
        or (n == 3)
        or (n == 9)
        ... 
        or (n == 1162261467) 
    

    has a certain beautiful simplicity to it (the last number is 3^19, so there aren't an absurd number of cases). Even for an unsigned 64-bit integer there still be only 41 cases (thanks @Alexandru for pointing out my brain-slip). And of course would be impossible for arbitrary-precision arithmetic...

    0 讨论(0)
提交回复
热议问题