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

Skip to content

Conversation

@unnecessary-username
Copy link
Contributor

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?

@matusvalo matusvalo added this to the 3.1 milestone Mar 14, 2024
@da-woods
Copy link
Contributor

Do I need to append the div() function as the C API equivalent in the docs/src/userguide/language_basics.rst file?

I don't think so - This is just a fairly invisible optimization

@matusvalo
Copy link
Contributor

matusvalo commented Mar 14, 2024

Maybe improvement for another PR but is it possible to avoid creating tuple when user stores result in ctuple?

cdef (int, int) bar = divmod(...)

@da-woods
Copy link
Contributor

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

Copy link
Contributor

@da-woods da-woods left a 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.
@unnecessary-username
Copy link
Contributor Author

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.
So I still need to call the PyNumber_Divmod() function for these situations. Switch the optimise function to unsigned int would overflow for the C div() function.
As for the cdef (int, int) bar = divmod(...) approach, I cannot come up with such solution within my current knowledge.

@scoder
Copy link
Contributor

scoder commented Mar 15, 2024

Yeah, there's dedicated integer division/modulus code for this:
https://github.com/cython/cython/blob/master/Cython/Utility/CMath.c#L43
I think you can do this here as well. Just leave a comment where it came from.

Also, you need to handle the division by zero case.
https://github.com/cython/cython/blob/master/Cython/Utility/Optimize.c#L1190

Copy link
Contributor

@scoder scoder left a 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) {
Copy link
Contributor

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).

Copy link
Contributor Author

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.

Copy link
Contributor

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.

Comment on lines +163 to +165
BuiltinFunction('divmod', "ii", "O", "__Pyx_divmod_int",
utility_code=UtilityCode.load("divmod_int", "Builtins.c"),
is_strict_signature = True),
Copy link
Contributor

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) {
Copy link
Contributor

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.

Comment on lines +66 to +67
>>> divmod_int_regular(0,-987654321)
(0, 0)
Copy link
Contributor

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.

Copy link
Contributor Author

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.

@da-woods
Copy link
Contributor

da-woods commented May 5, 2024

I think this has been reviewed fairly thoroughly so let's merge it. Thanks @unnecessary-username

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants