-
Notifications
You must be signed in to change notification settings - Fork 39
/
magicgu.py.txt
50 lines (42 loc) · 1.84 KB
/
magicgu.py.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/usr/bin/python
""" Division by Multiplication Considered More Generally
Handles arbitrary max dividends (not necessarily of the form 2**W -
1), and bignums.
Computes the magic number for unsigned division, given a max value of
the dividend, and a divisor.
This uses equations (26) and (27) on page 181, but with nc determined
from the maximum value of n, which is not necessarily 2**W - 1 for W =
the word size of n. It finds the smallest number that can serve for a
multiplier for all n in the range 0 <= n <= nmax.
It is much simpler than the programs given in Hacker's Delight (e.g.,
that of Figure 10-2) because in Python, one need not be concerned about
overflowing the word size in which the computations are done.
Example: magicgu(255, 7) is a 9-bit number, but magicgu(200, 7) is an
8-bit number.
Also, magicgu(127, 7) is an 8-bit number, but magicgu(90, 7) is a
6-bit number. """
import sys
# ----------------------------- magicgu --------------------------------
def magicgu(nmax, d):
nc = ((nmax + 1)//d)*d - 1
nbits = len(bin(nmax)) - 2
for p in range(0, 2*nbits + 1):
if 2**p > nc*(d - 1 - (2**p - 1)%d):
m = (2**p + d - 1 - (2**p - 1)%d)//d
return (m, p)
print "Can't find p, something is wrong."
sys.exit(1)
# ------------------------------ main ----------------------------------
args = sys.argv[1:] # This is to work with Python 2.6 and 2.7.
if len(args) == 1:
args = args[0].split()
if len(args) != 2: print "Wrong number of args, need 2."; sys.exit(1)
nmax = eval(args[0]) # Max value of dividend.
d = eval(args[1]) # Divisor.
if (nmax <= 0 or d <= 0):
print "Both arguments must be > 0."
sys.exit(1)
(m, s) = magicgu(nmax, d)
print "For nmax %d, divisor %d, magic number = hex %X (%d bits), shift = %d" % \
(nmax, d, m, len(bin(m)) - 2, s)
sys.exit(0)