How to optimize the following (convert arithmetic to bit-wise operations)?
Optimize:
int A = B * 4
int A = B * 72
int A = B % 1
int A = B % 16
int A = (B + C) / 2
int A = (B * 3) / 8
int A = (B % 8) * 4
Saw these questions in interview.
How to optimize the following (convert arithmetic to bit-wise operations)?
Optimize:
int A = B * 4
int A = B * 72
int A = B % 1
int A = B % 16
int A = (B + C) / 2
int A = (B * 3) / 8
int A = (B % 8) * 4
Saw these questions in interview.
The interviewer is probably looking for your ability to convert arithmetic to bitwise operations under the misguided notion that this will be faster. The compiler will perform optimizations, so there's nothing you need to optimize. If you don't have an optimizing compiler, then the right thing to do is to profile your code to see where the performance bottlenecks are and fix them. It is unlikely that arithmetic will be your performance bottleneck.
That said, this is probably what the interviewer is looking for:
B * 4
, multiplication by powers of two can be performed using bit-shift operations, such as B << 2
. This achieves the same result.B * 72
, this is actually B * 8 * 9
, which is B * 2^3 * (2^3 + 1) = (B*2^6) + (B*2^3)
. Again, the solution is to find powers of two and write them using bit-shift operations. (B << 6) + (B << 3)
is the same as B * 72
B % 16
, is always a number in the range 0-15 (if B is positive) this is asking for the last 4 bits of an integer, and can be found using a bit mask: B & 0xF
.Note that in each case the meaning of the code is harder to follow. B * 72
is easier to read than (B << 6) + (B << 3)
. This process of trying to nitpick code performance without actually profiling anything is called premature optimization. If you profile your code and find its performance bottleneck really is these math operations, then you can rewrite them in optimized forms, but you have to document what the code means so that the next person who looks at it understands why the code is so messy.
I would note that, if I were the interviewer asking this question (and I wouldn't ask this question), I would prefer the answer "let the compiler do the optimizations" to just blindly finding bitwise ways of expressing the arithmetic.
All of these calculations can be done by bit-shifts; however, this would only work on positive numbers. We need to have a special case for negative inputs, since the interviewer didn't specify which!
Multiplication by 4 = 22 can be done by left-shifting by 2 bits.
int A = (B < 0) ? -((-B) << 2)) : B << 2;
The negative number will overflow and give the wrong result if we directly do a shift on it, so we operate on minus-it.
72 = 64 + 8 = 26 + 23. Thus:
int A = (B < 0) ? -(((-B) << 6) + ((-B) << 3)) : (B << 6) + (B << 3)
The modulus for negative numbers in the C++ standard is equivalent to:
neg_number % N = -((-neg_number) % N);
(Test it for yourself)
But this has no effect on modulus by 1! Thus int A = 0;
Using an AND (&
) as Welbog said:
int A = (B < 0) ? -((-B) & 0xF) : B & 0xF;
Do the same as previously said, but on the sum; using a right shift by 1:
int A = (B + C < 0) ? -((-(B+C)) >> 1) : (B + C) >> 1;
int A = (B < 0) ? -(((-B) << 1 - B) >> 3) : (B << 1 + B) >> 3;
int A = (B < 0) ? -(((-B) & 7) << 2) : (B & 7) << 2;