-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Accelerate divmod() in Cython by calling C div() for C int type integers #6073
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
I don't think so - This is just a fairly invisible optimization |
|
Maybe improvement for another PR but is it possible to avoid creating tuple when user stores result in ctuple? cdef (int, int) bar = divmod(...) |
I think this was suggested in #3780, but would probably be quite hard to do I think. I'd probably leave it for another PR |
da-woods
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we also want to make sure that this is tested at least once.
tests/run/builtin_abs.pyx is where the builtin abs function is tested, so you could do something very similar here.
…s and remainders when the dividend is negative and the divisor is positive and vice versa.
|
Realised that Python and C/C++ use different algorithm in calculating quotients and remainders. This results in different answers between Python and C/C++ when the dividend is negative and the divisor is positive and vice versa. |
|
Yeah, there's dedicated integer division/modulus code for this: Also, you need to handle the division by zero case. |
scoder
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm actually not sure if Builtin.py is the best place for this optimisation. It might be more effective in the builtins transformation in Optimise.py, where we have more control over the syntax tree that we build. It would allow us to call existing utility functions, split the two operations if we find that the user code unpacks the results into separate variables, thing like that.
|
|
||
| //////////////////// divmod_int.proto ////////////////// | ||
|
|
||
| static CYTHON_INLINE PyObject* __Pyx_divmod_int(int a, int b) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why int and not long?
You can also define multiple variants using the different C types and corresponding functions:
https://en.cppreference.com/w/c/numeric/math/div
See the abs() implementation in this file (Builtins.py).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As stated in the top, I was planning like if expanding to C div() function is accepted, I could subsequently open another PR for C long type integers by calling (pure) C ldiv() function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine with me. You can then probably use simple code generation for the three different C integer types to avoid duplicating the implementation.
| BuiltinFunction('divmod', "ii", "O", "__Pyx_divmod_int", | ||
| utility_code=UtilityCode.load("divmod_int", "Builtins.c"), | ||
| is_strict_signature = True), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should really return a ctuple (int, int) instead of a Python tuple. Can't say how difficult that would be to set up and implement. ctuples are implemented as C structs, so you need a struct type declaration. See the abs implementations for a way to declare the exact function type, including its return type.
Not necessarily something for this PR. It would also make the exception handling difficult.
|
|
||
| //////////////////// divmod_int.proto ////////////////// | ||
|
|
||
| static CYTHON_INLINE PyObject* __Pyx_divmod_int(int a, int b) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine with me. You can then probably use simple code generation for the three different C integer types to avoid duplicating the implementation.
| >>> divmod_int_regular(0,-987654321) | ||
| (0, 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if we strictly require int to be 32 bit. We probably do it implicitly. It's usually best to start off with long these days, but given that the current divmod implementation was made for int, let's make this the first iteration and then extend it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @scoder for your commits. Originally I planned to implement for C long type in a new/separate PR. Let me know if you prefer me to just implement it in this PR.
|
I think this has been reviewed fairly thoroughly so let's merge it. Thanks @unnecessary-username |
Inspired by #3780, this is my first attempt accelerating divmod() in Cython by calling (pure) C div() function for C int type integers.
If this is expected, I could subsequently open another PR for C long type integers by calling (pure) C ldiv() function.
Do I need to append the div() function as the C API equivalent in the docs/src/userguide/language_basics.rst file?