STINNER Victor <vstin...@python.org> added the comment:

>>> a / 10**9 <= b
    False

Try to use a/1e9 <= b.

--

The C code to get the system clock is the same for time.time() and 
time.time_ns(). It's only the conversion of the result which is different:

static PyObject *
time_time(PyObject *self, PyObject *unused)
{
    _PyTime_t t = _PyTime_GetSystemClock();
    return _PyFloat_FromPyTime(t);
}

static PyObject *
time_time_ns(PyObject *self, PyObject *unused)
{
    _PyTime_t t = _PyTime_GetSystemClock();
    return _PyTime_AsNanosecondsObject(t);
}

where _PyTime_t is int64_t: 64-bit signed integer.


Conversions:

static PyObject*
_PyFloat_FromPyTime(_PyTime_t t)
{
    double d = _PyTime_AsSecondsDouble(t);
    return PyFloat_FromDouble(d);
}


double
_PyTime_AsSecondsDouble(_PyTime_t t)
{
    /* volatile avoids optimization changing how numbers are rounded */
    volatile double d;

    if (t % SEC_TO_NS == 0) {
        _PyTime_t secs;
        /* Divide using integers to avoid rounding issues on the integer part.
           1e-9 cannot be stored exactly in IEEE 64-bit. */
        secs = t / SEC_TO_NS;
        d = (double)secs;
    }
    else {
        d = (double)t;
        d /= 1e9;
    }
    return d;
}

PyObject *
_PyTime_AsNanosecondsObject(_PyTime_t t)
{
    Py_BUILD_ASSERT(sizeof(long long) >= sizeof(_PyTime_t));
    return PyLong_FromLongLong((long long)t);
}

In short, time.time() = float(time.time_ns()) / 1e9.

--

The problem can be reproduced in Python:

>>> a=1580301619906185300
>>> b=a/1e9
>>> a / 10**9 <= b
False

I added time.time_ns() because we loose precision if you care about nanosecond 
resolution, with such "large number". float has a precision around 238 
nanoseconds:

>>> import math; ulp=math.ulp(b)
>>> ulp
2.384185791015625e-07
>>> "%.0f +- %.0f" % (b*1e9, ulp*1e9)
'1580301619906185216 +- 238'

int/int and int/float don't give the same result:

>>> a/10**9
1580301619.9061854
>>> a/1e9
1580301619.9061852

I'm not sure which one is "correct". To understand the issue, you can use the 
next math.nextafter() function to get the next floating point towards -inf:

>>> a/10**9
1580301619.9061854
>>> a/1e9
1580301619.9061852
>>> math.nextafter(a/10**9, -math.inf)
1580301619.9061852
>>> math.nextafter(a/1e9, -math.inf)
1580301619.906185

Handling floating point numbers are hard.

Why don't use only use integers? :-)

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue39484>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to