tags:

views:

1266

answers:

11

I saw this question,and pop up this idea.

+9  A: 

Recursively divide by 3, check that the remainder is zero and re-apply to the quotient.

Note that 1 is a valid answer as 3 to the zero power is 1 is an edge case to beware.

JB King
+1 for the correct approach, but recursion (in its true sense) is completely unnecessary. This can be done iteratively.
Carl Smotricz
+1 @Carl Smotzicz: The algorithm is inherently recursive, iteration just a workaround with no objective advantage (see tail-recursion elimination)
Dario
Or, iterate the other way:-- is the number 1 (ie 3^0) ? if so, success if not continue:-- is the number 1*3, ...-- is the number 1*3*3 ...This avoids division and keeps your firmly in the realm of integers.OR, if you are using a system with, say, 64-bit integers, build a table of the powers of 3 and check against each entry in the array, it's only 40 elements.
High Performance Mark
+2  A: 

If you are running Python, you can try using this (broken because of rounding error) code.

from math import log

def power_of(number, base):
    return log(number) / log(base) % 1 == 0

The test shown below that it is only reliable on the lower values of 3 ** X. Rounding can help, but starblue's answer is certainly superior to any other way of solving your question.

>>> from math import log
>>> def power_of(number, base):
    return log(number) / log(base) % 1 == 0

>>> for power in range(21):
    number = 3 ** power
    answer = '{} is{}a power of {}.'
    values = number, ' ' if power_of(number, 3) else ' not ', 3
    print(answer.format(*values))
    number += 1
    values = number, ' ' if power_of(number, 3) else ' not ', 3
    print(answer.format(*values))


1 is a power of 3.
2 is not a power of 3.
3 is a power of 3.
4 is not a power of 3.
9 is a power of 3.
10 is not a power of 3.
27 is a power of 3.
28 is not a power of 3.
81 is a power of 3.
82 is not a power of 3.
243 is not a power of 3.
244 is not a power of 3.
729 is a power of 3.
730 is not a power of 3.
2187 is a power of 3.
2188 is not a power of 3.
6561 is a power of 3.
6562 is not a power of 3.
19683 is a power of 3.
19684 is not a power of 3.
59049 is not a power of 3.
59050 is not a power of 3.
177147 is a power of 3.
177148 is not a power of 3.
531441 is a power of 3.
531442 is not a power of 3.
1594323 is not a power of 3.
1594324 is not a power of 3.
4782969 is a power of 3.
4782970 is not a power of 3.
14348907 is not a power of 3.
14348908 is not a power of 3.
43046721 is a power of 3.
43046722 is not a power of 3.
129140163 is not a power of 3.
129140164 is not a power of 3.
387420489 is a power of 3.
387420490 is not a power of 3.
1162261467 is a power of 3.
1162261468 is not a power of 3.
3486784401 is not a power of 3.
3486784402 is not a power of 3.
>>>
Noctis Skytower
Shouldn't there be a check that the number is a positive value, though?
JB King
You can also use: Math.Log(x, 3) == Math.Round(Math.Log(x, 3))
Elisha
Surely he was asking for a bit hack?
int3
Unless I'm very mistaken, this is a horribly stupid implementation. It's unlikely that Math.Log will evaluate to a number that's all 0's in the trailing decimals; in other words, it's very ignorant of floating-point rounding errors.
Carl Smotricz
just FYI >>> [((math.log(3**i) / math.log(3)) % 1 == 0) for i in range(20)][True, True, True, True, True, False, True, True, True, True, False, True, True, False, True, False, True, False, True, True]
S.Mark
So the algorithm fails for 3^6, 3^11 and others. Thank you, S.Mark . I don't have a Python handy so I wasn't able to deliver this proof myself.
Carl Smotricz
Noctis, I apologize for sounding harsh, but I consider an algorithm unacceptable if it doesn't produce a correct result for all values of its defined input range.
Carl Smotricz
btw, if I rounded to around 5, its become more reasonable results, its surely rounding issues. >>> [(round((math.log(3**i)) / math.log(3),5) % 1 == 0) for i in range(20)][True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True]
S.Mark
You know, "replace NUMBER with your number" etc. is nowadays usually expressed through functions with parameters.
Svante
+35  A: 
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).

starblue
I will comment here, since it is currently (and I hope remains) the top-voted answer. For all the folks who want to avoid division by multiplying: The reason this answer will typically beat yours is that for most input, it won't have to divide very many times. Two thirds of random input will be eliminated after a single mod and compare. Multiplication-based answers have to keep multiplying until the accumulator meets or exceeds n, for ANY input.
John Y
+1, but remember to check if n==0 before the loop.
Bruno Rothgiesser
You cannot get much simpler or clearer than this algorithm. In pure mathematics, we would use logarithms. On computers, we would use starblue's example code instead.
Noctis Skytower
@Noctis: There are real-world applications that require both big integers and speed.
J.F. Sebastian
JohnY, avoiding multiplication by dividing twice as often (and the fact that it doesn't handle zero) does not make for a good answer.
Marcelo Cantos
@Marcelo: On random input, it will not be dividing twice as often. In fact, for two-thirds of random input, it will not even be dividing twice.
John Y
@Marcelo Cantos With the check for zero I think this is still the best solution for most practical cases. Most of the time it is fast enough, and the two divisions need not happen if the compiler replaces them with a single machine instruction that does both. Note that all the log "solutions" also neglect to check for zero and negative numbers, apart from their problem with floating point imprecision.
starblue
I read this and the other answers with interest, but the **fastest solution of all was not here.** I have posted another answer that is faster than this one and also faster than the if-tree idea because it avoids pipeline stalls (check it out...). I must say, however, that **I really like the simplicity of this answer** and would probably choose it over my own answer if I were writing anything but a library for which speed was the most important criterion.
Ray Burns
+29  A: 

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...

AakashM
for 64-bit integers you shouldn't get more than 64 cases.
Alexandru
You could expand out the constants: e.g. n = 3 * 3 or n = 3 ** 2. That way you could visually check for correctness. Typically your compiler will fold the constants for you, so there would be no loss of efficiency (that may not be the case in all languages/implementations).
dangph
You could use binary search to speed it up.
starblue
+1. With binary search, I'm sure this is the most efficient solution
nikie
an elegant solution!
Axarydax
+3  A: 

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.

Alexandru
I'd agree if there was going to be a large number of powers of 3, but with only 40 less than 2^64, I think a linear search might outperform the binary search. And, no, I'm not inclined to test this !
High Performance Mark
+1 for the pre-computation idea. Very useful if the operation has to happen multiple times.
Programming Hero
Might even be possible to create an efficient hash.
MSalters
+12  A: 

if (log n) / (log 3) is integral then n is a power of 3.

Visage
+1 for using math. :)
ojrac
True in mathematical sense, not practical because of rounding errors. I checked that (log 3^40)/log(3^40-1)=1.0 on my machine.
Rafał Dowgird
Imho, this is too inefficent and imprecise, though mathematically correct.
Dario
+2  A: 

You can do better than repeated division, which takes O(lg(X) * |division|) time. Essentially you do a binary search on powers of 3. Really we will be doing a binary search on N, where 3^N = input value). Setting the Pth binary digit of N corresponds to multiplying by 3^(2^P), and values of the form 3^(2^P) can be computed by repeated squaring.

Algorithm

  • Let the input value be X.
  • Generate a list L of repeated squared values which ends once you pass X.
  • Let your candidate value be T, initialized to 1.
  • For each E in reversed L, if T*E <= X then let T *= E.
  • Return T == X.

Complexity:

O(lg(lg(X)) * |multiplication|) - Generating and iterating over L takes lg(lg(X)) iterations, and multiplication is the most expensive operation in an iteration.

Strilanc
I am not sure this is better than repeated division in practice because a division-based solution short-circuits very quickly in the typical case. You can stop dividing once you get a remainder, which is after the very first pass on two-thirds of random input. 8/9 of random input requires no more than 2 passes; etc. Unless division is VASTLY slower than multiplication (which it typically isn't these days), the division method usually produces an answer before you have even finished generating L.
John Y
True, but still not as good in the worst case.
Strilanc
+1  A: 

Set based solution...

DECLARE @LastExponent smallint, @SearchCase decimal(38,0)

SELECT
    @LastExponent = 79, -- 38 for bigint
    @SearchCase = 729

;WITH CTE AS
(
    SELECT
        POWER(CAST(3 AS decimal(38,0)), ROW_NUMBER() OVER (ORDER BY c1.object_id)) AS Result,
        ROW_NUMBER() OVER (ORDER BY c1.object_id) AS Exponent
    FROM
        sys.columns c1, sys.columns c2
)
SELECT
    Result, Exponent
FROM
    CTE
WHERE
    Exponent <= @LastExponent
    AND
    Result = @SearchCase

With SET STATISTICS TIME ON it record the lowest possible, 1 millisecond.

gbn
Is needed the second table 'sys.columns c2'? Did you chosen to use sys.columns for speed reasons?
Nitai Bezerra
I used the cross join to make sure I get enough rows, and sys.columns because I know it has at least 40-50 rows. And it was the first one I thought of :-)
gbn
+3  A: 

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);
}

Nice "hybrid" approach (essentially combining division with precomputed values).
John Y
+2  A: 
ldog
What language is this? What's the time for one million (or one billion) executions of `x % 3` and the time for the same number of executions of this algorithm?
Chip Uni
% uses the euclidian algorithm which is a general algorithm to determine the remainder when dviding by an arbitriary number. % worst case (non-bitwise) time complexity is 5 times the number of digits in the base 10 representation of the smaller number, meaning no more than 15 multiplications and subtractions. This is O(n) in the complexity of the number of bits, however.
ldog
This is pseudo code, it can easily be implemented in C or C++ efficiently. Keep in mind that multiplication can not be done in O(n) time, so the euclidian algorithm will be slower than this.
ldog
I should rephrase that, we don't know of a multiplication algorithm that computes the product in O(n) time where n is the number of bits.
ldog
You're forgetting an important fact: hardware is much faster than software. As long as you have multiplication in hardware, % is going to be faster. Your algorithm could still be useful for a bignum library, though.
LaC
hmm yes, I agree that hardware is generally faster. I thought that the initial question was posed for cases where the input number is **very big** otherwise why bother? just create a look up tables up to the largest power of 3 you want to represent, the look up table will be of logarithmic size, and pretty compact.
ldog
+9  A: 

