Skip to content

Commit f06786e

Browse files
committed
Use static tables rather than computing on startup.
1 parent 7912268 commit f06786e

File tree

3 files changed

+121
-42
lines changed

3 files changed

+121
-42
lines changed

Objects/longobject.c

Lines changed: 52 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2821,35 +2821,57 @@ just 1 digit at the start, so that the copying code was exercised for every
28212821
digit beyond the first.
28222822
***/
28232823

2824-
static double log_base_BASE[37] = {0.0e0,};
2825-
static int convwidth_base[37] = {0,};
2826-
static twodigits convmultmax_base[37] = {0,};
2827-
2828-
static void
2829-
long_precompute_base_conv(void)
2830-
{
2831-
// These constants are quick to compute (likely less than 1 μs) and
2832-
// computing them at runtime avoids hard-coding a table dependant on
2833-
// PyLong_BASE.
2834-
for (int base = 2; base <= 36; base++) {
2835-
twodigits convmax = base;
2836-
int i = 1;
2837-
2838-
log_base_BASE[base] = (log((double)base) /
2839-
log((double)PyLong_BASE));
2840-
for (;;) {
2841-
twodigits next = convmax * base;
2842-
if (next > PyLong_BASE) {
2843-
break;
2844-
}
2845-
convmax = next;
2846-
++i;
2847-
}
2848-
convmultmax_base[base] = convmax;
2849-
assert(i > 0);
2850-
convwidth_base[base] = i;
2851-
}
2852-
}
2824+
// Tables are computed by Tools/scripts/long_conv_tables.py
2825+
#if PYLONG_BITS_IN_DIGIT == 15
2826+
static double log_base_BASE[37] = {0.0, 0.0, 0.06666666666666667,
2827+
0.10566416671474375, 0.13333333333333333, 0.15479520632582416,
2828+
0.17233083338141042, 0.18715699480384027, 0.19999999999999998,
2829+
0.2113283334294875, 0.22146187299249084, 0.23062877457581984,
2830+
0.2389975000480771, 0.24669598120940617, 0.25382366147050694,
2831+
0.26045937304056793, 0.26666666666666666, 0.27249752275002265,
2832+
0.27799500009615413, 0.2831951675629057, 0.28812853965915747,
2833+
0.29282116151858406, 0.2972954412424865, 0.3015707970704675,
2834+
0.3056641667147438, 0.30959041265164833, 0.3133626478760728,
2835+
0.31699250014423125, 0.3204903281371736, 0.3238653996751715,
2836+
0.3271260397072346, 0.3302797540257917, 0.33333333333333337,
2837+
0.3362929412905636, 0.3391641894166893, 0.34195220112966446,
2838+
0.34466166676282084};
2839+
static int convmultmax_base[37] = {0, 0, 32768, 19683, 16384,
2840+
15625, 7776, 16807, 32768, 6561, 10000, 14641, 20736, 28561,
2841+
2744, 3375, 4096, 4913, 5832, 6859, 8000, 9261, 10648, 12167,
2842+
13824, 15625, 17576, 19683, 21952, 24389, 27000, 29791, 32768,
2843+
1089, 1156, 1225, 1296};
2844+
static twodigits convwidth_base[37] = {0, 0, 15, 9, 7, 6, 5, 5, 5,
2845+
4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2846+
3, 3, 3, 2, 2, 2, 2};
2847+
#elif PYLONG_BITS_IN_DIGIT == 30
2848+
static double log_base_BASE[37] = {0.0, 0.0, 0.03333333333333333,
2849+
0.05283208335737188, 0.06666666666666667, 0.07739760316291208,
2850+
0.08616541669070521, 0.09357849740192013, 0.09999999999999999,
2851+
0.10566416671474375, 0.11073093649624542, 0.11531438728790992,
2852+
0.11949875002403855, 0.12334799060470308, 0.12691183073525347,
2853+
0.13022968652028397, 0.13333333333333333, 0.13624876137501132,
2854+
0.13899750004807707, 0.14159758378145285, 0.14406426982957873,
2855+
0.14641058075929203, 0.14864772062124326, 0.15078539853523376,
2856+
0.1528320833573719, 0.15479520632582416, 0.1566813239380364,
2857+
0.15849625007211562, 0.1602451640685868, 0.16193269983758574,
2858+
0.1635630198536173, 0.16513987701289584, 0.16666666666666669,
2859+
0.1681464706452818, 0.16958209470834465, 0.17097610056483223,
2860+
0.17233083338141042};
2861+
static int convmultmax_base[37] = {0, 0, 1073741824, 387420489,
2862+
1073741824, 244140625, 362797056, 282475249, 1073741824,
2863+
387420489, 1000000000, 214358881, 429981696, 815730721,
2864+
105413504, 170859375, 268435456, 410338673, 612220032,
2865+
893871739, 64000000, 85766121, 113379904, 148035889,
2866+
191102976, 244140625, 308915776, 387420489, 481890304,
2867+
594823321, 729000000, 887503681, 1073741824, 39135393,
2868+
45435424, 52521875, 60466176};
2869+
static twodigits convwidth_base[37] = {0, 0, 30, 18, 15, 12, 11,
2870+
10, 10, 9, 9, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6,
2871+
6, 6, 6, 6, 6, 6, 5, 5, 5, 5};
2872+
#else
2873+
#error "invalid PYLONG_BITS_IN_DIGIT value"
2874+
#endif
28532875

