-
-
Notifications
You must be signed in to change notification settings - Fork 12.6k
ENH: Added libdivide for floor divide #17727
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
Changes from 3 commits
179038f
e89175b
565759b
d0c934c
b02399a
f0ddb7c
72dcc04
19835d2
3975a28
90e6cf5
969aa03
44a3a31
b3d70ef
931134b
6e2e281
90a84af
61c3d38
827bc38
0ce0ebd
c85c44a
0517f13
a769d6f
0e2116f
f93ca93
285d810
9825795
1f104fd
2fde590
8912ffd
a5e1235
ca4ba20
28aa883
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,7 @@ | |
| #include "ufunc_object.h" | ||
|
|
||
| #include <string.h> /* for memchr */ | ||
| #include <libdivide.h> | ||
|
ganesh-k13 marked this conversation as resolved.
Outdated
|
||
|
|
||
| /* | ||
| * cutoff blocksize for pairwise summation | ||
|
|
@@ -826,6 +827,7 @@ NPY_NO_EXPORT void | |
| * #TYPE = BYTE, SHORT, INT, LONG, LONGLONG# | ||
| * #type = npy_byte, npy_short, npy_int, npy_long, npy_longlong# | ||
| * #c = ,,,l,ll# | ||
| * #div = s32, s32, s32, s64, s64# | ||
|
ganesh-k13 marked this conversation as resolved.
Outdated
|
||
| */ | ||
|
|
||
| NPY_NO_EXPORT NPY_GCC_OPT_3 void | ||
|
|
@@ -840,6 +842,115 @@ NPY_NO_EXPORT NPY_GCC_OPT_3 void | |
| UNARY_LOOP_FAST(@type@, @type@, *out = in > 0 ? 1 : (in < 0 ? -1 : 0)); | ||
| } | ||
|
|
||
| #ifdef USE_LIBDIVIDE | ||
| NPY_NO_EXPORT void | ||
| @TYPE@_divide(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) | ||
| { | ||
| BINARY_LOOP_BASE | ||
|
|
||
| if(!is2) { | ||
| const @type@ in2 = *(@type@ *)ip2; | ||
| struct libdivide_@div@_t fast_d = libdivide_@div@_gen(in2); | ||
| BINARY_LOOP_FIXED { | ||
| const @type@ in1 = *(@type@ *)ip1; | ||
| /* | ||
| * FIXME: On x86 at least, dividing the smallest representable integer | ||
| * by -1 causes a SIFGPE (division overflow). We treat this case here | ||
| * (to avoid a SIGFPE crash at python level), but a good solution would | ||
| * be to treat integer division problems separately from FPU exceptions | ||
| * (i.e. a different approach than npy_set_floatstatus_divbyzero()). | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, true, and on our agenda, but currently not something we can do. Happy to keep the comment though, even if the second part applies much more generally. |
||
| */ | ||
| if (in2 == 0 || (in1 == NPY_MIN_@TYPE@ && in2 == -1)) { | ||
|
ganesh-k13 marked this conversation as resolved.
Outdated
|
||
| npy_set_floatstatus_divbyzero(); | ||
|
seberg marked this conversation as resolved.
Outdated
|
||
| *((@type@ *)op1) = 0; | ||
| } | ||
| else if (((in1 > 0) != (in2 > 0)) && (in1 % in2 != 0)) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I honestly think we can avoid this
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So I still don't know how removing the
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, interesting. @ganesh-k13 two things: First make sure you are dividing a positive by a negative number (or vice versa), otherwise this is not hit at all. Second, was the timing difference with libdivide? I guess it might be the compiler is smart enough to optimize the modulo away, but I would be surprised if it is smart enough when libdivide is being used?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They seem to have not done it yet: ridiculousfish/libdivide#9
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All this changes is subtract one for rounding purproses, Now unless there is some edge case again, I think you can just do without the subtract, and then move the if to later, so that
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You were right about not hitting the case, @seberg , seems like in the profile script I forgot to invert the signs. Above method seems to work, few edge cases to iron out(like <= 0, etc), will try them.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I found three edge cases:
Let me know if any more are there. |
||
| *((@type@ *)op1) = libdivide_@div@_do(in1, &fast_d) - 1; | ||
| } | ||
| else { | ||
| *((@type@ *)op1) = libdivide_@div@_do(in1, &fast_d); | ||
| } | ||
| } | ||
| } | ||
| else { | ||
| BINARY_LOOP_SLIDING { // XXX Lot of repeated code | ||
|
ganesh-k13 marked this conversation as resolved.
Outdated
|
||
| const @type@ in1 = *(@type@ *)ip1; | ||
| const @type@ in2 = *(@type@ *)ip2; | ||
| /* | ||
| * FIXME: On x86 at least, dividing the smallest representable integer | ||
| * by -1 causes a SIFGPE (division overflow). We treat this case here | ||
| * (to avoid a SIGFPE crash at python level), but a good solution would | ||
| * be to treat integer division problems separately from FPU exceptions | ||
| * (i.e. a different approach than npy_set_floatstatus_divbyzero()). | ||
| */ | ||
| if (in2 == 0 || (in1 == NPY_MIN_@TYPE@ && in2 == -1)) { | ||
| npy_set_floatstatus_divbyzero(); | ||
| *((@type@ *)op1) = 0; | ||
| } | ||
| else if (((in1 > 0) != (in2 > 0)) && (in1 % in2 != 0)) { | ||
| *((@type@ *)op1) = in1/in2 - 1; | ||
| } | ||
| else { | ||
| *((@type@ *)op1) = in1/in2; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| #elif defined(USE_OPTIMAL_DIVISOR) | ||
| NPY_NO_EXPORT void | ||
| @TYPE@_divide(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) | ||
| { | ||
| BINARY_LOOP_BASE | ||
|
|
||
| if(!is2) { | ||
| const @type@ in2 = *(@type@ *)ip2; | ||
| const float in2_f = (float) in2; | ||
|
seberg marked this conversation as resolved.
Outdated
|
||
| BINARY_LOOP_FIXED { | ||
| const @type@ in1 = *(@type@ *)ip1; | ||
| /* | ||
| * FIXME: On x86 at least, dividing the smallest representable integer | ||
| * by -1 causes a SIFGPE (division overflow). We treat this case here | ||
| * (to avoid a SIGFPE crash at python level), but a good solution would | ||
| * be to treat integer division problems separately from FPU exceptions | ||
| * (i.e. a different approach than npy_set_floatstatus_divbyzero()). | ||
| */ | ||
| if (in2 == 0 || (in1 == NPY_MIN_@TYPE@ && in2 == -1)) { | ||
| npy_set_floatstatus_divbyzero(); | ||
| *((@type@ *)op1) = 0; | ||
| } | ||
| else if ((in1 > 0) != (in2 > 0)) { | ||
| *((@type@ *)op1) = floor(in1/in2_f); | ||
| } | ||
| else { | ||
| *((@type@ *)op1) = in1/in2; | ||
| } | ||
| } | ||
| } | ||
| else { | ||
| BINARY_LOOP_SLIDING { // XXX Lot of repeated code | ||
| const @type@ in1 = *(@type@ *)ip1; | ||
| const @type@ in2 = *(@type@ *)ip2; | ||
| /* | ||
| * FIXME: On x86 at least, dividing the smallest representable integer | ||
| * by -1 causes a SIFGPE (division overflow). We treat this case here | ||
| * (to avoid a SIGFPE crash at python level), but a good solution would | ||
| * be to treat integer division problems separately from FPU exceptions | ||
| * (i.e. a different approach than npy_set_floatstatus_divbyzero()). | ||
| */ | ||
| if (in2 == 0 || (in1 == NPY_MIN_@TYPE@ && in2 == -1)) { | ||
| npy_set_floatstatus_divbyzero(); | ||
| *((@type@ *)op1) = 0; | ||
| } | ||
| else if (((in1 > 0) != (in2 > 0)) && (in1 % in2 != 0)) { | ||
|
ganesh-k13 marked this conversation as resolved.
Outdated
|
||
| *((@type@ *)op1) = in1/in2 - 1; | ||
| } | ||
| else { | ||
| *((@type@ *)op1) = in1/in2; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| #else | ||
| NPY_NO_EXPORT void | ||
| @TYPE@_divide(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) | ||
| { | ||
|
|
@@ -865,6 +976,7 @@ NPY_NO_EXPORT void | |
| } | ||
| } | ||
| } | ||
| #endif | ||
|
|
||
| NPY_NO_EXPORT void | ||
| @TYPE@_remainder(char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(func)) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.