mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
Issue #23517: Add "half up" rounding mode to the _PyTime API
This commit is contained in:
parent
bbdda21a7a
commit
744742320f
4 changed files with 122 additions and 15 deletions
|
@ -30,8 +30,11 @@ class _PyTime(enum.IntEnum):
|
|||
ROUND_FLOOR = 0
|
||||
# Round towards infinity (+inf)
|
||||
ROUND_CEILING = 1
|
||||
# Round to nearest with ties going away from zero
|
||||
ROUND_HALF_UP = 2
|
||||
|
||||
ALL_ROUNDING_METHODS = (_PyTime.ROUND_FLOOR, _PyTime.ROUND_CEILING)
|
||||
ALL_ROUNDING_METHODS = (_PyTime.ROUND_FLOOR, _PyTime.ROUND_CEILING,
|
||||
_PyTime.ROUND_HALF_UP)
|
||||
|
||||
|
||||
class TimeTestCase(unittest.TestCase):
|
||||
|
@ -753,11 +756,11 @@ class TestPyTime_t(unittest.TestCase):
|
|||
(123.0, 123 * SEC_TO_NS),
|
||||
(-7.0, -7 * SEC_TO_NS),
|
||||
|
||||
# nanosecond are kept for value <= 2^23 seconds
|
||||
# nanosecond are kept for value <= 2^23 seconds,
|
||||
# except 2**23-1e-9 with HALF_UP
|
||||
(2**22 - 1e-9, 4194303999999999),
|
||||
(2**22, 4194304000000000),
|
||||
(2**22 + 1e-9, 4194304000000001),
|
||||
(2**23 - 1e-9, 8388607999999999),
|
||||
(2**23, 8388608000000000),
|
||||
|
||||
# start loosing precision for value > 2^23 seconds
|
||||
|
@ -790,24 +793,36 @@ class TestPyTime_t(unittest.TestCase):
|
|||
# Conversion giving different results depending on the rounding method
|
||||
FLOOR = _PyTime.ROUND_FLOOR
|
||||
CEILING = _PyTime.ROUND_CEILING
|
||||
HALF_UP = _PyTime.ROUND_HALF_UP
|
||||
for obj, ts, rnd in (
|
||||
# close to zero
|
||||
( 1e-10, 0, FLOOR),
|
||||
( 1e-10, 1, CEILING),
|
||||
( 1e-10, 0, HALF_UP),
|
||||
(-1e-10, -1, FLOOR),
|
||||
(-1e-10, 0, CEILING),
|
||||
(-1e-10, 0, HALF_UP),
|
||||
|
||||
# test rounding of the last nanosecond
|
||||
( 1.1234567899, 1123456789, FLOOR),
|
||||
( 1.1234567899, 1123456790, CEILING),
|
||||
( 1.1234567899, 1123456790, HALF_UP),
|
||||
(-1.1234567899, -1123456790, FLOOR),
|
||||
(-1.1234567899, -1123456789, CEILING),
|
||||
(-1.1234567899, -1123456790, HALF_UP),
|
||||
|
||||
# close to 1 second
|
||||
( 0.9999999999, 999999999, FLOOR),
|
||||
( 0.9999999999, 1000000000, CEILING),
|
||||
( 0.9999999999, 1000000000, HALF_UP),
|
||||
(-0.9999999999, -1000000000, FLOOR),
|
||||
(-0.9999999999, -999999999, CEILING),
|
||||
(-0.9999999999, -1000000000, HALF_UP),
|
||||
|
||||
# close to 2^23 seconds
|
||||
(2**23 - 1e-9, 8388607999999999, FLOOR),
|
||||
(2**23 - 1e-9, 8388607999999999, CEILING),
|
||||
(2**23 - 1e-9, 8388608000000000, HALF_UP),
|
||||
):
|
||||
with self.subTest(obj=obj, round=rnd, timestamp=ts):
|
||||
self.assertEqual(PyTime_FromSecondsObject(obj, rnd), ts)
|
||||
|
@ -875,18 +890,33 @@ class TestPyTime_t(unittest.TestCase):
|
|||
|
||||
FLOOR = _PyTime.ROUND_FLOOR
|
||||
CEILING = _PyTime.ROUND_CEILING
|
||||
HALF_UP = _PyTime.ROUND_HALF_UP
|
||||
for ns, tv, rnd in (
|
||||
# nanoseconds
|
||||
(1, (0, 0), FLOOR),
|
||||
(1, (0, 1), CEILING),
|
||||
(1, (0, 0), HALF_UP),
|
||||
(-1, (-1, 999999), FLOOR),
|
||||
(-1, (0, 0), CEILING),
|
||||
(-1, (0, 0), HALF_UP),
|
||||
|
||||
# seconds + nanoseconds
|
||||
(1234567001, (1, 234567), FLOOR),
|
||||
(1234567001, (1, 234568), CEILING),
|
||||
(1234567001, (1, 234567), HALF_UP),
|
||||
(-1234567001, (-2, 765432), FLOOR),
|
||||
(-1234567001, (-2, 765433), CEILING),
|
||||
(-1234567001, (-2, 765433), HALF_UP),
|
||||
|
||||
# half up
|
||||
(499, (0, 0), HALF_UP),
|
||||
(500, (0, 1), HALF_UP),
|
||||
(501, (0, 1), HALF_UP),
|
||||
(999, (0, 1), HALF_UP),
|
||||
(-499, (0, 0), HALF_UP),
|
||||
(-500, (0, 0), HALF_UP),
|
||||
(-501, (-1, 999999), HALF_UP),
|
||||
(-999, (-1, 999999), HALF_UP),
|
||||
):
|
||||
with self.subTest(nanoseconds=ns, timeval=tv, round=rnd):
|
||||
self.assertEqual(PyTime_AsTimeval(ns, rnd), tv)
|
||||
|
@ -929,18 +959,33 @@ class TestPyTime_t(unittest.TestCase):
|
|||
|
||||
FLOOR = _PyTime.ROUND_FLOOR
|
||||
CEILING = _PyTime.ROUND_CEILING
|
||||
HALF_UP = _PyTime.ROUND_HALF_UP
|
||||
for ns, ms, rnd in (
|
||||
# nanoseconds
|
||||
(1, 0, FLOOR),
|
||||
(1, 1, CEILING),
|
||||
(1, 0, HALF_UP),
|
||||
(-1, 0, FLOOR),
|
||||
(-1, -1, CEILING),
|
||||
(-1, 0, HALF_UP),
|
||||
|
||||
# seconds + nanoseconds
|
||||
(1234 * MS_TO_NS + 1, 1234, FLOOR),
|
||||
(1234 * MS_TO_NS + 1, 1235, CEILING),
|
||||
(1234 * MS_TO_NS + 1, 1234, HALF_UP),
|
||||
(-1234 * MS_TO_NS - 1, -1234, FLOOR),
|
||||
(-1234 * MS_TO_NS - 1, -1235, CEILING),
|
||||
(-1234 * MS_TO_NS - 1, -1234, HALF_UP),
|
||||
|
||||
# half up
|
||||
(499999, 0, HALF_UP),
|
||||
(499999, 0, HALF_UP),
|
||||
(500000, 1, HALF_UP),
|
||||
(999999, 1, HALF_UP),
|
||||
(-499999, 0, HALF_UP),
|
||||
(-500000, -1, HALF_UP),
|
||||
(-500001, -1, HALF_UP),
|
||||
(-999999, -1, HALF_UP),
|
||||
):
|
||||
with self.subTest(nanoseconds=ns, milliseconds=ms, round=rnd):
|
||||
self.assertEqual(PyTime_AsMilliseconds(ns, rnd), ms)
|
||||
|
@ -966,18 +1011,31 @@ class TestPyTime_t(unittest.TestCase):
|
|||
|
||||
FLOOR = _PyTime.ROUND_FLOOR
|
||||
CEILING = _PyTime.ROUND_CEILING
|
||||
HALF_UP = _PyTime.ROUND_HALF_UP
|
||||
for ns, ms, rnd in (
|
||||
# nanoseconds
|
||||
(1, 0, FLOOR),
|
||||
(1, 1, CEILING),
|
||||
(1, 0, HALF_UP),
|
||||
(-1, 0, FLOOR),
|
||||
(-1, -1, CEILING),
|
||||
(-1, 0, HALF_UP),
|
||||
|
||||
# seconds + nanoseconds
|
||||
(1234 * US_TO_NS + 1, 1234, FLOOR),
|
||||
(1234 * US_TO_NS + 1, 1235, CEILING),
|
||||
(1234 * US_TO_NS + 1, 1234, HALF_UP),
|
||||
(-1234 * US_TO_NS - 1, -1234, FLOOR),
|
||||
(-1234 * US_TO_NS - 1, -1235, CEILING),
|
||||
(-1234 * US_TO_NS - 1, -1234, HALF_UP),
|
||||
|
||||
# half up
|
||||
(1499, 1, HALF_UP),
|
||||
(1500, 2, HALF_UP),
|
||||
(1501, 2, HALF_UP),
|
||||
(-1499, -1, HALF_UP),
|
||||
(-1500, -2, HALF_UP),
|
||||
(-1501, -2, HALF_UP),
|
||||
):
|
||||
with self.subTest(nanoseconds=ns, milliseconds=ms, round=rnd):
|
||||
self.assertEqual(PyTime_AsMicroseconds(ns, rnd), ms)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue