A recursive function that can check if a number num is power a anohter number base.
bool isPowerof(long long num, long long base)
{
if (num <= 0)
return false;
if (num % base == 0)
return isPowerof(num / base, base);
if (num == 1)
return true;
return false;
}
- Limitation : num<= $$$2^{62}$$$ and 2<=base<= $$$2^{62}$$$
- Time complexity : O($$$log_{base}^{num}$$$).
- Sample submission : 169977243.








Try to use long doubles and gnu g++20 11.2.0 (64 bit)
Btw, in order to check is integer $$$x$$$ power of $$$2$$$ it is better to use
(x & (x - 1)) == 0btw,
x & -x == xis shorter and easier to remember.Of course, it's hardly universal, but to me this formula is much less intuitive. Still, I think this explanation might help you wrap you head around the logic behind the two formulae, rather than remember them.
The only thing you need to understand to understand
(x & (x - 1)) == 0is whatx - 1does: it takes the binary form ofx, replaces its last one with zero and every zero after it with ones (i.e....10000 -> ...01111). Soxandx - 1agree on everything before the last one and disagree on everything after and including it. Thereforex & (x - 1)retains bits before the last one and drops everything after, effectively just resetting the lowest bit set.So
(x & (x - 1)) == 0asks: if I remove the last one bit, will I get nothing left? And it's trivial to see how this is equivalent to checking for a power of two (except whenx == 0, of course, but that's intuitive too: if you've got nothing to remove, you still get nought).x & (-x)takes this one step further than necessary: you need to understand that-xis in fact~(x - 1), which, as we have seen just before, agrees withxon everything after and including the last one and disagrees on everything before the last one, so in factx & -xretains only the last bit set. So(x & -x) == xasks: if I only retain the last one bit (and drop every other bit), will I get no changes? I hope it's now easy to see how this is exactly dual to the other formula.__builtin_popcount(x)==1It generates slightly different code, and seems to be slightly faster for
int(on Codeforces). Forlong long, I could not possible to identify advantages (on Codeforces).On the other hand, it depends on the CPU. So, for example, on my local laptop, methods for
intwork the same by speed, but forlong longpopcount loses.Code (ofc with pragmas): https://godbolt.org/z/98753T416
loggives you an approximate value, because floating-point values are imprecise by their nature. And even ifloggives the best approximation possible, you divide an approximation by another approximation, resulting in a worse approximation. All of this means thatlog_nummay be not an integer but a value very near to it even if logically it should be integral.In problems like this one, what you need to do is not check that
log_numis an integer, which you're doing now, but that it's "near enough" to an integer. If you knew that "near enough" means "at most 0.00001 far from an integer", you could useabs(log_num - round(log_num)) < 0.00001for that.But in this case, you don't: if
numis very big, you can't be certain what the epsilon should be. That's the problem with logarithms: a big change in the argument can yield an incomparably small change in the result, so we have to find another way, and it's like this: takelog_num, round it to an integer and check that base to the power of the roundedlog_numis indeed equal tonum:pow(base, round(log_num)) == num.Except that this won't work right either!
powis, just like every other floating-point function, only approximate: even if both of its arguments are integers, whatpow(a, b)really does is best expressed byexp(log(a) * b), so the result might not be an integer but only a very near number. So you need to round it before comparing tonum:round(pow(base, round(log_num))) == num.And even that's not enough.
long longis usually 64-bit.doubleis usually 64-bit too, butdoublepays for its increased precision with decreased precision for big numbers, so it can only store integers up to $$$2^{53}$$$ -- after that, it starts approximating them, e.g. $$$2^{53} + 1$$$ is equal to $$$2^{53}$$$. If you want your code to work with alllong longnumbers, you need to uselong double, which is usually a 80-bit number (but not on MSVC, unfortunately), which allows it to express all integers thatlong longcan.Thanks,mate.You were right about the approximation.
By adding this line,
if (fabs(log_num - round(log_num)) < 0.000001)I was able to check if the numbers were same or not and also in constant time. Here is the submission 169961565. Also, it can calculate accurately up numbers <=2^63.Here is the modified function :
Now you just didn't listen to like half of what I said and incorrectly believe you've got working code which only passes due to sheer luck and bad tests (try $$$2^{46} + 1$$$ with base $$$2$$$, for instance -- it fails). Good job.
Droped the idea of solving it using log. Solved it using recursion and also the time complexity isn't that much for 1475A - Odd Divisor. If you have time can you check this solution mate ?
Looks fine to me. I wouldn't use recursion though: it's slow and sometimes difficult to get right. A simple loop suffices:
And it's (arguably) easier to see how this works: it literally checks that
numis one multiplied bybaseany number of times.