Python 如何将“int"与“float"对象进行比较? [英] How does Python compare 'int' to 'float' objects?
问题描述
有关数字类型的文档指出:
<块引用>Python 完全支持混合算术:当一个二元算术运算符有不同数值类型的操作数时,具有较窄"类型的操作数被加宽到另一个类型的操作数,其中整数比浮点窄,浮点比复数窄.混合类型数字之间的比较使用相同的规则.
以下行为支持这一点:
<预><代码>>>>int.__eq__(1, 1.0)未实现>>>float.__eq__(1.0, 1)真的然而,对于大整数,似乎会发生其他事情,因为除非明确转换为 float
,否则它们不会比较相等:
另一方面,对于 2 的幂,这似乎不是问题:
<预><代码>>>>n = 2**512>>>浮动(n)== n真的因为文档暗示 int
被加宽"(我假设转换/转换?)到 float
我期望 float(n) ==n
和 float(n) == float(n)
是相似的,但上面带有 n = 3**64
的例子建议不同.那么 Python 使用什么规则来比较 int
和 float
(或一般的混合数字类型)?
使用 Anaconda 的 CPython 3.7.3 和 PyPy 7.3.0 (Python 3.6.9) 进行测试.
关于值比较的语言规范 包含以下段落:
<块引用>内置数字类型(数字类型 — int、float、complex
)和标准库类型 fractions.Fraction
和 decimal.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">数字类型的等价关系.如果 int
与 float
的比较会给出类似的结果,就好像 int
对象将被转换为 float
对象然后传递关系将无效:
另一方面,float.__eq__
实现考虑了所表示的数学数字,并没有违反该要求:
由于缺少传递性,以下列表的顺序不会因排序而改变(因为所有连续的数字似乎都相等):
<预><代码>>>>类浮动(浮动):... 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
,顺序相反:
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 typesfractions.Fraction
anddecimal.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屋!