rounding errors in Python floor division

前端 未结 5 1054
挽巷
挽巷 2020-12-04 21:29

I know rounding errors happen in floating point arithmetic but can somebody explain the reason for this one:

>>> 8.0 / 0.4  # as expected
20.0
>&         


        
5条回答
  •  不知归路
    2020-12-04 22:05

    That's because there is no 0.4 in python (floating-point finite representation) it's actually a float like 0.4000000000000001 which makes the floor of division to be 19.

    >>> floor(8//0.4000000000000001)
    19.0
    

    But the true division (/) returns a reasonable approximation of the division result if the arguments are floats or complex. And that's why the result of 8.0/0.4 is 20. It actually depends on the size of arguments (in C double arguments). (not rounding to nearest float)

    Read more about pythons integer division floors by Guido himself.

    Also for complete information about the float numbers you can read this article https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

    For those who have interest, the following function is the float_div that does the true division task for float numbers, in Cpython's source code:

    float_div(PyObject *v, PyObject *w)
    {
        double a,b;
        CONVERT_TO_DOUBLE(v, a);
        CONVERT_TO_DOUBLE(w, b);
        if (b == 0.0) {
            PyErr_SetString(PyExc_ZeroDivisionError,
                            "float division by zero");
            return NULL;
        }
        PyFPE_START_PROTECT("divide", return 0)
        a = a / b;
        PyFPE_END_PROTECT(a)
        return PyFloat_FromDouble(a);
    }
    

    Which the final result would be calculated by function PyFloat_FromDouble:

    PyFloat_FromDouble(double fval)
    {
        PyFloatObject *op = free_list;
        if (op != NULL) {
            free_list = (PyFloatObject *) Py_TYPE(op);
            numfree--;
        } else {
            op = (PyFloatObject*) PyObject_MALLOC(sizeof(PyFloatObject));
            if (!op)
                return PyErr_NoMemory();
        }
        /* Inline PyObject_New */
        (void)PyObject_INIT(op, &PyFloat_Type);
        op->ob_fval = fval;
        return (PyObject *) op;
    }
    

提交回复
热议问题