From 68880246800d286b3afc4df6c986cb7e9ad3cae6 Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Fri, 28 Feb 2025 16:09:28 -0800 Subject: [PATCH 1/8] gh-130599: precompute conversion constants for ``long()`` This avoids a data race in free-threaded builds due to mutating the statically arrays at runtime. Instead, compute and initialize the constants at runtime initialization. --- Include/internal/pycore_long.h | 1 + Objects/longobject.c | 47 +++++++++++++++++++++++----------- Python/pylifecycle.c | 5 ++++ 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index df0656a7cb8f0c..ae1953bbbbea6e 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -49,6 +49,7 @@ extern "C" { /* runtime lifecycle */ +extern PyStatus _PyLong_InitRuntime(void); extern PyStatus _PyLong_InitTypes(PyInterpreterState *); extern void _PyLong_FiniTypes(PyInterpreterState *interp); diff --git a/Objects/longobject.c b/Objects/longobject.c index 370328dcfe8c9a..ec4f3a85dd62b1 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -2820,23 +2820,18 @@ that triggers it(!). Instead the code was tested by artificially allocating just 1 digit at the start, so that the copying code was exercised for every digit beyond the first. ***/ -static int -long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, int base, PyLongObject **res) -{ - twodigits c; /* current input character */ - Py_ssize_t size_z; - int i; - int convwidth; - twodigits convmultmax, convmult; - digit *pz, *pzstop; - PyLongObject *z; - const char *p; - static double log_base_BASE[37] = {0.0e0,}; - static int convwidth_base[37] = {0,}; - static twodigits convmultmax_base[37] = {0,}; +static double log_base_BASE[37] = {0.0e0,}; +static int convwidth_base[37] = {0,}; +static twodigits convmultmax_base[37] = {0,}; - if (log_base_BASE[base] == 0.0) { +static void +long_precompute_base_conv(void) +{ + // These constants are quick to compute (likely less than 1 μs) and + // computing them at runtime avoids hard-coding a table dependant on + // PyLong_BASE. + for (int base = 2; base <= 36; base++) { twodigits convmax = base; int i = 1; @@ -2854,6 +2849,21 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, assert(i > 0); convwidth_base[base] = i; } +} + +static int +long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, int base, PyLongObject **res) +{ + twodigits c; /* current input character */ + Py_ssize_t size_z; + int i; + int convwidth; + twodigits convmultmax, convmult; + digit *pz, *pzstop; + PyLongObject *z; + const char *p; + + assert (log_base_BASE[base] != 0.0); // pre-computed by _PyLong_InitRuntime() /* Create an int object that can contain the largest possible * integer with this base and length. Note that there's no @@ -6740,6 +6750,13 @@ PyLong_GetInfo(void) /* runtime lifecycle */ +PyStatus +_PyLong_InitRuntime(void) +{ + long_precompute_base_conv(); + return _PyStatus_OK(); +} + PyStatus _PyLong_InitTypes(PyInterpreterState *interp) { diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 1a7f312a604614..d564fe9c1e89a1 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -510,6 +510,11 @@ pycore_init_runtime(_PyRuntimeState *runtime, return status; } + status = _PyLong_InitRuntime(); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + status = _PyImport_Init(); if (_PyStatus_EXCEPTION(status)) { return status; From 4f8cd777e7fb3d89fe12b47987825b904d6e89aa Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Sat, 1 Mar 2025 12:12:40 -0800 Subject: [PATCH 2/8] Code tidy for assert(). Co-authored-by: Kumar Aditya --- Objects/longobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index ec4f3a85dd62b1..eeae1f04e107b1 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -2863,7 +2863,7 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, PyLongObject *z; const char *p; - assert (log_base_BASE[base] != 0.0); // pre-computed by _PyLong_InitRuntime() + assert(log_base_BASE[base] != 0.0); // pre-computed by _PyLong_InitRuntime() /* Create an int object that can contain the largest possible * integer with this base and length. Note that there's no From 791226872984861a72a66d6697300f9945745e64 Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Sat, 1 Mar 2025 12:27:45 -0800 Subject: [PATCH 3/8] Update c-analyzer/cpython/ignored.tsv. --- Tools/c-analyzer/cpython/ignored.tsv | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index df0262f9c84148..8385a70670771f 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -28,11 +28,13 @@ Python/thread_pthread.h PyThread__init_thread lib_initialized - ##----------------------- ## other values (not Python-specific) +# computed by runtime init, before interpreters created +Objects/longobject.c - log_base_BASE - +Objects/longobject.c - convwidth_base - +Objects/longobject.c - convmultmax_base - + ## cached computed data - set lazily (*after* first init) # XXX Are these safe relative to write races? -Objects/longobject.c long_from_non_binary_base log_base_BASE - -Objects/longobject.c long_from_non_binary_base convwidth_base - -Objects/longobject.c long_from_non_binary_base convmultmax_base - Objects/unicodeobject.c - bloom_linebreak - # This is safe: Objects/unicodeobject.c _init_global_state initialized - From f06786e8965817971b0d14f6dcd40960a47ee952 Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Sat, 1 Mar 2025 13:50:16 -0800 Subject: [PATCH 4/8] Use static tables rather than computing on startup. --- Objects/longobject.c | 89 ++++++++++++++++++------------- Python/pylifecycle.c | 5 -- Tools/scripts/long_conv_tables.py | 69 ++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 42 deletions(-) create mode 100644 Tools/scripts/long_conv_tables.py diff --git a/Objects/longobject.c b/Objects/longobject.c index eeae1f04e107b1..c3742fd37cc3c6 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -2821,35 +2821,57 @@ just 1 digit at the start, so that the copying code was exercised for every digit beyond the first. ***/ -static double log_base_BASE[37] = {0.0e0,}; -static int convwidth_base[37] = {0,}; -static twodigits convmultmax_base[37] = {0,}; - -static void -long_precompute_base_conv(void) -{ - // These constants are quick to compute (likely less than 1 μs) and - // computing them at runtime avoids hard-coding a table dependant on - // PyLong_BASE. - for (int base = 2; base <= 36; base++) { - twodigits convmax = base; - int i = 1; - - log_base_BASE[base] = (log((double)base) / - log((double)PyLong_BASE)); - for (;;) { - twodigits next = convmax * base; - if (next > PyLong_BASE) { - break; - } - convmax = next; - ++i; - } - convmultmax_base[base] = convmax; - assert(i > 0); - convwidth_base[base] = i; - } -} +// Tables are computed by Tools/scripts/long_conv_tables.py +#if PYLONG_BITS_IN_DIGIT == 15 + static double log_base_BASE[37] = {0.0, 0.0, 0.06666666666666667, + 0.10566416671474375, 0.13333333333333333, 0.15479520632582416, + 0.17233083338141042, 0.18715699480384027, 0.19999999999999998, + 0.2113283334294875, 0.22146187299249084, 0.23062877457581984, + 0.2389975000480771, 0.24669598120940617, 0.25382366147050694, + 0.26045937304056793, 0.26666666666666666, 0.27249752275002265, + 0.27799500009615413, 0.2831951675629057, 0.28812853965915747, + 0.29282116151858406, 0.2972954412424865, 0.3015707970704675, + 0.3056641667147438, 0.30959041265164833, 0.3133626478760728, + 0.31699250014423125, 0.3204903281371736, 0.3238653996751715, + 0.3271260397072346, 0.3302797540257917, 0.33333333333333337, + 0.3362929412905636, 0.3391641894166893, 0.34195220112966446, + 0.34466166676282084}; + static int convmultmax_base[37] = {0, 0, 32768, 19683, 16384, + 15625, 7776, 16807, 32768, 6561, 10000, 14641, 20736, 28561, + 2744, 3375, 4096, 4913, 5832, 6859, 8000, 9261, 10648, 12167, + 13824, 15625, 17576, 19683, 21952, 24389, 27000, 29791, 32768, + 1089, 1156, 1225, 1296}; + static twodigits convwidth_base[37] = {0, 0, 15, 9, 7, 6, 5, 5, 5, + 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 2, 2, 2, 2}; +#elif PYLONG_BITS_IN_DIGIT == 30 + static double log_base_BASE[37] = {0.0, 0.0, 0.03333333333333333, + 0.05283208335737188, 0.06666666666666667, 0.07739760316291208, + 0.08616541669070521, 0.09357849740192013, 0.09999999999999999, + 0.10566416671474375, 0.11073093649624542, 0.11531438728790992, + 0.11949875002403855, 0.12334799060470308, 0.12691183073525347, + 0.13022968652028397, 0.13333333333333333, 0.13624876137501132, + 0.13899750004807707, 0.14159758378145285, 0.14406426982957873, + 0.14641058075929203, 0.14864772062124326, 0.15078539853523376, + 0.1528320833573719, 0.15479520632582416, 0.1566813239380364, + 0.15849625007211562, 0.1602451640685868, 0.16193269983758574, + 0.1635630198536173, 0.16513987701289584, 0.16666666666666669, + 0.1681464706452818, 0.16958209470834465, 0.17097610056483223, + 0.17233083338141042}; + static int convmultmax_base[37] = {0, 0, 1073741824, 387420489, + 1073741824, 244140625, 362797056, 282475249, 1073741824, + 387420489, 1000000000, 214358881, 429981696, 815730721, + 105413504, 170859375, 268435456, 410338673, 612220032, + 893871739, 64000000, 85766121, 113379904, 148035889, + 191102976, 244140625, 308915776, 387420489, 481890304, + 594823321, 729000000, 887503681, 1073741824, 39135393, + 45435424, 52521875, 60466176}; + static twodigits convwidth_base[37] = {0, 0, 30, 18, 15, 12, 11, + 10, 10, 9, 9, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 5, 5, 5, 5}; +#else + #error "invalid PYLONG_BITS_IN_DIGIT value" +#endif static int 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, PyLongObject *z; const char *p; - assert(log_base_BASE[base] != 0.0); // pre-computed by _PyLong_InitRuntime() + assert(log_base_BASE[base] != 0.0); /* Create an int object that can contain the largest possible * integer with this base and length. Note that there's no @@ -6750,13 +6772,6 @@ PyLong_GetInfo(void) /* runtime lifecycle */ -PyStatus -_PyLong_InitRuntime(void) -{ - long_precompute_base_conv(); - return _PyStatus_OK(); -} - PyStatus _PyLong_InitTypes(PyInterpreterState *interp) { diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index d564fe9c1e89a1..1a7f312a604614 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -510,11 +510,6 @@ pycore_init_runtime(_PyRuntimeState *runtime, return status; } - status = _PyLong_InitRuntime(); - if (_PyStatus_EXCEPTION(status)) { - return status; - } - status = _PyImport_Init(); if (_PyStatus_EXCEPTION(status)) { return status; diff --git a/Tools/scripts/long_conv_tables.py b/Tools/scripts/long_conv_tables.py new file mode 100644 index 00000000000000..16ee79a8844086 --- /dev/null +++ b/Tools/scripts/long_conv_tables.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +# +# Compute tables for longobject.c integer conversion. + +import math +import textwrap + + +def format_array(name, values): + values = [str(v) for v in values] + values = ', '.join(values) + result = f'{name} = {{{values}}};' + result = textwrap.wrap( + result, + initial_indent=' ' * 4, + subsequent_indent=' ' * 8, + ) + return '\n'.join(result) + + +def conv_tables(long_bits): + steps = 0 + PyLong_BASE = 1 << long_bits + log_base_BASE = [0.0] * 37 + convmultmax_base = [0] * 37 + convwidth_base = [0] * 37 + for base in range(2, 37): + convmax = base + i = 1 + log_base_BASE[base] = math.log(float(base)) / math.log(PyLong_BASE) + while True: + steps += 1 + next = convmax * base + if next > PyLong_BASE: + break + convmax = next + i += 1 + convmultmax_base[base] = convmax + assert i > 0 + convwidth_base[base] = i + # print('steps', steps) + return '\n'.join( + [ + format_array('static double log_base_BASE[37]', log_base_BASE), + format_array('static int convmultmax_base[37]', convmultmax_base), + format_array( + 'static twodigits convwidth_base[37]', convwidth_base + ), + ] + ) + + +def main(): + print( + f'''\ +// Tables are computed by Tools/scripts/long_conv_tables.py +#if PYLONG_BITS_IN_DIGIT == 15 +{conv_tables(15)} +#elif PYLONG_BITS_IN_DIGIT == 30 +{conv_tables(30)} +#else + #error "invalid PYLONG_BITS_IN_DIGIT value" +#endif +''' + ) + + +if __name__ == '__main__': + main() From 6ce699d00b41572921a41f81583f147516b9f12d Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Sat, 1 Mar 2025 13:58:31 -0800 Subject: [PATCH 5/8] Remove unneeded func declaration, fix comment. --- Include/internal/pycore_long.h | 1 - Tools/c-analyzer/cpython/ignored.tsv | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index ae1953bbbbea6e..df0656a7cb8f0c 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -49,7 +49,6 @@ extern "C" { /* runtime lifecycle */ -extern PyStatus _PyLong_InitRuntime(void); extern PyStatus _PyLong_InitTypes(PyInterpreterState *); extern void _PyLong_FiniTypes(PyInterpreterState *interp); diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 8385a70670771f..9b624d809879ff 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -28,7 +28,7 @@ Python/thread_pthread.h PyThread__init_thread lib_initialized - ##----------------------- ## other values (not Python-specific) -# computed by runtime init, before interpreters created +# static tables computed by external script Objects/longobject.c - log_base_BASE - Objects/longobject.c - convwidth_base - Objects/longobject.c - convmultmax_base - From d8b044c42be98305705f26e232f89ecc3a990e34 Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Mon, 3 Mar 2025 13:40:57 -0800 Subject: [PATCH 6/8] Fix array declarations. Use "const" and fix the swapped types of convmultmax_base and convwidth_base. --- Objects/longobject.c | 82 +++++++++++++++---------------- Tools/scripts/long_conv_tables.py | 6 +-- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index c3742fd37cc3c6..f2872760d23ea0 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -2823,52 +2823,52 @@ digit beyond the first. // Tables are computed by Tools/scripts/long_conv_tables.py #if PYLONG_BITS_IN_DIGIT == 15 - static double log_base_BASE[37] = {0.0, 0.0, 0.06666666666666667, - 0.10566416671474375, 0.13333333333333333, 0.15479520632582416, - 0.17233083338141042, 0.18715699480384027, 0.19999999999999998, - 0.2113283334294875, 0.22146187299249084, 0.23062877457581984, - 0.2389975000480771, 0.24669598120940617, 0.25382366147050694, - 0.26045937304056793, 0.26666666666666666, 0.27249752275002265, - 0.27799500009615413, 0.2831951675629057, 0.28812853965915747, - 0.29282116151858406, 0.2972954412424865, 0.3015707970704675, - 0.3056641667147438, 0.30959041265164833, 0.3133626478760728, - 0.31699250014423125, 0.3204903281371736, 0.3238653996751715, - 0.3271260397072346, 0.3302797540257917, 0.33333333333333337, - 0.3362929412905636, 0.3391641894166893, 0.34195220112966446, - 0.34466166676282084}; - static int convmultmax_base[37] = {0, 0, 32768, 19683, 16384, - 15625, 7776, 16807, 32768, 6561, 10000, 14641, 20736, 28561, - 2744, 3375, 4096, 4913, 5832, 6859, 8000, 9261, 10648, 12167, - 13824, 15625, 17576, 19683, 21952, 24389, 27000, 29791, 32768, - 1089, 1156, 1225, 1296}; - static twodigits convwidth_base[37] = {0, 0, 15, 9, 7, 6, 5, 5, 5, + static const double log_base_BASE[37] = {0.0, 0.0, + 0.06666666666666667, 0.10566416671474375, 0.13333333333333333, + 0.15479520632582416, 0.17233083338141042, 0.18715699480384027, + 0.19999999999999998, 0.2113283334294875, 0.22146187299249084, + 0.23062877457581984, 0.2389975000480771, 0.24669598120940617, + 0.25382366147050694, 0.26045937304056793, 0.26666666666666666, + 0.27249752275002265, 0.27799500009615413, 0.2831951675629057, + 0.28812853965915747, 0.29282116151858406, 0.2972954412424865, + 0.3015707970704675, 0.3056641667147438, 0.30959041265164833, + 0.3133626478760728, 0.31699250014423125, 0.3204903281371736, + 0.3238653996751715, 0.3271260397072346, 0.3302797540257917, + 0.33333333333333337, 0.3362929412905636, 0.3391641894166893, + 0.34195220112966446, 0.34466166676282084}; + static const int convwidth_base[37] = {0, 0, 15, 9, 7, 6, 5, 5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2}; + static const twodigits convmultmax_base[37] = {0, 0, 32768, 19683, + 16384, 15625, 7776, 16807, 32768, 6561, 10000, 14641, 20736, + 28561, 2744, 3375, 4096, 4913, 5832, 6859, 8000, 9261, 10648, + 12167, 13824, 15625, 17576, 19683, 21952, 24389, 27000, 29791, + 32768, 1089, 1156, 1225, 1296}; #elif PYLONG_BITS_IN_DIGIT == 30 - static double log_base_BASE[37] = {0.0, 0.0, 0.03333333333333333, - 0.05283208335737188, 0.06666666666666667, 0.07739760316291208, - 0.08616541669070521, 0.09357849740192013, 0.09999999999999999, - 0.10566416671474375, 0.11073093649624542, 0.11531438728790992, - 0.11949875002403855, 0.12334799060470308, 0.12691183073525347, - 0.13022968652028397, 0.13333333333333333, 0.13624876137501132, - 0.13899750004807707, 0.14159758378145285, 0.14406426982957873, - 0.14641058075929203, 0.14864772062124326, 0.15078539853523376, - 0.1528320833573719, 0.15479520632582416, 0.1566813239380364, - 0.15849625007211562, 0.1602451640685868, 0.16193269983758574, - 0.1635630198536173, 0.16513987701289584, 0.16666666666666669, - 0.1681464706452818, 0.16958209470834465, 0.17097610056483223, - 0.17233083338141042}; - static int convmultmax_base[37] = {0, 0, 1073741824, 387420489, - 1073741824, 244140625, 362797056, 282475249, 1073741824, - 387420489, 1000000000, 214358881, 429981696, 815730721, - 105413504, 170859375, 268435456, 410338673, 612220032, - 893871739, 64000000, 85766121, 113379904, 148035889, - 191102976, 244140625, 308915776, 387420489, 481890304, - 594823321, 729000000, 887503681, 1073741824, 39135393, - 45435424, 52521875, 60466176}; - static twodigits convwidth_base[37] = {0, 0, 30, 18, 15, 12, 11, + static const double log_base_BASE[37] = {0.0, 0.0, + 0.03333333333333333, 0.05283208335737188, 0.06666666666666667, + 0.07739760316291208, 0.08616541669070521, 0.09357849740192013, + 0.09999999999999999, 0.10566416671474375, 0.11073093649624542, + 0.11531438728790992, 0.11949875002403855, 0.12334799060470308, + 0.12691183073525347, 0.13022968652028397, 0.13333333333333333, + 0.13624876137501132, 0.13899750004807707, 0.14159758378145285, + 0.14406426982957873, 0.14641058075929203, 0.14864772062124326, + 0.15078539853523376, 0.1528320833573719, 0.15479520632582416, + 0.1566813239380364, 0.15849625007211562, 0.1602451640685868, + 0.16193269983758574, 0.1635630198536173, 0.16513987701289584, + 0.16666666666666669, 0.1681464706452818, 0.16958209470834465, + 0.17097610056483223, 0.17233083338141042}; + static const int convwidth_base[37] = {0, 0, 30, 18, 15, 12, 11, 10, 10, 9, 9, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5}; + static const twodigits convmultmax_base[37] = {0, 0, 1073741824, + 387420489, 1073741824, 244140625, 362797056, 282475249, + 1073741824, 387420489, 1000000000, 214358881, 429981696, + 815730721, 105413504, 170859375, 268435456, 410338673, + 612220032, 893871739, 64000000, 85766121, 113379904, + 148035889, 191102976, 244140625, 308915776, 387420489, + 481890304, 594823321, 729000000, 887503681, 1073741824, + 39135393, 45435424, 52521875, 60466176}; #else #error "invalid PYLONG_BITS_IN_DIGIT value" #endif diff --git a/Tools/scripts/long_conv_tables.py b/Tools/scripts/long_conv_tables.py index 16ee79a8844086..f5907205974c20 100644 --- a/Tools/scripts/long_conv_tables.py +++ b/Tools/scripts/long_conv_tables.py @@ -41,11 +41,11 @@ def conv_tables(long_bits): # print('steps', steps) return '\n'.join( [ - format_array('static double log_base_BASE[37]', log_base_BASE), - format_array('static int convmultmax_base[37]', convmultmax_base), + format_array('static const double log_base_BASE[37]', log_base_BASE), format_array( - 'static twodigits convwidth_base[37]', convwidth_base + 'static const int convwidth_base[37]', convwidth_base ), + format_array('static const twodigits convmultmax_base[37]', convmultmax_base), ] ) From 3f9e1e7a3525e0b07ea13a3d288479d08096f120 Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Mon, 3 Mar 2025 15:23:22 -0800 Subject: [PATCH 7/8] Remove unused 'steps' variable. --- Tools/scripts/long_conv_tables.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/Tools/scripts/long_conv_tables.py b/Tools/scripts/long_conv_tables.py index f5907205974c20..7602377ee2794f 100644 --- a/Tools/scripts/long_conv_tables.py +++ b/Tools/scripts/long_conv_tables.py @@ -19,7 +19,6 @@ def format_array(name, values): def conv_tables(long_bits): - steps = 0 PyLong_BASE = 1 << long_bits log_base_BASE = [0.0] * 37 convmultmax_base = [0] * 37 @@ -29,7 +28,6 @@ def conv_tables(long_bits): i = 1 log_base_BASE[base] = math.log(float(base)) / math.log(PyLong_BASE) while True: - steps += 1 next = convmax * base if next > PyLong_BASE: break @@ -38,7 +36,6 @@ def conv_tables(long_bits): convmultmax_base[base] = convmax assert i > 0 convwidth_base[base] = i - # print('steps', steps) return '\n'.join( [ format_array('static const double log_base_BASE[37]', log_base_BASE), From f4388ba2deac2f6b04c71a9f9f2f57ed477775ba Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Mon, 3 Mar 2025 17:48:09 -0800 Subject: [PATCH 8/8] Don't compute unneeded constants. This makes the pre-computed tables match exactly what was previously computed at runtime, if all base conversions were used. This makes them slightly smaller too. --- Objects/longobject.c | 87 +++++++++++++++---------------- Tools/scripts/long_conv_tables.py | 17 ++++-- 2 files changed, 56 insertions(+), 48 deletions(-) diff --git a/Objects/longobject.c b/Objects/longobject.c index f2872760d23ea0..ab5cfab74d8a34 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -2823,51 +2823,50 @@ digit beyond the first. // Tables are computed by Tools/scripts/long_conv_tables.py #if PYLONG_BITS_IN_DIGIT == 15 - static const double log_base_BASE[37] = {0.0, 0.0, - 0.06666666666666667, 0.10566416671474375, 0.13333333333333333, - 0.15479520632582416, 0.17233083338141042, 0.18715699480384027, - 0.19999999999999998, 0.2113283334294875, 0.22146187299249084, - 0.23062877457581984, 0.2389975000480771, 0.24669598120940617, - 0.25382366147050694, 0.26045937304056793, 0.26666666666666666, - 0.27249752275002265, 0.27799500009615413, 0.2831951675629057, - 0.28812853965915747, 0.29282116151858406, 0.2972954412424865, - 0.3015707970704675, 0.3056641667147438, 0.30959041265164833, - 0.3133626478760728, 0.31699250014423125, 0.3204903281371736, - 0.3238653996751715, 0.3271260397072346, 0.3302797540257917, - 0.33333333333333337, 0.3362929412905636, 0.3391641894166893, - 0.34195220112966446, 0.34466166676282084}; - static const int convwidth_base[37] = {0, 0, 15, 9, 7, 6, 5, 5, 5, - 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 2, 2, 2, 2}; - static const twodigits convmultmax_base[37] = {0, 0, 32768, 19683, - 16384, 15625, 7776, 16807, 32768, 6561, 10000, 14641, 20736, - 28561, 2744, 3375, 4096, 4913, 5832, 6859, 8000, 9261, 10648, - 12167, 13824, 15625, 17576, 19683, 21952, 24389, 27000, 29791, - 32768, 1089, 1156, 1225, 1296}; + static const double log_base_BASE[37] = {0.0, 0.0, 0.0, + 0.10566416671474375, 0.0, 0.15479520632582416, + 0.17233083338141042, 0.18715699480384027, 0.0, + 0.2113283334294875, 0.22146187299249084, 0.23062877457581984, + 0.2389975000480771, 0.24669598120940617, 0.25382366147050694, + 0.26045937304056793, 0.0, 0.27249752275002265, + 0.27799500009615413, 0.2831951675629057, 0.28812853965915747, + 0.29282116151858406, 0.2972954412424865, 0.3015707970704675, + 0.3056641667147438, 0.30959041265164833, 0.3133626478760728, + 0.31699250014423125, 0.3204903281371736, 0.3238653996751715, + 0.3271260397072346, 0.3302797540257917, 0.0, + 0.3362929412905636, 0.3391641894166893, 0.34195220112966446, + 0.34466166676282084}; + static const int convwidth_base[37] = {0, 0, 0, 9, 0, 6, 5, 5, 0, + 4, 4, 4, 4, 4, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 0, 2, 2, 2, 2}; + static const twodigits convmultmax_base[37] = {0, 0, 0, 19683, 0, + 15625, 7776, 16807, 0, 6561, 10000, 14641, 20736, 28561, 2744, + 3375, 0, 4913, 5832, 6859, 8000, 9261, 10648, 12167, 13824, + 15625, 17576, 19683, 21952, 24389, 27000, 29791, 0, 1089, + 1156, 1225, 1296}; #elif PYLONG_BITS_IN_DIGIT == 30 - static const double log_base_BASE[37] = {0.0, 0.0, - 0.03333333333333333, 0.05283208335737188, 0.06666666666666667, - 0.07739760316291208, 0.08616541669070521, 0.09357849740192013, - 0.09999999999999999, 0.10566416671474375, 0.11073093649624542, - 0.11531438728790992, 0.11949875002403855, 0.12334799060470308, - 0.12691183073525347, 0.13022968652028397, 0.13333333333333333, - 0.13624876137501132, 0.13899750004807707, 0.14159758378145285, - 0.14406426982957873, 0.14641058075929203, 0.14864772062124326, - 0.15078539853523376, 0.1528320833573719, 0.15479520632582416, - 0.1566813239380364, 0.15849625007211562, 0.1602451640685868, - 0.16193269983758574, 0.1635630198536173, 0.16513987701289584, - 0.16666666666666669, 0.1681464706452818, 0.16958209470834465, - 0.17097610056483223, 0.17233083338141042}; - static const int convwidth_base[37] = {0, 0, 30, 18, 15, 12, 11, - 10, 10, 9, 9, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 5, 5, 5, 5}; - static const twodigits convmultmax_base[37] = {0, 0, 1073741824, - 387420489, 1073741824, 244140625, 362797056, 282475249, - 1073741824, 387420489, 1000000000, 214358881, 429981696, - 815730721, 105413504, 170859375, 268435456, 410338673, - 612220032, 893871739, 64000000, 85766121, 113379904, - 148035889, 191102976, 244140625, 308915776, 387420489, - 481890304, 594823321, 729000000, 887503681, 1073741824, + static const double log_base_BASE[37] = {0.0, 0.0, 0.0, + 0.05283208335737188, 0.0, 0.07739760316291208, + 0.08616541669070521, 0.09357849740192013, 0.0, + 0.10566416671474375, 0.11073093649624542, 0.11531438728790992, + 0.11949875002403855, 0.12334799060470308, 0.12691183073525347, + 0.13022968652028397, 0.0, 0.13624876137501132, + 0.13899750004807707, 0.14159758378145285, 0.14406426982957873, + 0.14641058075929203, 0.14864772062124326, 0.15078539853523376, + 0.1528320833573719, 0.15479520632582416, 0.1566813239380364, + 0.15849625007211562, 0.1602451640685868, 0.16193269983758574, + 0.1635630198536173, 0.16513987701289584, 0.0, + 0.1681464706452818, 0.16958209470834465, 0.17097610056483223, + 0.17233083338141042}; + static const int convwidth_base[37] = {0, 0, 0, 18, 0, 12, 11, 10, + 0, 9, 9, 8, 8, 8, 7, 7, 0, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 0, 5, 5, 5, 5}; + static const twodigits convmultmax_base[37] = {0, 0, 0, 387420489, + 0, 244140625, 362797056, 282475249, 0, 387420489, 1000000000, + 214358881, 429981696, 815730721, 105413504, 170859375, 0, + 410338673, 612220032, 893871739, 64000000, 85766121, + 113379904, 148035889, 191102976, 244140625, 308915776, + 387420489, 481890304, 594823321, 729000000, 887503681, 0, 39135393, 45435424, 52521875, 60466176}; #else #error "invalid PYLONG_BITS_IN_DIGIT value" diff --git a/Tools/scripts/long_conv_tables.py b/Tools/scripts/long_conv_tables.py index 7602377ee2794f..998a1e0d9b2251 100644 --- a/Tools/scripts/long_conv_tables.py +++ b/Tools/scripts/long_conv_tables.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 # -# Compute tables for longobject.c integer conversion. +# Compute tables for longobject.c long_from_non_binary_base(). They are used +# for conversions of strings to integers with a non-binary base. import math import textwrap @@ -24,9 +25,12 @@ def conv_tables(long_bits): convmultmax_base = [0] * 37 convwidth_base = [0] * 37 for base in range(2, 37): + is_binary_base = (base & (base - 1)) == 0 + if is_binary_base: + continue # don't need, leave as zero convmax = base i = 1 - log_base_BASE[base] = math.log(float(base)) / math.log(PyLong_BASE) + log_base_BASE[base] = math.log(base) / math.log(PyLong_BASE) while True: next = convmax * base if next > PyLong_BASE: @@ -38,11 +42,16 @@ def conv_tables(long_bits): convwidth_base[base] = i return '\n'.join( [ - format_array('static const double log_base_BASE[37]', log_base_BASE), + format_array( + 'static const double log_base_BASE[37]', log_base_BASE + ), format_array( 'static const int convwidth_base[37]', convwidth_base ), - format_array('static const twodigits convmultmax_base[37]', convmultmax_base), + format_array( + 'static const twodigits convmultmax_base[37]', + convmultmax_base, + ), ] )