import _testcapi import fractions # _PyTime_ROUND_FLOOR: Round towards minus infinity (-inf) _PyTime_ROUND_FLOOR = 0 SEC_TO_NS = 10 ** 9 FULLINT = False CHECK_OVERFLOW = False def test(qpc, qpf): text = "[qpc=%s, qpf=%s]" % (qpc, qpf) bugs = [] if FULLINT: frac = fractions.Fraction(SEC_TO_NS, qpf) mul, div = frac.numerator, frac.denominator t = qpc * mul if CHECK_OVERFLOW: if t > 2**63 - 1: raise OverflowError("%s: t=%s, bits=%s" % (text, t, t.bit_length())) t = t // div d = _testcapi.PyTime_AsSecondsDouble(t) t2 = _testcapi.PyTime_FromSecondsObject(d, _PyTime_ROUND_FLOOR) text = ("%s t: %s -> %s -> %s (int diff=%s)" % (text, t, d, t2, t2 - t)) if t2 != t: # check if the conversion to double looses precision bugs.append("t2 != t") else: d = qpc / qpf t2 = _testcapi.PyTime_FromSecondsObject(d, _PyTime_ROUND_FLOOR) d2 = _testcapi.PyTime_AsSecondsDouble(t2) text = ("%s: %s -> %s -> %s (double diff=%s)" % (text, d, t2, d2, d2 - d)) if d2 != d: bugs.append("d2 != d") if bugs: print("BUGS %s! %s" % (bugs, text)) else: print("Ok. %s" % text) return bool(bugs) day_in_sec = 3600 * 24 year_in_sec = day_in_sec * 366 loss = False for qpf in (10 ** 7, 3579545): for sec in ( 1, #day_in_sec, #day_in_sec * 49, #year_in_sec, #year_in_sec * 25, ): qpc = sec * qpf loss |= test(qpc, qpf) loss |= test(qpc - 1, qpf) loss |= test(qpc + 1, qpf) print() if loss: print("Lost precision :-(") else: print("Everything is fine!")