From aecba4b2f64096cbc7bf32d1fa50f827877bb0f5 Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Mon, 25 Mar 2024 00:20:40 +0100 Subject: [PATCH 01/22] faster ifrac --- pandas/_libs/src/vendored/numpy/datetime/np_datetime.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index f854f7b9210d8..329331f59e598 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -761,6 +761,7 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, const int sign = frac < 0 ? -1 : 1; if (frac < 0) { + npy_int64 ifrac = td; // even fraction if ((-frac % sec_per_day) != 0) { out->days = -frac / sec_per_day + 1; @@ -794,11 +795,7 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, out->days = -out->days; if (base > NPY_FR_s) { - const npy_int64 sfrac = - (out->hrs * sec_per_hour + out->min * sec_per_min + out->sec) * - per_sec; - - npy_int64 ifrac = td - (out->days * per_day + sfrac); + ifrac = (ifrac - out->days * per_day) % per_sec; if (base == NPY_FR_ms) { out->ms = (npy_int32)ifrac; From 6f43de0263ed1ae9654cd8996ae4eb68408f2f9a Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Mon, 25 Mar 2024 00:22:02 +0100 Subject: [PATCH 02/22] remove unnecessary statement --- pandas/_libs/src/vendored/numpy/datetime/np_datetime.c | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index 329331f59e598..7262d4c6f4677 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -788,7 +788,6 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, if (frac >= 0) { out->sec = (npy_int32)frac; - frac -= out->sec; } if (sign < 0) From 47a0d9b36aa237be7094ab59a356b0a9cf6cf752 Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Mon, 25 Mar 2024 00:24:05 +0100 Subject: [PATCH 03/22] shorten days * per_day) % per_sec; if (base == NPY_FR_ms) { - out->ms = (npy_int32)ifrac; + out->ms = ifrac; } else if (base == NPY_FR_us) { out->ms = (npy_int32)(ifrac / 1000LL); ifrac = ifrac % 1000LL; out->us = (npy_int32)ifrac; + out->ms = (ifrac / 1000LL); + out->us = ifrac % 1000LL; } else if (base == NPY_FR_ns) { - out->ms = (npy_int32)(ifrac / (1000LL * 1000LL)); - ifrac = ifrac % (1000LL * 1000LL); - out->us = (npy_int32)(ifrac / 1000LL); - ifrac = ifrac % 1000LL; - out->ns = (npy_int32)ifrac; + out->ms = (ifrac / (1000LL * 1000LL)); + out->us = (ifrac / 1000LL); + out->nanoseconds = ifrac % 1000LL; } } + out->microseconds = out->ms * 1000 + out->us; } break; default: From 61c5caee073588fec9b0f1d5a3612fd1b90c8f99 Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Mon, 25 Mar 2024 00:24:40 +0100 Subject: [PATCH 04/22] remove assignments --- pandas/_libs/src/vendored/numpy/datetime/np_datetime.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index a050ea3c09aaa..c8ef857fc7140 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -799,9 +799,6 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, if (base == NPY_FR_ms) { out->ms = ifrac; } else if (base == NPY_FR_us) { - out->ms = (npy_int32)(ifrac / 1000LL); - ifrac = ifrac % 1000LL; - out->us = (npy_int32)ifrac; out->ms = (ifrac / 1000LL); out->us = ifrac % 1000LL; } else if (base == NPY_FR_ns) { From e4c64b271e0215251c4907bf7028cfe27aeb33d4 Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Mon, 25 Mar 2024 00:25:15 +0100 Subject: [PATCH 05/22] shorten frac assignments --- pandas/_libs/src/vendored/numpy/datetime/np_datetime.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index c8ef857fc7140..cd0e238707d78 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -778,12 +778,12 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, if (frac >= sec_per_hour) { out->hrs = (npy_int32)(frac / sec_per_hour); - frac -= out->hrs * sec_per_hour; + frac %= sec_per_hour; } if (frac >= sec_per_min) { out->min = (npy_int32)(frac / sec_per_min); - frac -= out->min * sec_per_min; + frac %= sec_per_min; } if (frac >= 0) { From fa3ff63789236e2e0618854c417b29d6cbf9f5a6 Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Mon, 25 Mar 2024 00:25:52 +0100 Subject: [PATCH 06/22] shorten days logic --- .../src/vendored/numpy/datetime/np_datetime.c | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index cd0e238707d78..aad129f056511 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -752,28 +752,25 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, } const npy_int64 per_day = sec_per_day * per_sec; - npy_int64 frac; - // put frac in seconds - if (td < 0 && td % per_sec != 0) - frac = td / per_sec - 1; - else - frac = td / per_sec; - - const int sign = frac < 0 ? -1 : 1; - if (frac < 0) { npy_int64 ifrac = td; + int sign = td >= 0 ? 1 : -1; + int has_seconds = td % per_sec != 0 ? 1 : 0; + frac = td / per_sec; + if (sign < 0) { + if (has_seconds == 1) { + frac -= 1; + } + frac *= -1; // even fraction - if ((-frac % sec_per_day) != 0) { - out->days = -frac / sec_per_day + 1; - frac += sec_per_day * out->days; - } else { - frac = -frac; + if ((frac % sec_per_day) != 0) { + out->days = -frac / sec_per_day - 1; + frac += per_sec * out->days; } } if (frac >= sec_per_day) { - out->days += frac / sec_per_day; - frac -= out->days * sec_per_day; + out->days += sign * frac / sec_per_day; + frac -= sign * out->days * sec_per_day; } if (frac >= sec_per_hour) { @@ -790,9 +787,6 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, out->sec = (npy_int32)frac; } - if (sign < 0) - out->days = -out->days; - if (base > NPY_FR_s) { ifrac = (ifrac - out->days * per_day) % per_sec; From 9d768d6987e2b0821eb69ee8cdf5f712d896dd08 Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Mon, 25 Mar 2024 00:26:54 +0100 Subject: [PATCH 07/22] remove unnecessary assignments --- pandas/_libs/src/vendored/numpy/datetime/np_datetime.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index aad129f056511..fb6534071efb3 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -813,8 +813,6 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, out->seconds = (npy_int32)(out->hrs * sec_per_hour + out->min * sec_per_min + out->sec); - out->microseconds = out->ms * 1000 + out->us; - out->nanoseconds = out->ns; } /* From c9f75b1b33411e5e8400e898e04797a89dce66ae Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Mon, 25 Mar 2024 00:29:16 +0100 Subject: [PATCH 08/22] reuse td --- .../src/vendored/numpy/datetime/np_datetime.c | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index fb6534071efb3..4328e0a2cd68a 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -755,36 +755,36 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, npy_int64 ifrac = td; int sign = td >= 0 ? 1 : -1; int has_seconds = td % per_sec != 0 ? 1 : 0; - frac = td / per_sec; + td = td / per_sec; if (sign < 0) { if (has_seconds == 1) { - frac -= 1; + td -= 1; } - frac *= -1; + td *= -1; // even fraction - if ((frac % sec_per_day) != 0) { - out->days = -frac / sec_per_day - 1; - frac += per_sec * out->days; + if ((td % sec_per_day) != 0) { + out->days = -td / sec_per_day - 1; + td += per_sec * out->days; } } - if (frac >= sec_per_day) { - out->days += sign * frac / sec_per_day; - frac -= sign * out->days * sec_per_day; + if (td >= sec_per_day) { + out->days += sign * td / sec_per_day; + td -= sign * out->days * sec_per_day; } - if (frac >= sec_per_hour) { - out->hrs = (npy_int32)(frac / sec_per_hour); - frac %= sec_per_hour; + if (td >= sec_per_hour) { + out->hrs = (npy_int32)(td / sec_per_hour); + td %= sec_per_hour; } - if (frac >= sec_per_min) { - out->min = (npy_int32)(frac / sec_per_min); - frac %= sec_per_min; + if (td >= sec_per_min) { + out->min = (npy_int32)(td / sec_per_min); + td %= sec_per_min; } - if (frac >= 0) { - out->sec = (npy_int32)frac; + if (td >= 0) { + out->sec = (npy_int32)td; } if (base > NPY_FR_s) { From aba6c3a777e28e2014435551fb4b73d6ac581633 Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Mon, 25 Mar 2024 02:15:46 +0100 Subject: [PATCH 09/22] fix regression for td close to int64 bounds --- .../src/vendored/numpy/datetime/np_datetime.c | 49 +++++++++++-------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index 4328e0a2cd68a..e943f8cafa376 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -753,55 +753,63 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, const npy_int64 per_day = sec_per_day * per_sec; npy_int64 ifrac = td; - int sign = td >= 0 ? 1 : -1; - int has_seconds = td % per_sec != 0 ? 1 : 0; - td = td / per_sec; - if (sign < 0) { - if (has_seconds == 1) { - td -= 1; - } - td *= -1; + const int sign = td < 0 ? -1 : 1; + // put frac in seconds + if (sign < 0 && td % per_sec != 0) + td = td / per_sec - 1; + else + td = td / per_sec; + + if (td < 0) { // even fraction - if ((td % sec_per_day) != 0) { - out->days = -td / sec_per_day - 1; - td += per_sec * out->days; + if ((-td % sec_per_day) != 0) { + out->days = -td / sec_per_day + 1; + td += sec_per_day * out->days; + } else { + td = -td; } } if (td >= sec_per_day) { - out->days += sign * td / sec_per_day; - td -= sign * out->days * sec_per_day; + out->days += td / sec_per_day; + td -= out->days * sec_per_day; } if (td >= sec_per_hour) { - out->hrs = (npy_int32)(td / sec_per_hour); + out->hrs = (td / sec_per_hour); td %= sec_per_hour; } if (td >= sec_per_min) { - out->min = (npy_int32)(td / sec_per_min); + out->min = td / sec_per_min; td %= sec_per_min; } if (td >= 0) { - out->sec = (npy_int32)td; + out->sec = td; } + if (sign < 0) + out->days = -out->days; + if (base > NPY_FR_s) { + // the days * per_day removes so many base units that ifrac is within + // int32 bounds ifrac = (ifrac - out->days * per_day) % per_sec; if (base == NPY_FR_ms) { out->ms = ifrac; } else if (base == NPY_FR_us) { - out->ms = (ifrac / 1000LL); + out->ms = ifrac / 1000LL; out->us = ifrac % 1000LL; } else if (base == NPY_FR_ns) { - out->ms = (ifrac / (1000LL * 1000LL)); - out->us = (ifrac / 1000LL); + out->ms = ifrac / (1000LL * 1000LL); + ifrac = ifrac % (1000LL * 1000LL); + out->us = ifrac / 1000LL; out->nanoseconds = ifrac % 1000LL; } + out->microseconds = out->ms * 1000 + out->us; } - out->microseconds = out->ms * 1000 + out->us; } break; default: @@ -810,7 +818,6 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, "invalid base unit"); break; } - out->seconds = (npy_int32)(out->hrs * sec_per_hour + out->min * sec_per_min + out->sec); } From e7c02e80007bc9e769abdcb516afcf6a8f499aee Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Mon, 25 Mar 2024 02:29:54 +0100 Subject: [PATCH 10/22] re-add unnecessary conversions --- .../src/vendored/numpy/datetime/np_datetime.c | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index e943f8cafa376..c4329fef1b59b 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -776,37 +776,35 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, } if (td >= sec_per_hour) { - out->hrs = (td / sec_per_hour); + out->hrs = (npy_int32)(td / sec_per_hour); td %= sec_per_hour; } if (td >= sec_per_min) { - out->min = td / sec_per_min; + out->min = (npy_int32)(td / sec_per_min); td %= sec_per_min; } if (td >= 0) { - out->sec = td; + out->sec = (npy_int32)td; } if (sign < 0) out->days = -out->days; if (base > NPY_FR_s) { - // the days * per_day removes so many base units that ifrac is within - // int32 bounds ifrac = (ifrac - out->days * per_day) % per_sec; if (base == NPY_FR_ms) { - out->ms = ifrac; + out->ms = (npy_int32)ifrac; } else if (base == NPY_FR_us) { - out->ms = ifrac / 1000LL; - out->us = ifrac % 1000LL; + out->ms = (npy_int32)(ifrac / 1000LL); + out->us = (npy_int32)(ifrac % 1000LL); } else if (base == NPY_FR_ns) { - out->ms = ifrac / (1000LL * 1000LL); + out->ms = (npy_int32)(ifrac / (1000LL * 1000LL)); ifrac = ifrac % (1000LL * 1000LL); - out->us = ifrac / 1000LL; - out->nanoseconds = ifrac % 1000LL; + out->us = (npy_int32)(ifrac / 1000LL); + out->nanoseconds = (npy_int32)(ifrac % 1000LL); } out->microseconds = out->ms * 1000 + out->us; } From b3c0199fd3af31cceb45278751d9be45d35d55ce Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Mon, 25 Mar 2024 22:12:17 +0100 Subject: [PATCH 11/22] remove sign if --- pandas/_libs/src/vendored/numpy/datetime/np_datetime.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index c4329fef1b59b..15985224898de 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -754,8 +754,9 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, const npy_int64 per_day = sec_per_day * per_sec; npy_int64 ifrac = td; const int sign = td < 0 ? -1 : 1; + const int uneven_in_seconds = td % per_sec != 0; // put frac in seconds - if (sign < 0 && td % per_sec != 0) + if (sign < 0 && uneven_in_seconds) td = td / per_sec - 1; else td = td / per_sec; @@ -775,6 +776,8 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, td -= out->days * sec_per_day; } + out->days = sign * (out->days); + if (td >= sec_per_hour) { out->hrs = (npy_int32)(td / sec_per_hour); td %= sec_per_hour; From 5a04d8dedd00815299dff81201111edb45cdf43c Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Mon, 25 Mar 2024 22:23:07 +0100 Subject: [PATCH 12/22] remove mod seconds if layer --- .../src/vendored/numpy/datetime/np_datetime.c | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index 15985224898de..751c8c6d386eb 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -754,21 +754,21 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, const npy_int64 per_day = sec_per_day * per_sec; npy_int64 ifrac = td; const int sign = td < 0 ? -1 : 1; - const int uneven_in_seconds = td % per_sec != 0; + const int uneven_in_seconds = td % per_sec != 0 ? 1 : 0; // put frac in seconds - if (sign < 0 && uneven_in_seconds) - td = td / per_sec - 1; - else - td = td / per_sec; - - if (td < 0) { - // even fraction - if ((-td % sec_per_day) != 0) { - out->days = -td / sec_per_day + 1; - td += sec_per_day * out->days; - } else { - td = -td; + if (sign < 0) { + td = td / per_sec - uneven_in_seconds; + if (td < 0) { + // even fraction + if ((-td % sec_per_day) != 0) { + out->days = -td / sec_per_day + 1; + td += sec_per_day * out->days; + } else { + td = -td; + } } + } else { + td = td / per_sec; } if (td >= sec_per_day) { From 39c77ab7cf3aea11864d15e7d7053f8d5f3ef03d Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Mon, 25 Mar 2024 22:24:44 +0100 Subject: [PATCH 13/22] remove second negative check if layer --- .../src/vendored/numpy/datetime/np_datetime.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index 751c8c6d386eb..660180f4a884e 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -758,14 +758,12 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, // put frac in seconds if (sign < 0) { td = td / per_sec - uneven_in_seconds; - if (td < 0) { - // even fraction - if ((-td % sec_per_day) != 0) { - out->days = -td / sec_per_day + 1; - td += sec_per_day * out->days; - } else { - td = -td; - } + // even fraction + if ((-td % sec_per_day) != 0) { + out->days = -td / sec_per_day + 1; + td += sec_per_day * out->days; + } else { + td = -td; } } else { td = td / per_sec; From 2227b1b4fe269e1fefde15dee37143ef0d73f026 Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Mon, 25 Mar 2024 22:28:52 +0100 Subject: [PATCH 14/22] duplicate larger than day check --- pandas/_libs/src/vendored/numpy/datetime/np_datetime.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index 660180f4a884e..b20ee10fb127f 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -765,8 +765,17 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, } else { td = -td; } + if (td >= sec_per_day) { + out->days += out->days + td / sec_per_day; + td -= out->days * sec_per_day; + } + out->days = -out->days; } else { td = td / per_sec; + if (td >= sec_per_day) { + out->days += out->days + td / sec_per_day; + td -= out->days * sec_per_day; + } } if (td >= sec_per_day) { From 0171a7c3a98ed1a884676c9af55e5f505bb1382f Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Mon, 25 Mar 2024 22:30:03 +0100 Subject: [PATCH 15/22] remove forgetten functions --- pandas/_libs/src/vendored/numpy/datetime/np_datetime.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index b20ee10fb127f..90e068b31ec0e 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -778,13 +778,6 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, } } - if (td >= sec_per_day) { - out->days += td / sec_per_day; - td -= out->days * sec_per_day; - } - - out->days = sign * (out->days); - if (td >= sec_per_hour) { out->hrs = (npy_int32)(td / sec_per_hour); td %= sec_per_hour; @@ -799,9 +792,6 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, out->sec = (npy_int32)td; } - if (sign < 0) - out->days = -out->days; - if (base > NPY_FR_s) { ifrac = (ifrac - out->days * per_day) % per_sec; From 1492bc91030ffd90a4871c3fcb02646918793348 Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Mon, 25 Mar 2024 22:35:13 +0100 Subject: [PATCH 16/22] make days assignment conditions explicit --- .../_libs/src/vendored/numpy/datetime/np_datetime.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index 90e068b31ec0e..022706b8f5f61 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -764,16 +764,17 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, td += sec_per_day * out->days; } else { td = -td; - } - if (td >= sec_per_day) { - out->days += out->days + td / sec_per_day; - td -= out->days * sec_per_day; + if (td >= sec_per_day) { + out->days = td / sec_per_day; + td -= out->days * sec_per_day; + } } out->days = -out->days; + } else { td = td / per_sec; if (td >= sec_per_day) { - out->days += out->days + td / sec_per_day; + out->days = td / sec_per_day; td -= out->days * sec_per_day; } } From 2e670c038dfa82fe64514d1a85fc8660f07346e5 Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Mon, 25 Mar 2024 22:38:57 +0100 Subject: [PATCH 17/22] directly flip out.days --- pandas/_libs/src/vendored/numpy/datetime/np_datetime.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index 022706b8f5f61..22a712d11e92e 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -760,16 +760,15 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, td = td / per_sec - uneven_in_seconds; // even fraction if ((-td % sec_per_day) != 0) { - out->days = -td / sec_per_day + 1; - td += sec_per_day * out->days; + out->days = td / sec_per_day - 1; + td -= sec_per_day * out->days; } else { td = -td; if (td >= sec_per_day) { - out->days = td / sec_per_day; - td -= out->days * sec_per_day; + out->days = -td / sec_per_day; + td += out->days * sec_per_day; } } - out->days = -out->days; } else { td = td / per_sec; From 03164421b6754de80263292583ffdc232e35eaae Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Mon, 25 Mar 2024 22:57:10 +0100 Subject: [PATCH 18/22] extract normalization to secs --- .../src/vendored/numpy/datetime/np_datetime.c | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index 22a712d11e92e..2a0cfc4c6bcaf 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -756,26 +756,26 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, const int sign = td < 0 ? -1 : 1; const int uneven_in_seconds = td % per_sec != 0 ? 1 : 0; // put frac in seconds + td = td / per_sec; if (sign < 0) { - td = td / per_sec - uneven_in_seconds; + td -= uneven_in_seconds; // even fraction if ((-td % sec_per_day) != 0) { + // days = td / sec_per_day - is_even_fraction out->days = td / sec_per_day - 1; td -= sec_per_day * out->days; } else { - td = -td; - if (td >= sec_per_day) { - out->days = -td / sec_per_day; + if (td <= sec_per_day) { + out->days = td / sec_per_day; + td = -td; td += out->days * sec_per_day; + } else { + td = -td; } } - - } else { - td = td / per_sec; - if (td >= sec_per_day) { - out->days = td / sec_per_day; - td -= out->days * sec_per_day; - } + } else if (td >= sec_per_day) { + out->days = td / sec_per_day; + td -= out->days * sec_per_day; } if (td >= sec_per_hour) { From b61b71c8e230ff56b1daa089189588ef70c0bcb4 Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Tue, 26 Mar 2024 00:47:31 +0100 Subject: [PATCH 19/22] reintroduce sfrac, minimize casting --- .../src/vendored/numpy/datetime/np_datetime.c | 58 +++++++++---------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index 2a0cfc4c6bcaf..b43bbc47caf38 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -752,59 +752,55 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, } const npy_int64 per_day = sec_per_day * per_sec; - npy_int64 ifrac = td; const int sign = td < 0 ? -1 : 1; + const int is_negative = td < 0 ? 1 : 0; const int uneven_in_seconds = td % per_sec != 0 ? 1 : 0; // put frac in seconds - td = td / per_sec; + npy_int64 sfrac = td / per_sec - is_negative * uneven_in_seconds; if (sign < 0) { - td -= uneven_in_seconds; // even fraction - if ((-td % sec_per_day) != 0) { - // days = td / sec_per_day - is_even_fraction - out->days = td / sec_per_day - 1; - td -= sec_per_day * out->days; + if ((-sfrac % sec_per_day) != 0) { + out->days = sfrac / sec_per_day - 1; + sfrac -= sec_per_day * out->days; } else { - if (td <= sec_per_day) { - out->days = td / sec_per_day; - td = -td; - td += out->days * sec_per_day; - } else { - td = -td; + if (sfrac <= sec_per_day) { + out->days = sfrac / sec_per_day; + sfrac -= out->days * sec_per_day; } + sfrac = -sfrac; } - } else if (td >= sec_per_day) { - out->days = td / sec_per_day; - td -= out->days * sec_per_day; + } else if (sfrac >= sec_per_day) { + out->days = sfrac / sec_per_day; + sfrac -= out->days * sec_per_day; } - if (td >= sec_per_hour) { - out->hrs = (npy_int32)(td / sec_per_hour); - td %= sec_per_hour; + if (sfrac >= sec_per_hour) { + out->hrs = (npy_int32)(sfrac / sec_per_hour); + sfrac %= sec_per_hour; } - if (td >= sec_per_min) { - out->min = (npy_int32)(td / sec_per_min); - td %= sec_per_min; + if (sfrac >= sec_per_min) { + out->min = (npy_int32)(sfrac / sec_per_min); + sfrac %= sec_per_min; } - if (td >= 0) { - out->sec = (npy_int32)td; + if (sfrac >= 0) { + out->sec = (npy_int32)sfrac; } if (base > NPY_FR_s) { - ifrac = (ifrac - out->days * per_day) % per_sec; + npy_int32 ifrac = (npy_int32)((td - out->days * per_day) % per_sec); if (base == NPY_FR_ms) { - out->ms = (npy_int32)ifrac; + out->ms = ifrac; } else if (base == NPY_FR_us) { - out->ms = (npy_int32)(ifrac / 1000LL); - out->us = (npy_int32)(ifrac % 1000LL); + out->ms = ifrac / 1000LL; + out->us = ifrac % 1000LL; } else if (base == NPY_FR_ns) { - out->ms = (npy_int32)(ifrac / (1000LL * 1000LL)); + out->ms = ifrac / (1000LL * 1000LL); ifrac = ifrac % (1000LL * 1000LL); - out->us = (npy_int32)(ifrac / 1000LL); - out->nanoseconds = (npy_int32)(ifrac % 1000LL); + out->us = ifrac / 1000LL; + out->nanoseconds = ifrac % 1000LL; } out->microseconds = out->ms * 1000 + out->us; } From c3b19e0f445fe7d9d50a3972b4bdd9ef1b90d965 Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Tue, 26 Mar 2024 01:05:47 +0100 Subject: [PATCH 20/22] add comment --- pandas/_libs/src/vendored/numpy/datetime/np_datetime.c | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index b43bbc47caf38..fc04a4be17757 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -789,6 +789,7 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, } if (base > NPY_FR_s) { + // there will be at most 1 billion nanoseconds left here npy_int32 ifrac = (npy_int32)((td - out->days * per_day) % per_sec); if (base == NPY_FR_ms) { From 80ce2834cd23bdb96994b7fd5452d13a48efa4f7 Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Tue, 26 Mar 2024 01:24:58 +0100 Subject: [PATCH 21/22] fix error --- pandas/_libs/src/vendored/numpy/datetime/np_datetime.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index fc04a4be17757..5e53be6f138f9 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -801,9 +801,8 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, out->ms = ifrac / (1000LL * 1000LL); ifrac = ifrac % (1000LL * 1000LL); out->us = ifrac / 1000LL; - out->nanoseconds = ifrac % 1000LL; + out->ns = ifrac % 1000LL; } - out->microseconds = out->ms * 1000 + out->us; } } break; @@ -815,6 +814,8 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, } out->seconds = (npy_int32)(out->hrs * sec_per_hour + out->min * sec_per_min + out->sec); + out->microseconds = out->ms * 1000 + out->us; + out->nanoseconds = out->ns; } /* From 322252e5b277f30c68018d276fb2e6ee375ffacb Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Tue, 26 Mar 2024 02:42:12 +0100 Subject: [PATCH 22/22] remove uneven_in_seconds --- pandas/_libs/src/vendored/numpy/datetime/np_datetime.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c index 5e53be6f138f9..d60500a3c45dd 100644 --- a/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c +++ b/pandas/_libs/src/vendored/numpy/datetime/np_datetime.c @@ -753,11 +753,12 @@ void pandas_timedelta_to_timedeltastruct(npy_timedelta td, const npy_int64 per_day = sec_per_day * per_sec; const int sign = td < 0 ? -1 : 1; - const int is_negative = td < 0 ? 1 : 0; - const int uneven_in_seconds = td % per_sec != 0 ? 1 : 0; // put frac in seconds - npy_int64 sfrac = td / per_sec - is_negative * uneven_in_seconds; + npy_int64 sfrac = td / per_sec; if (sign < 0) { + if (td % per_sec != 0) + sfrac -= 1; + // even fraction if ((-sfrac % sec_per_day) != 0) { out->days = sfrac / sec_per_day - 1;