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

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

I saw this question, and pop up this idea.

23条回答
  •  不知归路
    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
    

提交回复
热议问题