Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bd3a527

Browse files
committed
Two patches by Jason Harper:
- Faster conversion to string for binary bases: linear instead of quadratic! - Allocate smaller result for certain masking ops, e.g. (1L<<30000) & 1.
1 parent 9279ec2 commit bd3a527

1 file changed

Lines changed: 96 additions & 37 deletions

File tree

Objects/longobject.c

Lines changed: 96 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -315,9 +315,11 @@ PyLong_FromLongLong(ival)
315315
#else
316316
if( ival <= (long long)LONG_MAX ) {
317317
return PyLong_FromLong( (long)ival );
318-
} else if( ival <= (unsigned long long)ULONG_MAX ) {
318+
}
319+
else if( ival <= (unsigned long long)ULONG_MAX ) {
319320
return PyLong_FromUnsignedLong( (unsigned long)ival );
320-
} else {
321+
}
322+
else {
321323
/* Assume a C long long fits in at most 10 'digits'.
322324
* Should be OK if we're assuming long fits in 5.
323325
*/
@@ -359,7 +361,8 @@ PyLong_FromUnsignedLongLong(ival)
359361
#else
360362
if( ival <= (unsigned long long)ULONG_MAX ) {
361363
return PyLong_FromUnsignedLong( (unsigned long)ival );
362-
} else {
364+
}
365+
else {
363366
/* Assume a C long fits in at most 10 'digits'. */
364367
PyLongObject *v = _PyLong_New(10);
365368

@@ -572,30 +575,71 @@ long_format(aa, base)
572575
if (a->ob_size < 0)
573576
sign = '-';
574577

575-
Py_INCREF(a);
576-
do {
577-
digit rem;
578-
PyLongObject *temp = divrem1(a, (digit)base, &rem);
579-
if (temp == NULL) {
580-
Py_DECREF(a);
581-
Py_DECREF(str);
582-
return NULL;
578+
if (a->ob_size == 0) {
579+
*--p = '0';
580+
}
581+
else if ((base & (base - 1)) == 0) {
582+
/* JRH: special case for power-of-2 bases */
583+
twodigits temp = a->ob_digit[0];
584+
int bitsleft = SHIFT;
585+
int rem;
586+
int last = abs(a->ob_size);
587+
int basebits = 1;
588+
i = base;
589+
while ((i >>= 1) > 1) ++basebits;
590+
591+
i = 0;
592+
for (;;) {
593+
while (bitsleft >= basebits) {
594+
if ((temp == 0) && (i >= last - 1)) break;
595+
rem = temp & (base - 1);
596+
if (rem < 10)
597+
rem += '0';
598+
else
599+
rem += 'A' - 10;
600+
assert(p > PyString_AS_STRING(str));
601+
*--p = (char) rem;
602+
bitsleft -= basebits;
603+
temp >>= basebits;
604+
}
605+
if (++i >= last) {
606+
if (temp == 0) break;
607+
bitsleft = 99;
608+
/* loop again to pick up final digits */
609+
}
610+
else {
611+
temp = (a->ob_digit[i] << bitsleft) | temp;
612+
bitsleft += SHIFT;
613+
}
583614
}
584-
if (rem < 10)
585-
rem += '0';
586-
else
587-
rem += 'A'-10;
588-
assert(p > PyString_AS_STRING(str));
589-
*--p = (char) rem;
590-
Py_DECREF(a);
591-
a = temp;
592-
SIGCHECK({
615+
}
616+
else {
617+
Py_INCREF(a);
618+
do {
619+
digit rem;
620+
PyLongObject *temp = divrem1(a, (digit)base, &rem);
621+
if (temp == NULL) {
622+
Py_DECREF(a);
623+
Py_DECREF(str);
624+
return NULL;
625+
}
626+
if (rem < 10)
627+
rem += '0';
628+
else
629+
rem += 'A'-10;
630+
assert(p > PyString_AS_STRING(str));
631+
*--p = (char) rem;
593632
Py_DECREF(a);
594-
Py_DECREF(str);
595-
return NULL;
596-
})
597-
} while (ABS(a->ob_size) != 0);
598-
Py_DECREF(a);
633+
a = temp;
634+
SIGCHECK({
635+
Py_DECREF(a);
636+
Py_DECREF(str);
637+
return NULL;
638+
})
639+
} while (ABS(a->ob_size) != 0);
640+
Py_DECREF(a);
641+
}
642+
599643
if (base == 8) {
600644
if (size_a != 0)
601645
*--p = '0';
@@ -723,7 +767,8 @@ long_divrem(a, b, pdiv, prem)
723767
PyLongObject *z;
724768

725769
if (size_b == 0) {
726-
PyErr_SetString(PyExc_ZeroDivisionError, "long division or modulo");
770+
PyErr_SetString(PyExc_ZeroDivisionError,
771+
"long division or modulo");
727772
return -1;
728773
}
729774
if (size_a < size_b ||
@@ -1520,17 +1565,6 @@ long_bitwise(a, op, b)
15201565
maskb = 0;
15211566
}
15221567

1523-
size_a = a->ob_size;
1524-
size_b = b->ob_size;
1525-
size_z = MAX(size_a, size_b);
1526-
z = _PyLong_New(size_z);
1527-
if (a == NULL || b == NULL || z == NULL) {
1528-
Py_XDECREF(a);
1529-
Py_XDECREF(b);
1530-
Py_XDECREF(z);
1531-
return NULL;
1532-
}
1533-
15341568
negz = 0;
15351569
switch (op) {
15361570
case '^':
@@ -1557,6 +1591,31 @@ long_bitwise(a, op, b)
15571591
break;
15581592
}
15591593

1594+
/* JRH: The original logic here was to allocate the result value (z)
1595+
as the longer of the two operands. However, there are some cases
1596+
where the result is guaranteed to be shorter than that: AND of two
1597+
positives, OR of two negatives: use the shorter number. AND with
1598+
mixed signs: use the positive number. OR with mixed signs: use the
1599+
negative number. After the transformations above, op will be '&'
1600+
iff one of these cases applies, and mask will be non-0 for operands
1601+
whose length should be ignored.
1602+
*/
1603+
1604+
size_a = a->ob_size;
1605+
size_b = b->ob_size;
1606+
size_z = op == '&'
1607+
? (maska
1608+
? size_b
1609+
: (maskb ? size_a : MIN(size_a, size_b)))
1610+
: MAX(size_a, size_b);
1611+
z = _PyLong_New(size_z);
1612+
if (a == NULL || b == NULL || z == NULL) {
1613+
Py_XDECREF(a);
1614+
Py_XDECREF(b);
1615+
Py_XDECREF(z);
1616+
return NULL;
1617+
}
1618+
15601619
for (i = 0; i < size_z; ++i) {
15611620
diga = (i < size_a ? a->ob_digit[i] : 0) ^ maska;
15621621
digb = (i < size_b ? b->ob_digit[i] : 0) ^ maskb;

0 commit comments

Comments
 (0)