I'm surprised at this. Everyone seems to have missed the fastest algorithm of all.

The following algorithm is faster on average - and dramatically faster in some cases - than a simple while(n%3==0) n/=3; loop:

bool IsPowerOfThree(uint n)
{
  // Optimizing lines to handle the most common cases extremely quickly
  if(n%3 != 0) return n==1;
  if(n%9 != 0) return n==3;

  // General algorithm - works for any uint
  uint r;
  n = Math.DivRem(n, 59049, out r); if(n!=0 && r!=0) return false;
  n = Math.DivRem(n+r, 243, out r); if(n!=0 && r!=0) return false;
  n = Math.DivRem(n+r,  27, out r); if(n!=0 && r!=0) return false;
  n += r;
  return n==1 || n==3 || n==9;
}

The numeric constants in the code are 3^10, 3^5, and 3^3.

Performance calculations

In modern CPUs, DivRem is a often single instruction that takes a one cycle. On others it expands to a div followed by a mul and an add, which would takes more like three cycles altogether. Each step of the general algorithm looks long but it actually consists only of: DivRem, cmp, cmove, cmp, cand, cjmp, add. There is a lot of parallelism available, so on a typical two-way superscalar processor each step will likely execute in about 4 clock cycles, giving a guaranteed worst-case execution time of about 25 clock cycles.

If input values are evenly distributed over the range of UInt32, here are the probabilities associated with this algorithm:

  • Return in or before the first optimizing line: 66% of the time
  • Return in or before the second optimizing line: 89% of the time
  • Return in or before the first general algorithm step: 99.998% of the time
  • Return in or before the second general algorithm step: 99.99998% of the time
  • Return in or before the third general algorithm step: 99.999997% of the time

This algorithm outperforms the simple while(n%3==0) n/=3 loop, which has the following probabilities:

  • Return in the first iteration: 66% of the time
  • Return in the first two iterations: 89% of the time
  • Return in the first three iterations: 97% of the time
  • Return in the first four iterations: 98.8% of the time
  • Return in the first five iterations: 99.6% of the time ... and so on to ...
  • Return in the first twelve iterations: 99.9998% of the time ... and beyond ...

What is perhaps even more important, this algorithm handles midsize and large powers of three (and multiples thereof) much more efficiently: In the worst case the simple algorithm will consume over 100 CPU cycles because it will loop 20 times (41 times for 64 bits). The algorithm I present here will never take more than about 25 cycles.

Extending to 64 bits

Extending the above algorithm to 64 bits is trivial - just add one more step. Here is a 64 bit version of the above algorithm optimized for processors without efficient 64 bit division:

bool IsPowerOfThree(ulong nL)
{
  // General algorithm only
  ulong rL;
  nL = Math.DivRem(nL, 3486784401, out rL); if(nL!=0 && rL!=0) return false;
  nL = Math.DivRem(nL+rL,   59049, out rL); if(nL!=0 && rL!=0) return false;
  uint n = (uint)nL + (uint)rL;
  n = Math.DivRem(n,   243, out r); if(n!=0 && r!=0) return false;
  n = Math.DivRem(n+r,  27, out r); if(n!=0 && r!=0) return false;
  n += r;
  return n==1 || n==3 || n==9;

}

The new constant is 3^20. The optimization lines are omitted from the top of the method because under our assumption that 64 bit division is slow, they would actually be slow things down.

Why this technique works

Say I want to know if "100000000000000000" is a power of 10. I might follow these steps:

  1. I divide by 10^10 and get a quotient of 10000000 and a remainder of 0. These add to 10000000.
  2. I divide by 10^5 and get a quotient of 100 and a remainder of 0. These add to 100.
  3. I divide by 10^3 and get a quotient of 0 and a remainderof 100. These add to 100.
  4. I divide by 10^2 and get a quotient of 1 and a remainder of 0. These add to 1.

Because I started with a power of 10, every time I divided by a power of 10 I ended up with either a zero quotient or a zero remainder. Had I started out with anything except a power of 10 I would have sooner or later ended up with a nonzero quotient or remainder.

In this example I selected exponents of 10, 5, and 3 to match the code provided previously, and added 2 just for the heck of it. Other exponents would also work: There is a simple algorithm for selecting the ideal exponents given your maximum input value and the maximum power of 10 allowed in the output, but this margin does not have enough room to contain it.

NOTE: You may have been thinking in base ten throughout this explanation, but the entire explanation above can be read and understood identically if you're thinking in in base three, except the exponents would have been expressed differently (instead of "10", "5", "3" and "2" I would have to say "101", "12", "10" and "2").

Ray Burns
Pardon my ignorance, but on the cycle counts, don't div and mul usually take more than one cycle?
Michael Myers
It depends on the CPU. On CPUs where div takes multiple cycles the numbers will be different but this algorithm is still the most efficient available.
Ray Burns