mpmath 0.2__zip → 0.4__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mpmath-0.4/CHANGES +52 -0
- {mpmath-0.2 → mpmath-0.4}/PKG-INFO +1 -1
- {mpmath-0.2 → mpmath-0.4}/README +58 -8
- {mpmath-0.2 → mpmath-0.4}/demo/pidigits.py +10 -16
- mpmath-0.4/mpmath/__init__.py +3 -0
- mpmath-0.4/mpmath/functions2.py +384 -0
- mpmath-0.4/mpmath/lib/__init__.py +7 -0
- mpmath-0.4/mpmath/lib/complexop.py +181 -0
- mpmath-0.4/mpmath/lib/constants.py +212 -0
- mpmath-0.4/mpmath/lib/convert.py +233 -0
- mpmath-0.4/mpmath/lib/floatop.py +252 -0
- mpmath-0.4/mpmath/lib/functions.py +350 -0
- mpmath-0.4/mpmath/lib/squareroot.py +199 -0
- mpmath-0.4/mpmath/lib/util.py +268 -0
- mpmath-0.4/mpmath/mpmath.py +739 -0
- {mpmath-0.2 → mpmath-0.4}/setup.py +2 -2
- mpmath-0.4/tests/benchmark.py +139 -0
- mpmath-0.4/tests/runtests.py +5 -0
- mpmath-0.4/tests/test_bitwise.py +110 -0
- mpmath-0.4/tests/test_compatibility.py +51 -0
- mpmath-0.4/tests/test_convert.py +62 -0
- mpmath-0.4/tests/test_division.py +126 -0
- mpmath-0.4/tests/test_functions2.py +68 -0
- mpmath-0.4/tests/test_hp.py +199 -0
- {mpmath-0.2 → mpmath-0.4}/tests/test_mpmath.py +137 -166
- mpmath-0.2/CHANGES +0 -23
- mpmath-0.2/mpmath/__init__.py +0 -2
- mpmath-0.2/mpmath/lib.py +0 -1122
- mpmath-0.2/mpmath/mpmath.py +0 -515
- {mpmath-0.2 → mpmath-0.4}/LICENSE +0 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides functions for computing approximate square roots
|
|
3
|
+
(in fixed-point or floating-point form) of positive real numbers.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from util import *
|
|
7
|
+
from floatop import *
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def sqrt_initial(y, prec):
|
|
11
|
+
"""Given y = floor(x * 2**prec), compute floor(sqrt(x) * 2**50),
|
|
12
|
+
i.e. calculate a 50-bit approximation of the square root. This is
|
|
13
|
+
done quickly using regular floating-point arithmetic. It is
|
|
14
|
+
assumed that x ~= 1."""
|
|
15
|
+
|
|
16
|
+
# Two cases; the second avoids overflow
|
|
17
|
+
if prec < 200: return int(y**0.5 * 2.0**(50 - prec*0.5))
|
|
18
|
+
else: return int((y >> (prec-100))**0.5)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# XXX: doesn't work
|
|
22
|
+
def invsqrt_initial(y, prec):
|
|
23
|
+
"""Like sqrt_initial, but computes 1/sqrt(y) instead of sqrt(y)."""
|
|
24
|
+
if prec < 200: return int(y**-0.5 * 2.0**(50 + prec*0.5))
|
|
25
|
+
else: return int((y >> (prec-100)) ** -0.5)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def sqrt_fixed(y, prec):
|
|
29
|
+
"""
|
|
30
|
+
Square root of a fixed-point number.
|
|
31
|
+
|
|
32
|
+
Given the big integer y = floor(x * 2**prec), this function returns
|
|
33
|
+
floor(r * 2**prec) where r = sqrt(x).
|
|
34
|
+
|
|
35
|
+
We start from a 50-bit estimate for r generated with ordinary
|
|
36
|
+
floating-point arithmetic, and then refines the value to full
|
|
37
|
+
accuracy using the iteration
|
|
38
|
+
|
|
39
|
+
1 / y \
|
|
40
|
+
r = --- | r + --- |
|
|
41
|
+
n+1 2 \ n r_n /
|
|
42
|
+
|
|
43
|
+
which is simply Newton's method applied to the equation r**2 = y.
|
|
44
|
+
|
|
45
|
+
Newton's method doubles the accuracy with each step. We make use of
|
|
46
|
+
this fact by only using a precision corresponding to the current
|
|
47
|
+
accuracy during intermediate iterations. For example, with a 50-bit
|
|
48
|
+
accurate r_1, r_2 can be computed using 100-bit precision, r_3
|
|
49
|
+
using 200-bit precision, and so on. (In practice, the precision
|
|
50
|
+
levels must be chosen slightly more conservatively to account for
|
|
51
|
+
rounding errors in the last one or two bits.)
|
|
52
|
+
|
|
53
|
+
It is assumed that x ~= 1 (the main fsqrt() function fiddles with
|
|
54
|
+
the exponent of the input to reduce it to unit magnitude before
|
|
55
|
+
passing it here.)
|
|
56
|
+
|
|
57
|
+
TODO: it would be possible to specify separate precision levels
|
|
58
|
+
for the input and output, which could be useful when calculating
|
|
59
|
+
pure-integer square roots.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
r = sqrt_initial(y, prec)
|
|
63
|
+
extra = 10
|
|
64
|
+
prevp = 50
|
|
65
|
+
|
|
66
|
+
for p in giant_steps(50, prec+extra):
|
|
67
|
+
|
|
68
|
+
# Explanation: in the first term, we shift by the appropriate number
|
|
69
|
+
# of bits to convert r from the previous precision to the current one.
|
|
70
|
+
# The "-1" divides by two in the same step.
|
|
71
|
+
|
|
72
|
+
# In the second term, we do a fixed-point division using the usual
|
|
73
|
+
# formula (y<<precision)//r. The precision term is a bit messy and
|
|
74
|
+
# takes into account the fact that y, r_n and r_{n+1} all have
|
|
75
|
+
# different precision levels. As before, the "-1" divides by two.
|
|
76
|
+
r = lshift_quick(r, p-prevp-1) + (lshift_quick(y, p+prevp-prec-1)//r)
|
|
77
|
+
|
|
78
|
+
prevp = p
|
|
79
|
+
|
|
80
|
+
return r >> extra
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def sqrt_fixed2(y, prec):
|
|
84
|
+
"""
|
|
85
|
+
This function is essentially equivalent to sqrt_fixed (see its
|
|
86
|
+
documentation), but uses an asymptotically faster algorithm.
|
|
87
|
+
|
|
88
|
+
Instead of using Newton's method to calculate sqrt(y) directly,
|
|
89
|
+
we calculate 1/sqrt(y) with Newton's method and multiply by y to
|
|
90
|
+
obtain sqrt(y). The Newton iteration for 1/sqrt(y) is
|
|
91
|
+
|
|
92
|
+
r
|
|
93
|
+
n / 2 \
|
|
94
|
+
r = ---- * | 3 - y * r |.
|
|
95
|
+
n+1 2 \ n /
|
|
96
|
+
|
|
97
|
+
This is slightly slower at low precision levels since it requires
|
|
98
|
+
three multiplications in each step, as opposed to the single
|
|
99
|
+
division in the Newton iteration for sqrt(y).
|
|
100
|
+
|
|
101
|
+
However, since Python uses Karatsuba algorithm for multiplication,
|
|
102
|
+
three multiplications can be performed much more quickly than a
|
|
103
|
+
single division at high precision levels. In practice, the cutoff
|
|
104
|
+
where sqrt_fixed2 becomes faster than sqrt_fixed seems to be around
|
|
105
|
+
60,000 bits.
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
# XXX
|
|
109
|
+
from mpmath.lib import to_float, normalize, ROUND_FLOOR
|
|
110
|
+
r = to_float(normalize(y, -prec, 64, ROUND_FLOOR)) ** -0.5
|
|
111
|
+
r = int(r * 2**50)
|
|
112
|
+
|
|
113
|
+
# r = invsqrt_initial(y, prec)
|
|
114
|
+
|
|
115
|
+
extra = 10
|
|
116
|
+
prevp = 50
|
|
117
|
+
|
|
118
|
+
for p in giant_steps(50, prec+extra):
|
|
119
|
+
|
|
120
|
+
# This is even messier than in sqrt_fixed. As many shifts as possible
|
|
121
|
+
# have been combined together for optimal speed, at a slight expense
|
|
122
|
+
# of legibility.
|
|
123
|
+
|
|
124
|
+
# Compute r**2 at precision p.
|
|
125
|
+
r2 = rshift_quick(r*r, 2*prevp - p)
|
|
126
|
+
|
|
127
|
+
# A = r, converted from precision prevp to p
|
|
128
|
+
A = lshift_quick(r, p-prevp)
|
|
129
|
+
|
|
130
|
+
# S = y * r2, computed at precision p. We shift y by '-prec' to
|
|
131
|
+
# account for its initial precision, and by 'p' for the fixed-point
|
|
132
|
+
# multiplication
|
|
133
|
+
S = (lshift_quick(y, p-prec) * r2) >> p
|
|
134
|
+
|
|
135
|
+
# B = (3-S) and finally the outer product, both done at precision p
|
|
136
|
+
B = (3<<p) - S
|
|
137
|
+
r = (A*B) >> (p+1)
|
|
138
|
+
|
|
139
|
+
prevp = p
|
|
140
|
+
|
|
141
|
+
# Finally, sqrt(y) = y * (1/sqrt(y))
|
|
142
|
+
r = (r * y) >> prec
|
|
143
|
+
|
|
144
|
+
return r >> extra
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def fsqrt(s, prec, rounding):
|
|
150
|
+
"""
|
|
151
|
+
Floating-point square root.
|
|
152
|
+
|
|
153
|
+
Returns a tuple representing the square root of s, rounded to the
|
|
154
|
+
nearest floating-point number in the specified rounding direction.
|
|
155
|
+
The input must be a tuple representing a nonnegative floating-point
|
|
156
|
+
number.
|
|
157
|
+
"""
|
|
158
|
+
if s == fone:
|
|
159
|
+
return fone
|
|
160
|
+
|
|
161
|
+
man, exp, bc = s
|
|
162
|
+
|
|
163
|
+
if not man:
|
|
164
|
+
return fzero
|
|
165
|
+
|
|
166
|
+
# Convert to a fixed-point number with prec2 bits. Adjust
|
|
167
|
+
# exponents to be even so that they can be divided in half
|
|
168
|
+
prec2 = prec + 10 + (prec & 1)
|
|
169
|
+
|
|
170
|
+
if exp & 1:
|
|
171
|
+
exp -= 1
|
|
172
|
+
man <<= 1
|
|
173
|
+
bc += 1
|
|
174
|
+
|
|
175
|
+
# Mantissa may have more bits than we need. Trim it down.
|
|
176
|
+
shift = bc - prec2
|
|
177
|
+
shift -= shift & 1
|
|
178
|
+
man = rshift_quick(man, shift)
|
|
179
|
+
|
|
180
|
+
if prec < 65000:
|
|
181
|
+
man = sqrt_fixed(man, prec2)
|
|
182
|
+
else:
|
|
183
|
+
man = sqrt_fixed2(man, prec2)
|
|
184
|
+
|
|
185
|
+
return normalize(man, (exp+shift-prec2)>>1, prec, rounding)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def fhypot(x, y, prec, rounding):
|
|
190
|
+
if y == fzero:
|
|
191
|
+
return fabs(x, prec, rounding)
|
|
192
|
+
if x == fzero:
|
|
193
|
+
return fabs(y, prec, rounding)
|
|
194
|
+
|
|
195
|
+
RF = ROUND_FLOOR
|
|
196
|
+
hypot2 = fadd(fmul(x,x,prec+4,RF), fmul(y,y,prec+4,RF), prec+4, RF)
|
|
197
|
+
|
|
198
|
+
return fsqrt(hypot2, prec, rounding)
|
|
199
|
+
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Contents of this module:
|
|
3
|
+
|
|
4
|
+
* Integer and bit-level operations
|
|
5
|
+
* Miscellaneous utilities
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import math
|
|
10
|
+
import decimal
|
|
11
|
+
|
|
12
|
+
# Same as standard Python float
|
|
13
|
+
STANDARD_PREC = 53
|
|
14
|
+
|
|
15
|
+
LOG2_10 = math.log(10,2) # 3.3219...
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# All supported rounding modes. We define them as integer constants for easy
|
|
19
|
+
# management, but change __repr__ to give more information on inspection
|
|
20
|
+
|
|
21
|
+
class Rounding(int):
|
|
22
|
+
|
|
23
|
+
def __new__(cls, level, name):
|
|
24
|
+
a = int.__new__(cls, level)
|
|
25
|
+
a.name = name
|
|
26
|
+
return a
|
|
27
|
+
|
|
28
|
+
def __repr__(self):
|
|
29
|
+
return self.name
|
|
30
|
+
|
|
31
|
+
__str__ = __repr__
|
|
32
|
+
|
|
33
|
+
ROUND_DOWN = Rounding(1, 'ROUND_DOWN')
|
|
34
|
+
ROUND_UP = Rounding(2, 'ROUND_UP')
|
|
35
|
+
ROUND_FLOOR = Rounding(3, 'ROUND_FLOOR')
|
|
36
|
+
ROUND_CEILING = Rounding(4, 'ROUND_CEILING')
|
|
37
|
+
ROUND_HALF_UP = Rounding(5, 'ROUND_HALF_UP')
|
|
38
|
+
ROUND_HALF_DOWN = Rounding(6, 'ROUND_HALF_DOWN')
|
|
39
|
+
ROUND_HALF_EVEN = Rounding(7, 'ROUND_HALF_EVEN')
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def giant_steps(start, target):
|
|
43
|
+
"""Generate a list of precisions ranging from 'start' to 'target'
|
|
44
|
+
that doubles with each step. This is used by quadratically
|
|
45
|
+
convergent iterations (that is, Newton iterations), where we want
|
|
46
|
+
to keep the precision at the same level as the accuracy in each
|
|
47
|
+
step to minimize work.
|
|
48
|
+
|
|
49
|
+
For example, to find a sequence of precisions to reach 1000 bits
|
|
50
|
+
starting from a 53-bit estimate, giant_steps(53, 1000) gives
|
|
51
|
+
|
|
52
|
+
[64, 126, 251, 501, 1000]
|
|
53
|
+
|
|
54
|
+
So, if we start Newton's method with a 53-bit accurate initial
|
|
55
|
+
guess, the first iteration should be carried out at 64-bit
|
|
56
|
+
precision, the second at 126-bit precision, and so on.
|
|
57
|
+
|
|
58
|
+
Note the conservative rounding (1000 to 501, etc); this is used
|
|
59
|
+
guard against unit errors in the last place."""
|
|
60
|
+
L = [target]
|
|
61
|
+
while L[-1] > start*2:
|
|
62
|
+
L = L + [L[-1]//2 + 1]
|
|
63
|
+
return L[::-1]
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def rshift_quick(x, n):
|
|
67
|
+
"""For an integer x, calculate x >> n with the fastest (floor)
|
|
68
|
+
rounding. Unlike the plain Python expression (x >> n), n is
|
|
69
|
+
allowed to be negative, in which case a left shift is performed."""
|
|
70
|
+
if n >= 0: return x >> n
|
|
71
|
+
else: return x << (-n)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def lshift_quick(x, n):
|
|
75
|
+
"""For an integer x, calculate x << n. Unlike the plain Python
|
|
76
|
+
expression (x << n), n is allowed to be negative, in which case a
|
|
77
|
+
right shift with default (floor) rounding is performed."""
|
|
78
|
+
if n >= 0: return x << n
|
|
79
|
+
else: return x >> (-n)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def make_fixed(s, prec):
|
|
83
|
+
"""Convert a floating-point number to a fixed-point big integer"""
|
|
84
|
+
man, exp, bc = s
|
|
85
|
+
offset = exp + prec
|
|
86
|
+
if offset >= 0:
|
|
87
|
+
return man << offset
|
|
88
|
+
else:
|
|
89
|
+
return man >> (-offset)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def bitcount(n, log=math.log, table=(0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4)):
|
|
93
|
+
"""Give size of n in bits; i.e. the position of the highest set bit
|
|
94
|
+
in n. If n is negative, the absolute value is used. The bitcount of
|
|
95
|
+
zero is taken to be 0."""
|
|
96
|
+
|
|
97
|
+
if not n: return 0
|
|
98
|
+
if n < 0: n = -n
|
|
99
|
+
|
|
100
|
+
# math.log gives a good estimate, and never overflows, but
|
|
101
|
+
# is not always exact. Subtract 2 to underestimate, then
|
|
102
|
+
# count remaining bits by table lookup
|
|
103
|
+
bc = int(log(n, 2)) - 2
|
|
104
|
+
if bc < 0:
|
|
105
|
+
bc = 0
|
|
106
|
+
return bc + table[n >> bc]
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# from decimal.py -- faster for small precs
|
|
110
|
+
def bitcount2(n, correction = {
|
|
111
|
+
'0': 4, '1': 3, '2': 2, '3': 2,
|
|
112
|
+
'4': 1, '5': 1, '6': 1, '7': 1,
|
|
113
|
+
'8': 0, '9': 0, 'a': 0, 'b': 0,
|
|
114
|
+
'c': 0, 'd': 0, 'e': 0, 'f': 0}):
|
|
115
|
+
if n < 0:
|
|
116
|
+
n = -n
|
|
117
|
+
hex_n = "%x" % n
|
|
118
|
+
return 4*len(hex_n) - correction[hex_n[0]]
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def trailing_zeros(n):
|
|
122
|
+
"""Count trailing zero bits in an integer. If n is negative, it is
|
|
123
|
+
replaced by its absolute value."""
|
|
124
|
+
if n & 1: return 0
|
|
125
|
+
if not n: return 0
|
|
126
|
+
if n < 0: n = -n
|
|
127
|
+
t = 0
|
|
128
|
+
while not n & 0xffffffffffffffff: n >>= 64; t += 64
|
|
129
|
+
while not n & 0xff: n >>= 8; t += 8
|
|
130
|
+
while not n & 1: n >>= 1; t += 1
|
|
131
|
+
return t
|
|
132
|
+
|
|
133
|
+
#----------------------------------------------------------------------------
|
|
134
|
+
# Integer shifting with directed rounding
|
|
135
|
+
#
|
|
136
|
+
|
|
137
|
+
def round_floor(x, n):
|
|
138
|
+
if not n or not x: return x
|
|
139
|
+
if n < 0: return x << -n
|
|
140
|
+
return x >> n
|
|
141
|
+
|
|
142
|
+
def round_ceiling(x, n):
|
|
143
|
+
if not n or not x: return x
|
|
144
|
+
if n < 0: return x << -n
|
|
145
|
+
return -((-x) >> n)
|
|
146
|
+
|
|
147
|
+
def round_down(x, n):
|
|
148
|
+
if not n or not x: return x
|
|
149
|
+
if n < 0: return x << -n
|
|
150
|
+
if x > 0:
|
|
151
|
+
return x >> n
|
|
152
|
+
else:
|
|
153
|
+
return -((-x) >> n)
|
|
154
|
+
|
|
155
|
+
def round_up(x, n):
|
|
156
|
+
if not n or not x: return x
|
|
157
|
+
if n < 0: return x << -n
|
|
158
|
+
if x > 0:
|
|
159
|
+
return -((-x) >> n)
|
|
160
|
+
else:
|
|
161
|
+
return x >> n
|
|
162
|
+
|
|
163
|
+
def round_half_up(x, n):
|
|
164
|
+
if not n or not x: return x
|
|
165
|
+
if n < 0: return x << -n
|
|
166
|
+
positive = x > 0
|
|
167
|
+
if positive: t = x >> (n-1)
|
|
168
|
+
else: t = (-x) >> (n-1)
|
|
169
|
+
if t & 1:
|
|
170
|
+
if positive: return (t>>1)+1
|
|
171
|
+
else: return -((t>>1)+1)
|
|
172
|
+
if positive: return t>>1
|
|
173
|
+
else: return -(t>>1)
|
|
174
|
+
|
|
175
|
+
def round_half_down(x, n):
|
|
176
|
+
if not n or not x: return x
|
|
177
|
+
if n < 0: return x << -n
|
|
178
|
+
positive = x > 0
|
|
179
|
+
if positive: t = x >> (n-1)
|
|
180
|
+
else: t = (-x) >> (n-1)
|
|
181
|
+
if t & 1 and x & ((1<<(n-1))-1):
|
|
182
|
+
if positive: return (t>>1)+1
|
|
183
|
+
else: return -((t>>1)+1)
|
|
184
|
+
if positive: return t>>1
|
|
185
|
+
else: return -(t>>1)
|
|
186
|
+
|
|
187
|
+
def round_half_even(x, n):
|
|
188
|
+
if not n or not x: return x
|
|
189
|
+
if n < 0: return x << -n
|
|
190
|
+
positive = x > 0
|
|
191
|
+
if positive: t = x >> (n-1)
|
|
192
|
+
else: t = (-x) >> (n-1)
|
|
193
|
+
if t & 1 and (t&2 or x & ((1<<(n-1))-1)):
|
|
194
|
+
if positive: return (t>>1)+1
|
|
195
|
+
else: return -((t>>1)+1)
|
|
196
|
+
if positive: return t>>1
|
|
197
|
+
else: return -(t>>1)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
rounding_functions = {
|
|
201
|
+
ROUND_FLOOR : round_floor,
|
|
202
|
+
ROUND_CEILING : round_ceiling,
|
|
203
|
+
ROUND_DOWN : round_down,
|
|
204
|
+
ROUND_UP : round_up,
|
|
205
|
+
ROUND_HALF_UP : round_half_up,
|
|
206
|
+
ROUND_HALF_DOWN : round_half_down,
|
|
207
|
+
ROUND_HALF_EVEN : round_half_even
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def rshift(x, n, rounding):
|
|
212
|
+
"""Shift x (a plain Python integer) n bits to the right (i.e.,
|
|
213
|
+
calculate x/(2**n)), and round to the nearest integer in accordance
|
|
214
|
+
with the specified rounding mode. The exponent n may be negative,
|
|
215
|
+
in which case x is shifted to the left (and no rounding is
|
|
216
|
+
necessary)."""
|
|
217
|
+
return rounding_functions[rounding](x, n)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
# TODO: speed up for bases 2, 4, 8, 16, ...
|
|
222
|
+
|
|
223
|
+
def bin_to_radix(x, xbits, base, bdigits):
|
|
224
|
+
"""
|
|
225
|
+
Radix conversion for fixed-point numbers. That is, convert
|
|
226
|
+
x * 2**xbits to floor(x * 10**bdigits).
|
|
227
|
+
"""
|
|
228
|
+
return x * (base**bdigits) >> xbits
|
|
229
|
+
|
|
230
|
+
stddigits = '0123456789abcdefghijklmnopqrstuvwxyz'
|
|
231
|
+
|
|
232
|
+
def small_numeral(n, base=10, digits=stddigits):
|
|
233
|
+
"""
|
|
234
|
+
Return the string numeral of a positive integer in an arbitrary
|
|
235
|
+
base. Most efficient for small input.
|
|
236
|
+
"""
|
|
237
|
+
if base == 10:
|
|
238
|
+
return str(n)
|
|
239
|
+
digs = []
|
|
240
|
+
while n:
|
|
241
|
+
n, digit = divmod(n, base)
|
|
242
|
+
digs.append(digits[digit])
|
|
243
|
+
return "".join(digs[::-1])
|
|
244
|
+
|
|
245
|
+
def numeral(n, base=10, size=0, digits=stddigits):
|
|
246
|
+
"""
|
|
247
|
+
Represent the integer n as a string of digits in the given base.
|
|
248
|
+
Recursive division is used to make this function about 3x faster
|
|
249
|
+
than Python's str() for converting integers to decimal strings.
|
|
250
|
+
|
|
251
|
+
The 'size' parameters specifies the number of digits in n; this
|
|
252
|
+
number is only used to determine splitting points and need not
|
|
253
|
+
be exact.
|
|
254
|
+
"""
|
|
255
|
+
|
|
256
|
+
if n < 0:
|
|
257
|
+
return "-" + numeral(-n, base, size, digits)
|
|
258
|
+
|
|
259
|
+
# Fast enough to do directly
|
|
260
|
+
if size < 250:
|
|
261
|
+
return small_numeral(n, base, digits)
|
|
262
|
+
|
|
263
|
+
# Divide in half
|
|
264
|
+
half = (size // 2) + (size & 1)
|
|
265
|
+
A, B = divmod(n, base**half)
|
|
266
|
+
ad = numeral(A, base, half, digits)
|
|
267
|
+
bd = numeral(B, base, half, digits).rjust(half, "0")
|
|
268
|
+
return ad + bd
|