【问题标题】:why 1 // 0.05 results in 19.0 in python?为什么 1 // 0.05 在 python 中会导致 19.0?
【发布时间】:2023-03-05 15:42:01
【问题描述】:

我是 python 新手,在我的 mac 上使用 Python3.5.1 时发现了一个令人困惑的结果,我只是在终端中运行了这个命令

    1 // 0.05

但是,它在我的屏幕上打印了 19.0。从我的角度来看,应该是 20。有人可以解释这里发生了什么吗?我已经知道 '//' 类似于 math.floor() 函数。但我仍然无法理解这一点。

【问题讨论】:

  • 它先除然后向下舍入。就是这样。
  • @MarkyPython:不仅如此。在我的机器上,1 / 0.0520.0,但 1 // 0.0519.0
  • 长话短说:在处理浮点数时不要期待任何特定结果。
  • 为什么重新打开? IMO Is floating point math broken? 是一个很好的欺骗目标。
  • @vaultah 我重新打开了它,因为我不认为它与 stackoverflow.com/q/588004/2301450 重复。这个问题是专门关于楼层划分操作员如何工作的。这不是一个关于为什么浮点数学不精确的普遍问题。

标签: python floating-accuracy


【解决方案1】:

因为 Python 浮点文字 0.05 表示一个比数学值 0.05 略大的数字。

>>> '%.60f' % 0.05
'0.050000000000000002775557561562891351059079170227050781250000'

// 是除数,意思是结果是最大整数n 使得n 乘以除数小于或等于被除数。由于 20 倍 0.05000000000000000277555756156289135105907917022705078125 大于 1,这意味着正确的结果是 19。

至于为什么 Python 文字 0.05 不代表数字 0.05,以及关于浮点的许多其他内容,请参阅 What Every Computer Scientist Should Know About Floating-Point Arithmetic

【讨论】:

  • 另外,在这种情况下它不返回整数,而是浮点数。
  • @AnttiHaapala:我确实想知道我是否会摆脱那个术语。它返回一个表示整数的浮点值。它不返回的是 Python 类型 int(或 long),但我在这里使用“整数”这个词来表示整数的数学概念,而不是称为 int 的 Python 类型。
  • @SteveJessop 感谢您的帮助,我真的应该小心编程中的浮点值。
【解决方案2】:

0.05 不能用浮点数精确表示。 "%0.20f" % 0.05 表明 0.05 存储为一个比精确值略大的值:

>>> print "%0.20f" % 0.05
0.05000000000000000278

另一方面,1/0.05 似乎正好是 20:

>>> print "%0.20f" % (1/0.05)
20.00000000000000000000

但是,所有浮点值在存储时都会四舍五入,但计算会以更高的精度进行。在这种情况下,1//0.05 执行的地板操作似乎是在完全内部精度下完成的,因此它被四舍五入。

【讨论】:

    【解决方案3】:

    正如前面的回答者正确指出的那样,分数 0.05 = 1/20 不能用有限个以两位为底的数字精确表示。它适用于重复分数 0.0000 1100 1100 1100...(很像熟悉的十进制中的 1/3 = 0.333...)。

    但这并不是你问题的完整答案,因为这里还有一点奇怪之处:

    >>> 1 / 0.05
    20.0
    >>> 1 // 0.05
    19.0
    

    使用“真除法”运算符/ 恰好给出了预期的答案20.0。您在这里很幸运:除法中的舍入误差完全抵消了表示值 0.05 本身的误差。

    但是1 // 0.05 怎么会返回 19? a // b 不应该和math.floor(a /b) 一样吗?为什么/// 不一致?

    注意divmod函数与//运算符一致:

    >>> divmod(1, 0.05)
    (19.0, 0.04999999999999995)
    

    可以通过使用精确有理算术执行浮点除法来解释这种行为。当您在 Python 中(在符合 IEEE 754 的平台上)编写文字 0.05 时,表示的实际值为 3602879701896397 / 72057594037927936 = 0.05000000000000000277555756156289135105907917022705。这个值恰好比预期的 0.05 略,这意味着它的倒数将略

    确切地说,72057594037927936 / 3602879701896397 = 19.999999999999998889776975374843521206126552300723564152465244707437044687...

    所以,//divmod 看到整数商 19。余数等于 0.04999999999999994726440633030506432987749576568603515625,四舍五入显示为 0.04999999999999995。因此,考虑到 0.05 的原始值不正确,上面的 divmod 答案实际上对 53 位精度很好。

    但是/ 呢?那么,真正的商 72057594037927936 / 3602879701896397 不能表示为 float,所以它必须四舍五入,要么向下舍入到 20-2**-48(大约 2.44e-15 的误差)或高达 20.0(误差大约 1.11e-15)。 Python 正确地选择了更准确的选择,20.0

    因此,似乎 Python 的浮点除法在内部以足够高的精度完成,以知道 1 / 0.05(即 float 文字 0.05,而不是精确的小数部分 0.05)实际上是 小于 20,但float 类型本身无法表示差异。

    此时您可能会想“那又怎样?我不在乎 Python 是否给出了不正确值的正确倒数。我首先想知道如何获得正确的值。”答案是:

    【讨论】:

      猜你喜欢
      • 2014-11-29
      • 1970-01-01
      • 2018-06-25
      • 1970-01-01
      • 1970-01-01
      • 2015-05-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多