【问题标题】:Why no optimization of Python 3 range object for floats?为什么不针对浮点数优化 Python 3 范围对象?
【发布时间】:2016-05-12 04:32:56
【问题描述】:

从我不久前问的上一个问题跳出来:

Why is 1000000000000000 in range(1000000000000001) so fast in Python 3?

如果你这样做:

1000000000000000.0 in range(1000000000000001)

...很明显range 没有被优化来检查floats 是否在指定范围内。

我想我理解 range 的预期目的是仅与 ints 一起工作 - 例如,你不能这样做:

1000000000000 in range(1000000000000001.0)
# error: float object cannot be interpreted as an integer

或者这个:

1000000000000 in range(0, 1000000000000001, 1.0) 
# error: float object cannot be interpreted as an integer

但是,无论出于何种原因,我们都决定允许这样的事情:

1.0 in range(1)

似乎很明显1.0(和上面的1000000000000.0)没有被强制转换为ints,因为这样int 优化也适用于这些。

我的问题是,为什么不一致,为什么没有优化 floats?或者,或者,为什么上面的代码不会产生与前面的示例相同的错误背后的基本原理是什么?

这似乎是一个明显的优化,除了对ints 的优化。我猜有一些细微的问题阻碍了这种优化的干净实施,或者有某种理由说明为什么你实际上不想包含这样的优化。或者可能两者兼而有之。

编辑:为了澄清这里的问题,以下所有语句也评估为False:

3.2 in range(5)
'' in range(1)
[] in range(1)
None in range(1)

这对我来说似乎是出乎意料的行为,但到目前为止绝对没有不一致。但是,以下计算结果为 True:

1.0 in range(2.0)

如前所述,与上述类似的结构尚未优化。

这看起来确实不一致——在评估中的某个时刻,值1.0(或我原来的示例中的1000000000001.0)被强制转换为int。这是有道理的,因为将以.0 结尾的float 转换为int 是很自然的事情。然而,问题仍然存在:如果它被转换为int,为什么1000000000000.0 in range(1000000000001) 没有被优化?

【问题讨论】:

  • 在您的编辑中,您似乎假设 x in range(n) 对于 any float x 是错误的。这不是真的:例如,试试1.0 in range(2)。
  • @MarkDickinson 好点——现在我们回到了我认为不一致的问题,关于为什么1000000000000.0 in range(1000000000001) 的问题还没有得到优化——这似乎很明显要做——仍然存在。不幸的是,我已经接受了答案。
  • @MarkDickinson 我已经重新编辑了这个问题。感谢您指出这一点。

标签: python python-3.x optimization range


【解决方案1】:

这里没有不一致。浮点值不能强制转换为整数,只能反过来。因此,range() 在测试包容性时也不会将浮点数隐式转换为整数。

range() 对象是一个序列类型;它包含离散的整数值(尽管是虚拟的)。因此,它必须支持对 any 对象的包含测试,这些对象可能测试为相等。以下也有效:

>>> class ThreeReally:
...     def __eq__(self, other):
...         return other == 3
...
>>> ThreeReally() in range(4)
True

这必须对范围内的所有可能值进行全面扫描,以测试每个包含的整数是否相等。

但是,只有在使用 实际整数 时才能应用优化,因为这是唯一一种类型,range() 对象可以知道哪些值将被视为相等而不转换。

【讨论】:

  • 这是有道理的。但是仍然可以通过将int 边界转换为floats 来优化检查float 是否在两个ints 的范围内。这似乎是一件很明显的事情。为什么不这样做?
  • @RickTeachey:因为range()由一系列离散整数组成;中间的非整数十进制值不属于范围。
  • @RickTeachey:不,序列的文档指出in 测试对象中是否存在相等的值。 1.0 == 1 相等,所以 1.0 in range(10) 为真,因为该序列中有相等的值。 Python 只是没有优化它,因为这需要隐式转换,并且根本不是范围对象的用例。
  • @RickTeachey 我删除了我的评论,因为它与为什么1.0 in range(whatever) 的行为 与1 in range(whatever) 不同的问题并不真正相关,即使返回值是一样的。
  • @RickTeachey:我已经在我的问题中解决了这个问题,并以ThreeReally 为例。 1.0 == 1 是正确的,只是因为 float.__eq__ 存在进行转换。 range() 优化不会对实际整数以外的任何内容进行假设,并对这些类型进行全面扫描,包括 float。
猜你喜欢
  • 2019-03-15
  • 1970-01-01
  • 1970-01-01
  • 2022-11-16
  • 1970-01-01
  • 2015-09-30
  • 1970-01-01
  • 2014-03-15
  • 1970-01-01
相关资源
最近更新 更多