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

Skip to content

BUG: floor timedelta64 // int for negative values - #32526

Open
ShamikOfficial wants to merge 3 commits into
numpy:mainfrom
ShamikOfficial:fix-timedelta-floor-div
Open

BUG: floor timedelta64 // int for negative values#32526
ShamikOfficial wants to merge 3 commits into
numpy:mainfrom
ShamikOfficial:fix-timedelta-floor-div

Conversation

@ShamikOfficial

Copy link
Copy Markdown

PR summary

timedelta64 // int was wired to the same loop as true division (TIMEDELTA_mq_m_divide), which uses C truncating /. For negative values that means rounding toward zero, while int64 // int, timedelta64 // timedelta64, and Python datetime.timedelta // int all floor.

This adds a real TIMEDELTA_mq_m_floor_divide loop (including the existing SIMD floor path with NaT propagation for the mQ->m result) and stops aliasing floor_divide mq to divide. True division timedelta64 / int is 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 mq floor_divide alias in generate_umath.py / loops_arithmetic_timedelta.dispatch.cpp, draft the TIMEDELTA_mq_m_floor_divide implementation 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.

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]>
[TypeDescription('m', FullTypeDescr, 'mq', 'm', cfunc_alias='divide',
[TypeDescription('m', FullTypeDescr, 'mq', 'm',
dispatch='loops_arithmetic_timedelta'),
TypeDescription('m', FullTypeDescr, 'md', 'm'),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread numpy/_core/src/umath/loops_arithmetic_timedelta.dispatch.cpp
Comment thread numpy/_core/src/umath/loops_arithmetic_timedelta.dispatch.cpp
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]>
@ShamikOfficial

Copy link
Copy Markdown
Author

Thanks for the review. Latest commit:

  • Shared m // q and m // m floor division in one helper to remove the duplicated loops
  • Added array // array coverage for the mq path
  • Left timedelta64 // float for a follow-up, as suggested

@ganesh-k13 ganesh-k13 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is CPP, we can use inline. See:

/* `NPY_INLINE` kept for backwards compatibility; use `inline` instead */

}
}
else if (in2 == 0) {
npy_set_floatstatus_divbyzero();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: incorrect floored division of negative timedeltas

3 participants