Re: division by 7efficiently
- From: torbenm@xxxxxxxxxxxxx (Torben Ægidius Mogensen)
- Date: Mon, 05 Feb 2007 11:10:13 +0100
Jón Fairbairn <jon.fairbairn@xxxxxxxxxxxx> writes:
"eKo1" <berndlosert@xxxxxxxxxxxx> writes:
On Feb 1, 2:28 pm, "Krypto" <krypto.wiz...@xxxxxxxxx> wrote:
The correct answer as told to me by a person is
(N>>3) + ((N-7*(N>>3))>>3)
The above term always gives division by 7
N >> 3 is the same as dividing the number by eight so you have that
(N>>3) + ((N-7*(N>>3))>>3) = N/8 + (N - 7(N/8))/8 = N/8 + N/8 - 7N/64
= 2N/8 - 7N/64 = (16N - 7N) / 64 = 9/64 N.
9/64 = 0.140625
1/7 = 0.14285714285714285...
Close, but no cigar.
I suspect that what the interviewer was looking for was
something like:
division by 7 is the same as multiplication by 1/7. 1/7 in
binary is 0.001001001... (1/8 + 1/64 + 1/512 + ...)
So if you repeat "add N>>3 and shift the result 3 places
right" until it stops changing, you've got N/7 -- except
that if you do this in integer arithmetic it treats
0.111... as 0 when it really means 1. Correcting for that is
left as an exercise for the reader ;-)
You can do even better than this, by exploiting the periodicity of 1/7
to double the number of correct bits per step (instead of just adding
three correct bits per step):
x = N>>3; /* N * 0.001 */
x += x>>3; /* N * 0.001001 */
x += x>>6; /* N * 0.001001001001 */
x += x>>12; /* N * 0.001001001001001001001001 */
x += x>>24; /* N * 0.001001001001001001001001001001001001001001001001 */
There is still the problem of rounding, though. You can do this by
multiplying by 8/7 and then use the last bits to determine rounding
when doing a final shift:
x = N + (N>>3); /* N * 1.001 */
x += x>>6; /* N * 1.001001001 */
x += x>>12; /* N * 1.001001001001001001001 */
x += x>>24; /* N * 1.001001001001001001001001001001001001001001001 */
x = (x>>3) + (x&4 ? 1 : 0);
/* Divide by 8 and round up if last bits are >=4 */
Note that this assumes N>=0 and that N*8/7 fits within integers.
Note, also, that the above rounds the result, so it is not the same as
integer division. You can get closer to integer division if you only
round up if the last three bits before the last shift are all 1, i.e.,
by replacing the last line by:
x = (x>>3) + ((x&7)==7 ? 1 : 0);
/* Divide by 8 and round up if last bits are =7 */
It is not exactly the same as integer division, though. A test
program reveals that for 12 values of N under 1000 the above gives a
result that is one less than N/7. You can get more exact division at
the cost of reducing the highest allowable value of N by changing the
above to:
x = N + (N<<3); /* N * 1001 */
x += x>>6; /* N * 1001.001001 */
x += x>>12; /* N * 1001.001001001001001001 */
x += x>>24; /* N * 1001.001001001001001001001001001001001001001001 */
x = (x>>6) + ((x&63)==63 ? 1 : 0);
/* Divide by 64 and round up if last bits are = 63 */
Now, the smallest N that goes wrong is 28679 and there are "only" 288
Ns below 100000 that go wrong. You can trade range of N and exactness
of division even more, e.g., by:
x = N + (N<<3); /* N * 1001 */
x += x<<6; /* N * 1001001001. */
x += x>>12; /* N * 1001001001.001001001001 */
x += x>>24; /* N * 1001001001.001001001001001001001001001001001001 */
x = (x>>12) + ((x&4095)==4095 ? 1 : 0);
/* Divide by 2^12 and round up if last bits are = 2^12-1 */
Now it is exact up to N = 7*2^20 = 7340032, but it runs into overflow
problems when N is greater.
So, if you want fast integer division by 7 and you know N <= 7*2^20
(and you use 32-bit unsigned integers), you can use the above.
The method used above is fairly general: calculate exactly until the
period starts repeating, then use shifting to double the number of
periods at each step. It gets a bit more complicated if there are
bits before the period starts, but you can add these in later.
Torben
.
- Follow-Ups:
- Re: division by 7efficiently
- From: Torben Ægidius Mogensen
- Re: division by 7efficiently
- References:
- division by 7efficiently
- From: krypto . wizard
- Re: division by 7efficiently
- From: Tom Truscott
- Re: division by 7efficiently
- From: Krypto
- Re: division by 7efficiently
- From: eKo1
- Re: division by 7efficiently
- From: Jón Fairbairn
- division by 7efficiently
- Prev by Date: Re: Contesting machine checked proofs (was Hofman/Diaby 'debate')
- Next by Date: Re: division by 7efficiently
- Previous by thread: Re: division by 7efficiently
- Next by thread: Re: division by 7efficiently
- Index(es):
Relevant Pages
|