BUG: floor timedelta64 // int for negative values - #32526
Conversation
timedelta64 // int used C truncated division via an alias to TIMEDELTA_mq_m_divide, so negative values rounded toward zero. Add TIMEDELTA_mq_m_floor_divide so // matches int64 and m8 // m8. Closes numpy#32522 Co-authored-by: Cursor <[email protected]>
Co-authored-by: Cursor <[email protected]>
| [TypeDescription('m', FullTypeDescr, 'mq', 'm', cfunc_alias='divide', | ||
| [TypeDescription('m', FullTypeDescr, 'mq', 'm', | ||
| dispatch='loops_arithmetic_timedelta'), | ||
| TypeDescription('m', FullTypeDescr, 'md', 'm'), |
There was a problem hiding this comment.
timedelta64 // float (md→m) has the same floor bug and isn't covered here: np.timedelta64(-7,"us") // 2.0 returns -3 instead of -4.
I'm happy to track it as a follow up as well.
There was a problem hiding this comment.
Agreed that timedelta64 // float has the same truncation issue. I left it out of this PR on purpose because the md path goes through double and then casts, so a correct floor there needs a bit more care around non-finite values and large magnitudes. Happy to take that as a follow-up.
Fold m//q and m//m floor division into one helper to cut duplicated loops, and add non-scalar divisor tests for the mq path. Co-authored-by: Cursor <[email protected]>
|
Thanks for the review. Latest commit:
|
ganesh-k13
left a comment
There was a problem hiding this comment.
Looks good overall! Just some minor comments
| * Floor quotient of two nonzero, non-NaT int64 values. | ||
| * Matches Python/NumPy integer floor division (round toward -inf). | ||
| */ | ||
| static NPY_INLINE npy_int64 |
There was a problem hiding this comment.
Since this is CPP, we can use inline. See:
| } | ||
| } | ||
| else if (in2 == 0) { | ||
| npy_set_floatstatus_divbyzero(); |
There was a problem hiding this comment.
mq floor with a non-scalar (array) zero divisor now raises divbyzero.
I see tests cover it, nice! But we might want to flag this behavior change in the release notes above.
PR summary
timedelta64 // intwas wired to the same loop as true division (TIMEDELTA_mq_m_divide), which uses C truncating/. For negative values that means rounding toward zero, whileint64 // int,timedelta64 // timedelta64, and Pythondatetime.timedelta // intall floor.This adds a real
TIMEDELTA_mq_m_floor_divideloop (including the existing SIMD floor path with NaT propagation for themQ->mresult) and stops aliasingfloor_dividemqtodivide. True divisiontimedelta64 / intis unchanged and still truncates.Closes #32522
First time committer introduction
I use NumPy in day to day Python work and was looking for a small, well scoped correctness bug to contribute. Issue #32522 is a clear ufunc contract mismatch with a focused fix path, so I worked through the timedelta division loops and tests there.
AI Disclosure
Cursor (Composer agent) was used to help locate the
mqfloor_divide alias ingenerate_umath.py/loops_arithmetic_timedelta.dispatch.cpp, draft theTIMEDELTA_mq_m_floor_divideimplementation and tests, build locally on Windows, and open this PR. I reviewed the change, checked it against the issue reproduction and related floor vs trunc cases, and am responsible for the submitted code and this description.