为什么是9007199254740993!=9007199254740993.0?

2024-04-20 13:42:36 发布

您现在位置:Python中文网/ 问答频道 /正文

这个比较的结果让我吃惊(CPython 3.4):

>>> 9007199254740993 == 9007199254740993.0
False

我对the docs的理解是,左操作数应转换为float,以匹配右操作数的类型:

Python fully supports mixed arithmetic: when a binary arithmetic operator has operands of different numeric types, the operand with the “narrower” type is widened to that of the other, where integer is narrower than floating point, which is narrower than complex. Comparisons between numbers of mixed type use the same rule. The constructors int(), float(), and complex() can be used to produce numbers of a specific type.

这似乎没有发生:

^{pr2}$

这是怎么回事?在


Tags: ofthetofalsedocsistypearithmetic
1条回答
网友
1楼 · 发布于 2024-04-20 13:42:36

Python在这里并没有将整数转换为浮点;它将浮点转换为整数:

>>> 9007199254740993 == int(9007199254740993.0)
False

这失败了,因为int(9007199254740993.0)实际上是9007199254740992:

^{pr2}$

参见^{} function。具体而言,它面前的评论:

/* Comparison is pretty much a nightmare. 

 [...]

 * When mixing float with an integer type, there's no good *uniform* approach.
 * Converting the double to an integer obviously doesn't work, since we
 * may lose info from fractional bits.  Converting the integer to a double
 * also has two failure modes:  (1) an int may trigger overflow (too
 * large to fit in the dynamic range of a C double); (2) even a C long may have
 * more bits than fit in a C double (e.g., on a 64-bit box long may have
 * 63 bits of precision, but a C double probably has only 53), and then
 * we can falsely claim equality when low-order integer bits are lost by
 * coercion to double.  So this part is painful too.

这两个数字的结果是:

  • Python尝试int.__eq__(float)路由,但返回{}
  • Python尝试float.__eq__(int)路由,该路由由float_richcompare()处理。在

在那个函数中,v是你的浮点值,w是整数。以下是为该路径执行的代码选择:

else if (PyLong_Check(w)) {   /* true because the other number is an Python integer */

    /* ... */

    nbits = _PyLong_NumBits(w);   /* 54 for your integer */

    /* ... */

    if (nbits <= 48) {  /* nope, can't make it a float outright */
        /* ... */
    }

    (void) frexp(i, &exponent);  /* the exponent is 54 for your float */

    if (exponent < 0 || (size_t)exponent < nbits) {
        /* not true */
    }
    if ((size_t)exponent > nbits) {
        /* also not true */
    }
    /* v and w have the same number of bits before the radix
     * point.  Construct two ints that have the same comparison
     * outcome.
     */
    {
        /* code to convert v to an integer vv, copy w to ww */

        r = PyObject_RichCompareBool(vv, ww, op);

        /* ... */

        result = PyBool_FromLong(r);

        /* ... */

        return result;
    }

最后,由于涉及到的数字的大小,Python将浮点转换为整数,在这种转换中,浮点数变成了9007199254740992。这是因为float实际上不能准确地表示9007199254740993.0

>>> 9007199254740993.0
9007199254740992.0

相关问题 更多 >