| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
|
@pitrou had a link to portable safe overflow checks: portable-snippets |
|
I’ve been trying to get @lpereira interested. |
|
Any progress on this? |
|
@lpereira did you push a branch to https://github.com/faster-cpython/cpython? |
|
just as a comment, this is essentially how pypy does it. two representations of int, one storing a machine word with the value, one being a pointer to a list of digits. we have it a bit simpler in that we can hide the tag bit to distinguish the two cases in the header. there's a secondary benefit for algorithms that really operate on big integers. even in such programs, operations that mix a huge int and a machine-word sized one are common, so we have specialized implementations for long+int, long*int, etc. |
|
We need a better plan for this. I don't think it realistic to expect to merge very large changes, and long lived branches are a pain to maintain. Once python/cpython#30496 is merged, we should consider a way to break this into manageable chunks. One possible plan is this:
typedef struct _ {
uintptr_t size_plus;
digit ob_digits[1];
} PyLongValue;
typedef struct _ {
HEADER;
PyLongValue value;
} PyLongObject;
bit 0: 1
bit 1: sign
bit 2+: size
size == size_plus >> 2, sign == (size_plus & 2) - 1, size_plus & 1 == 1.
typedef struct _ {
HEADER;
union {
intptr_t medium;
PyLongValue big;
}
} PyIntObject;
typedef struct _ {
uintptr_t size_plus;
digit ob_digits[3]; // Make sure we have space.
} PyLongValue3;
PyIntObject *int_add(PyIntObject *a, PyIntObject *b) {
if ((a->medium | b->medium) & 1) {
PyLongValue3 temp;
PyLongValue *la = as_long_value(a, &temp);
PyLongValue *lb = as_long_value(b, &temp);
return normalize(long_add(la, lb));
}
// do fast add...
}
|
| Back | FazBrowse Home | New Git URL |
Uh oh!
There was an error while loading. Please reload this page.
{{title}}
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
{{editor}}'s edit
{{editor}}'s edit
Uh oh!
There was an error while loading. Please reload this page.
This is a reboot of #42. Any comments mentioning range will be deleted!
This might be a useful precursor to #138 as we will need to implement distinct paths for small integers vs larger integers for #138 as well.
Currently, int is implemented as an array of digits, where a digit is (approx) half a machine word.
I would suggest changing this to:
typedef struct { OBJECT_HEADER; Py_ssize_t tagged_bits; } PyIntObject;typedef struct { PyIntObject header; digit digits[1]; } PyLongObject;Values that, if represented as PyLongObject, would have -2 <= size <= 2 would be represented as a PyIntObject with obj->tagged_value_or_size_and_sign = value << 2.
Other values would be represented as a PyLongObject as they are now, except that the size would be stored as (size<<1)+1.
Intrinsic functions for add-with-overflow will help with performance. GCC has those. Windows has them for unsigned values only (I don't know why).
Even without intrinsics, the overflow checks can be implemented in only a few instructions, so should still be faster than what we have now.