Divide a number by 3 without using * / + - % operators
stackoverflow.com
stackoverflow.com
I don't usually sit on the side of fence that complains about "write a function that does X" style questions in interviews, but I can't see how this is useful at all.
This just seems like one of those things that you either know off the top of your head, or you don't. If you asked me to derive the addition operation using only bit level operators, I might be able to come up with it, but it'd probably take me much longer than an interview allows. But to come up with divide is just not going to happen.
So if you don't know the answer off the top of your head, what use is this question?
For this example, 1/3, in binary, is 0.0101010101…
From there, writing out the long multiplication will give hints towards a solution. Untested, so likely erroneous:
uint n = 12356;
uint result = 0;
while( n > 0)
{
n >>= 2;
result += n; // cheating
}
If you do not want to cheat, write a function that computes x minus 1 using but twiddling, and add a loop.PS: Or because there is no need for it to be fast just start with zero keep adding 1 until 3x+3 > n.
If N = 15692343, the result should be 5230781. Using "N /= 2", you get:
0
+ 3923085.75 = 3923085.75
+ 980771.4375 = 4903857.1875
+ 245192.859375 = 5149050.046875
+ 61298.21484375 = 5210348.26171875
+ 15324.5537109375 = 5225672.81542969
+ 3831.13842773438 = 5229503.95385742
+ 957.784606933594 = 5230461.73846436
+ 239.446151733398 = 5230701.18461609
+ 59.8615379333496 = 5230761.04615402
+ 14.9653844833374 = 5230776.01153851
+ 3.74134612083435 = 5230779.75288463
+ 0.935336530208588 = 5230780.68822116
+ 0.233834132552147 = 5230780.92205529
+ 0.0584585331380367 = 5230780.98051382
+ 0.0146146332845092 = 5230780.99512846
+ 0.0036536583211273 = 5230780.99878211
+ 0.000913414580281824 = 5230780.99969553
+ 0.000228353645070456 = 5230780.99992388
...
which eventually reaches the correct answer for any desired degree of accuracy. But using "N >>= 2", you get: 0
+ 3923085 = 3923085
+ 980771 = 4903856
+ 245192 = 5149048
+ 61298 = 5210346
+ 15324 = 5225670
+ 3831 = 5229501
+ 957 = 5230458
+ 239 = 5230697
+ 59 = 5230756
+ 14 = 5230770
+ 3 = 5230773
+ 0 = 5230773
which is out by 8. def badd(A, C):
while C != 0:
t = A & C
A = A ^ C
C = (t << 1) & 0xFFFFFFFF
return A
def div3(ah):
qh = 0
ql = 0
al = 0
while ah != 0:
al = (al >> 2) & 0x0000FFFF
al = badd(al, (ah & 0x3) << 14)
ah = ah >> 2
qh = badd(qh, ah)
ql = badd(ql, al)
if ql & 0xFFFF0000:
qh = badd(qh, ql >> 16)
ql = ql & 0xFFFF
if ql > 0x8000:
qh = badd(qh, 1)
return qhSay you have 50 people, all of whom are capable of doing the job. You have to whittle that number down somehow. Might as well find a problem only 1 in 50 could answer.
As a programmer I really like this, but as somebody who hires programmers it makes things difficult!
During a technical interview, my experience is that it's best to talk to your interviewer and interact with them as you solve the problem. Usually you will get a nudge in the right direction, and you'll find the problem is not nearly as daunting as your initial impression.
Even if you don't end up getting the question right, the interviewer can get a positive impression based on your problem-solving approach and how well you communicate your thought process.
This really isn't as difficult of a question as you think, especially in an interactive environment (interview) as opposed to noninteractive (pencil and paper test). I would not be surprised to see this question on a test for sophomores or even 2nd semester freshmen in ECE here at UIUC. Not that everyone would get it right... But that's the point of tests and interviews anyway.
Finally, keep in mind that based on this question, the position the interview was for probably required some decent low-level understanding. If you find it daunting, it's probably not a position you would have interviewed for anyway, so you wouldn't have to worry about it. (Basing this on the statement that deriving addition with bit-logic would only be a "maybe" for you. This knowledge would be a given for most Computer Engineers or Electrical Engineers. I hope neither of those was your discipline of choice. No offense!)
The question is, would graduated programmers work with bitwise operations? Or, even worse, programmers who haven't been to school, but still do good work?
The people that are questioning the validity of this question are not in the target audience. This definitely falls more towards the Electrical and Computer Engineering end of the spectrum than CS.
The point of such questions is to test the person's problem-solving skills. What's being observed is how they go about trying to crack open the problem. As well as how they react to being thrown a curveball - do they roll up their sleeves and get to work, or do they stammer and freeze up under the pressure?
Secondarily, their working knowledge is also being tested, since if they pass the first two parts of the test then they should end up demonstrating some of that knowledge as they start working their way into the problem.
But I'm not interested in sitting around waiting for a correct solution. Just waiting long enough to get an answer to the questions I had. None of which are the same as the question I asked.
As if you're qualified to tell one way or another.
I hope you appreciate the irony of you sarcasm.
Which, BTW, correlates more with whether they had seen that particular problem or not before (i.e. had subjected themselves to the tedious and soul-crushing task of prepping for interviews like this) than with any "intrinsic" problem-solving ability.
And yeah, I am starting to think that problem-solving ability is at least somewhat intrinsic, to the extent that it has more to do with a person's temperament than anything else. It's certainly not the kind of thing I've ever seen much success in training someone to do. It seems to be the difference between initially reacting with, "Hmm, that's funny, I wonder why that happened," and "Ughh no no how do I make it stop!?"
If it were workable, I think a stellar interview question might be, "Do you find jigsaw puzzles more enjoyable with or without a picture?"
So, in a sense, you're right. It's a good question because their is no correct answer. An interviewer who's asking many questions that have correct answers is an interviewer who didn't exercise due diligence during the pre-interview process.
1. Implement addition at the bit level. Here's an example for 16-bit numbers:
def badd(A, C):
while C != 0:
t = A & C
A = A ^ C
C = (t << 1) & 0xFFFF
return A
That's actually all I need, because I could no do something like make two counters in a loop, both starting at 0. The first counter goes up by 1 each iteration, the second by 3. Stop when the second counter exceeds the target number, and return the first counter.2. The solution in #1 can be greatly speed up, while keeping the same basic idea. Hard code in a table that contains decreasing powers of two in the first column, and the second column is 3 times the first column.
Now the loop starts at 0, and has two counters, but also has an index into the table. The first counter goes up by the first column at the current table index, the second counter by the second column. When a step would take the second counter past the target number instead of terminating, increment the index into the table.
3. Do division similar to how we would do it by hand. Here is an example for 16-bit numbers:
def div3(A):
m = 0x8000
r = 0
d = 0
while m != 0:
r <<= 1
if A & m:
r |= 1
if r == 0:
q, r = 0, 0
elif r == 1:
q, r = 0, 1
elif r == 2:
q, r = 0, 2
elif r == 3:
q, r = 1, 0
elif r == 4:
q, r = 1, 1
elif r == 5:
q, r = 1, 2
d = (d<<1) | q
m >>= 1
return d
4. Similar to the above, but first replace the if/elif chain with something based on table lookup, and work on more than one bit at a time.5. Dividing by 3 is the same as multiplying by 1/3. Multiplication can be done by shifting and adding, and I've got adding from #1.
6. Oracle can afford big machines. Just do the whole thing with a big table lookup.
"Look at bit-shift operators, and how they work on unsigned integers. Then think & and ^ and how they relate to addition (adders, after all, have to be implemented in terms of elementary operations like those). It's all pretty straightforward from there. Go the whiteboard and walk you through it? Huh? Look, it's an interesting problem, but I've got some regression tests to get straightened out by the end of the day that are like, totally messed up. They were written by some guy we hired on the basis of his ability to solve puzzle problems, but just ended up totally slacking and never tying the ends off of anything he did."
Really now, why should one's response in an interview be any different?
That kind of response would save me a tremendous amount of time and enormous headaches dealing with a bad hire. I would thank you for your honesty, ask you a couple of perfunctory questions so it didn't seem too awkward and then let you go on your way in life to be someone else's problem.
Working on real projects that people actually want to pay for means working somewhat on the edge. Things go wrong. There are crunch time when solutions have to be delivered. The last thing I want at those times is to have to depend upon some mommie's special little snowflake who was too self-important to gamely work through some puzzle exercises during an interview for a job he claimed he wanted. That little snowflake will melt every time and leave me and the rest of his team to fend for itself. No thanks.
Aww.
Edit: I should add, the problem never said I didn't have infinite memory or computational resources.
for i... {
append i
append i + 0.333
append i + 0.666
}Or a slide rule, though that's possibly cheating (technically you'd be dividing....)
http://stackoverflow.com/questions/11694546/divide-a-number-...
u32 add(u32 x, u32 y)
{
u32 z = 0;
for (u32 c = 0, m = 1; m; m <<= 1)
z |= (x ^ y ^ c) & m, c = ((x & y) | (x & c) | (y & c)) << 1;
return z;
}
u32 neg(u32 x) { return add(~x, 1); }
u32 sub(u32 x, u32 y) { return add(x, neg(y)); }
u32 lt(u32 x, u32 y) { return sub(x, y) >> 31; }
u32 div3(u32 x)
{
u32 q = 0;
assert(lt(-1, x)); // x >= 0 iff -1 < x
while (!lt(x, 3)) x = sub(x, 3), q = add(q, 1);
return q;
} n = 12345 # your input
s = ''.zfill(n) # fill as many zeroes
while len(s)>3: s=s[3:] # trim 3 zeroes each time
print 'divisible by 3' if len(s)==3 else 'nop'n_divideby_3 = lambda n: len(''.zfill(n)[2::3])
1 dollar.
I get that a company wants to hire smart people who can problem solve and think outside the box, but it doesn't really represent reality. I think if you had someone who wrote code like that you would have a maintenance nightmare since most people don't write code like that.
Of course not all situations are like mine. I write a few layers of abstraction away from the hardware, and live mostly in the managed code world. A low level/embedded systems developer may need to know these things.
Why would it be a maintenance nightmare?! It is arithmetic with one input and one output! If an organization cannot validate that, they have no chance of making good software.
1/3 = 0.010101... base 2.
x = let x0,x1,...,xN-2,xN-1 (MSB is x0 and LSB is xN-1)
Now y = x/3 = x * 1/3, where y=(y0,y1,...), so a long multiplication will look something like (being sloppy about exact bit positions):
x0,x1,...,xN-2,xN-1
* 0.010101...
-------------------------
x0,x1,x2,x3,x4,x5...,xN-2,xN-1
x0,x1,x2,x3,x4,x5...,xN-2,xN-1
x0,x1,x2,x3,x4,x5...,xN-2,xN-1
Let's shorten it by grouping the bits in pairs, so BN=(b2N,b2N+1). X0,X1,X2,X3
X0,X1,X2,X3
X0,X1,X2,X3
Y0,Y1,Y2,Y3,Y4,Y5
or:
Y0 =X0 or X0 +1 Y1=X1+X0+carry =X1+Y0 or X1+Y0+1 (extra bits of carry are in Y0)
Y2=X2+X1+X0+carry=X2+Y1 or X1+Y1+1 (extra bits of carry are in Y1)
The key is that in the above, there is only ever a single bit being carried between bit pairs, as the "01" pattern in 1/3 base 2 limits how carries propagate.Here's a partial solution, which only works fro a few trivial cases (eg 2^N) since I haven't accounted for the possability of a single bit carry. For a full solution, maybe a conditional is required and an additonal logic operation or two to perform an increment on a pair of bits?
div3(int x) { int y=0; while(x) y ^= (x>>=2) return(y) }
Can anyone complete it?
Edit: formatting. Beats me how to do fixed width properly. Edit: Oops. In the time it took me to write this qntm got there first!
OK my solution is connect to a postgres sql DB server and something very much like "SELECT WIDTH_BUCKET(389, 999, 0, 333);" and the result will be something like 129. width_bucket asks for a sample, the highest bucket, the lowest bucket, how many buckets, and tells you which bucket to dump the sample into. You know, for histograms and stuff like that. So you make the largest bucket max_int or 999 in this easy scenario, and the number of buckets precisely 1/3 the number of buckets or 333 in this easy case, and postgres database will figure out the number of the bucket to stick your sample into, which coincidentally happens to numerically match 1/3 the sample.
Its possible Oracle has a function similar to width_bucket from postgres, but I have no idea because a Oracle license costs about 10 times the value of my house so I can't afford it, probably because they pay people to reimplement /.
Another fun way to attack this problem would be to go all trig on them and try to convince them its impossible to divide by 3 because you can't trisect an angle using classical greek construction techniques. Then you hit them with galois theory as relates to solving cubic equations, until their brains bleed and/or you get the job and/or removed by security. This stuff is all 200 years old, or so, but you'll still find cranks who think they can trisect angles using classical greek construction techniques. Maybe being smart enough to understand that overqualifies the applicant from working at a place that things reimplementing / is a wise use of brain power.
Nearly spat out my coffee.
No bit twiddling. Small RAM footprint. Obviously correct. (This is really just an unoptimized version of the "clever" solution.)
For Oracle though -- create a database of numbers and their thirds and then lookup the answer.
Or += which is needed for the bitshift solution.
#include <stdio.h> #include <stdlib.h> #include <string.h>
int main() { FILE * fp=fopen("temp.dat","w+b"); int number=12346; int divisor=3; char * buf = malloc(number); memset(buf,0,number); fwrite(buf,number,1,fp); rewind(fp); int result=fread(buf,divisor,number,fp); printf("%d / %d = %d", number, divisor, result); free(buf); fclose(fp); return 0; }
I wonder what the Oracle interviewer would have thought if he gave that answer...
This just goes to prove that fread and fwrite are the biggest pile of crap.
You would have to handle each of the bits individually.
new java.math.BigInteger("10").divide(new java.math.BigInteger("3"));
or new java.math.BigDecimal("10").divide(new java.math.BigDecimal("3"), java.math.RoundingMode.HALF_UP);