Python 如何将“int"与“float"对象进行比较? [英] How does Python compare 'int' to 'float' objects?

查看:54
本文介绍了Python 如何将“int"与“float"对象进行比较?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有关数字类型的文档指出:

<块引用>

Python 完全支持混合算术:当一个二元算术运算符有不同数值类型的操作数时,具有较窄"类型的操作数被加宽到另一个类型的操作数,其中整数比浮点窄,浮点比复数窄.混合类型数字之间的比较使用相同的规则.

以下行为支持这一点:

<预><代码>>>>int.__eq__(1, 1.0)未实现>>>float.__eq__(1.0, 1)真的

然而,对于大整数,似乎会发生其他事情,因为除非明确转换为 float,否则它们不会比较相等:

<预><代码>>>>n = 3**64>>>浮动(n)== n错误的>>>浮点(n)==浮点(n)真的

另一方面,对于 2 的幂,这似乎不是问题:

<预><代码>>>>n = 2**512>>>浮动(n)== n真的

因为文档暗示 int 被加宽"(我假设转换/转换?)到 float 我期望 float(n) ==nfloat(n) == float(n) 是相似的,但上面带有 n = 3**64 的例子建议不同.那么 Python 使用什么规则来比较 intfloat(或一般的混合数字类型)?

<小时>

使用 Anaconda 的 CPython 3.7.3 和 PyPy 7.3.0 (Python 3.6.9) 进行测试.

解决方案

关于值比较的语言规范 包含以下段落:

<块引用>

内置数字类型(数字类型 — int、float、complex)和标准库类型 fractions.Fractiondecimal.Decimal 的数量 可以在它们的类型内和之间进行比较,但限制是复数不支持顺序比较.在所涉及类型的范围内,它们在数学上(算法上)进行比较而不会损失精度.

这意味着当比较两个数字类型时,将比较这些对象表示的实际(数学)数字.例如 numeral 16677181699666569.0(即 3**34) 表示数字 16677181699666569,即使在浮动空间"中,此数字与 16677181699666568.0 (3**34 - 1) 它们确实代表不同的数字.由于浮点精度有限,在 64 位体系结构上,值 float(3**34) 将存储为 16677181699666568,因此它表示与整数数字 16677181699666569 不同的数字.出于这个原因,我们有 float(3**34) != 3**34 可以在不损失精度的情况下执行比较.

为了保证传递性,此属性很重要://en.wikipedia.org/wiki/Equivalence_relation" rel="nofollow noreferrer">数字类型的等价关系.如果 intfloat 的比较会给出类似的结果,就好像 int 对象将被转换为 float 对象然后传递关系将无效:

<预><代码>>>>类浮动(浮动):... def __eq__(self, other):... return super().__eq__(float(other))...>>>a = 3**34 - 1>>>b = 浮点数(3**34)>>>c = 3**34>>>a == b真的>>>b == c真的>>>a == c # 传递性要求这成立错误的

另一方面,float.__eq__ 实现考虑了所表示的数学数字,并没有违反该要求:

<预><代码>>>>a = 3**34 - 1>>>b = 浮点数(3**34)>>>c = 3**34>>>a == b真的>>>b == c错误的>>>a == c错误的

由于缺少传递性,以下列表的顺序不会因排序而改变(因为所有连续的数字似乎都相等):

<预><代码>>>>类浮动(浮动):... def __lt__(self, other):... return super().__lt__(float(other))... def __eq__(self, other):... return super().__eq__(float(other))...>>>数字 = [3**34, Float(3**34), 3**34 - 1]>>>排序(数字)== 数字真的

另一方面,使用float,顺序相反:

<预><代码>>>>数字 = [3**34, float(3**34), 3**34 - 1]>>>排序(数字)==数字[::-1]真的

The documentation about numeric types states that:

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.

This is supported by the following behavior:

>>> int.__eq__(1, 1.0)
NotImplemented
>>> float.__eq__(1.0, 1)
True

However for large integer numbers something else seems to happen since they won't compare equal unless explicitly converted to float:

>>> n = 3**64
>>> float(n) == n
False
>>> float(n) == float(n)
True

On the other hand, for powers of 2, this doesn't seem to be a problem:

>>> n = 2**512
>>> float(n) == n
True

Since the documentation implies that int is "widened" (I assume converted / cast?) to float I'd expect float(n) == n and float(n) == float(n) to be similar but the above example with n = 3**64 suggests differently. So what rules does Python use to compare int to float (or mixed numeric types in general)?


Tested with CPython 3.7.3 from Anaconda and PyPy 7.3.0 (Python 3.6.9).

解决方案

The language specification on value comparisons contains the following paragraph:

Numbers of built-in numeric types (Numeric Types — int, float, complex) and of the standard library types fractions.Fraction and decimal.Decimal can be compared within and across their types, with the restriction that complex numbers do not support order comparison. Within the limits of the types involved, they compare mathematically (algorithmically) correct without loss of precision.

This means when two numeric types are compared, the actual (mathematical) numbers that are represented by these objects are compared. For example the numeral 16677181699666569.0 (which is 3**34) represents the number 16677181699666569 and even though in "float-space" there is no difference between this number and 16677181699666568.0 (3**34 - 1) they do represent different numbers. Due to limited floating point precision, on a 64-bit architecture, the value float(3**34) will be stored as 16677181699666568 and hence it represents a different number than the integer numeral 16677181699666569. For that reason we have float(3**34) != 3**34 which performs a comparison without loss of precision.

This property is important in order to guarantee transitivity of the equivalence relation of numeric types. If int to float comparison would give similar results as if the int object would be converted to a float object then the transitive relation would be invalidated:

>>> class Float(float):
...     def __eq__(self, other):
...         return super().__eq__(float(other))
... 
>>> a = 3**34 - 1
>>> b = Float(3**34)
>>> c = 3**34
>>> a == b
True
>>> b == c
True
>>> a == c  # transitivity demands that this holds true
False

The float.__eq__ implementation on the other hand, which considers the represented mathematical numbers, doesn't infringe that requirement:

>>> a = 3**34 - 1
>>> b = float(3**34)
>>> c = 3**34
>>> a == b
True
>>> b == c
False
>>> a == c
False

As a result of missing transitivity the order of the following list won't be changed by sorting (since all consecutive numbers appear to be equal):

>>> class Float(float):
...     def __lt__(self, other):
...         return super().__lt__(float(other))
...     def __eq__(self, other):
...         return super().__eq__(float(other))
... 
>>> numbers = [3**34, Float(3**34), 3**34 - 1]
>>> sorted(numbers) == numbers
True

Using float on the other hand, the order is reversed:

>>> numbers = [3**34, float(3**34), 3**34 - 1]
>>> sorted(numbers) == numbers[::-1]
True

这篇关于Python 如何将“int"与“float"对象进行比较?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