28542876
static int
28552877
long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, int base, PyLongObject **res)
@@ -2863,7 +2885,7 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits,
28632885
PyLongObject *z;
28642886
const char *p;
28652887

2866-
assert(log_base_BASE[base] != 0.0); // pre-computed by _PyLong_InitRuntime()
2888+
assert(log_base_BASE[base] != 0.0);
28672889

28682890
/* Create an int object that can contain the largest possible
28692891
* integer with this base and length. Note that there's no
@@ -6750,13 +6772,6 @@ PyLong_GetInfo(void)
67506772

67516773
/* runtime lifecycle */
67526774

6753-
PyStatus
6754-
_PyLong_InitRuntime(void)
6755-
{
6756-
long_precompute_base_conv();
6757-
return _PyStatus_OK();
6758-
}
6759-
67606775
PyStatus
67616776
_PyLong_InitTypes(PyInterpreterState *interp)
67626777
{

Python/pylifecycle.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -510,11 +510,6 @@ pycore_init_runtime(_PyRuntimeState *runtime,
510510
return status;
511511
}
512512

513-
status = _PyLong_InitRuntime();
514-
if (_PyStatus_EXCEPTION(status)) {
515-
return status;
516-
}
517-
518513
status = _PyImport_Init();
519514
if (_PyStatus_EXCEPTION(status)) {
520515
return status;

Tools/scripts/long_conv_tables.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Compute tables for longobject.c integer conversion.
4+
5+
import math
6+
import textwrap
7+
8+
9+
def format_array(name, values):
10+
values = [str(v) for v in values]
11+
values = ', '.join(values)
12+
result = f'{name} = {{{values}}};'
13+
result = textwrap.wrap(
14+
result,
15+
initial_indent=' ' * 4,
16+
subsequent_indent=' ' * 8,
17+
)
18+
return '\n'.join(result)
19+
20+
21+
def conv_tables(long_bits):
22+
steps = 0
23+
PyLong_BASE = 1 << long_bits
24+
log_base_BASE = [0.0] * 37
25+
convmultmax_base = [0] * 37
26+
convwidth_base = [0] * 37
27+
for base in range(2, 37):
28+
convmax = base
29+
i = 1
30+
log_base_BASE[base] = math.log(float(base)) / math.log(PyLong_BASE)
31+
while True:
32+
steps += 1
33+
next = convmax * base
34+
if next > PyLong_BASE:
35+
break
36+
convmax = next
37+
i += 1
38+
convmultmax_base[base] = convmax
39+
assert i > 0
40+
convwidth_base[base] = i
41+
# print('steps', steps)
42+
return '\n'.join(
43+
[
44+
format_array('static double log_base_BASE[37]', log_base_BASE),
45+
format_array('static int convmultmax_base[37]', convmultmax_base),
46+
format_array(
47+
'static twodigits convwidth_base[37]', convwidth_base
48+
),
49+
]
50+
)
51+
52+
53+
def main():
54+
print(
55+
f'''\
56+
// Tables are computed by Tools/scripts/long_conv_tables.py
57+
#if PYLONG_BITS_IN_DIGIT == 15
58+
{conv_tables(15)}
59+
#elif PYLONG_BITS_IN_DIGIT == 30
60+
{conv_tables(30)}
61+
#else
62+
#error "invalid PYLONG_BITS_IN_DIGIT value"
63+
#endif
64+
'''
65+
)
66+
67+
68+
if __name__ == '__main__':
69+
main()

0 commit comments

Comments
 (0)