В документации о числовых типах указано следующее:
Python полностью поддерживает смешанную арифметику: когда двоичный арифметический оператор имеет операнды разных числовых типов, операнд с «более узким» типом расширяется до другого, где целое уже, чем с плавающей запятой, которое уже, чем сложное. При сравнении чисел смешанного типа используется одно и то же правило.
Это подтверждается следующим поведением:
>>> int.__eq__(1, 1.0)
NotImplemented
>>> float.__eq__(1.0, 1)
True
Однако для больших целых чисел, похоже, происходит что-то еще, поскольку они не будут сравниваться равными, если они не будут явно преобразованы в float
:
>>> n = 3**64
>>> float(n) == n
False
>>> float(n) == float(n)
True
С другой стороны, для степеней двойки это не кажется проблемой:
>>> n = 2**512
>>> float(n) == n
True
Поскольку в документации подразумевается, что int
"расширяется" (я полагаю, преобразовано/приведено?) до float
, я ожидаю, что float(n) == n
и float(n) == float(n)
будут похожи, но приведенный выше пример с n = 3**64
предполагает другое. Итак, какие правила использует Python для сравнения int
с float
(или вообще смешанных числовых типов)?
Протестировано с CPython 3.7.3 от Anaconda и PyPy 7.3.0 (Python 3.6.9).
float(3**64)
не совсем равноint(3**64)
. - person deceze♦   schedule 31.01.2020float(2**512)
, с другой стороны, может быть представлено точно, несмотря на то, что он намного больше, потому что это степень числа 2. Мантиссе требуется только 1 бит для полной точности, и экспоненте нужно только 9. - person chepner   schedule 31.01.2020int
, будет расширен до другого, в данном случаеfloat
. Таким образом, не должно быть проблем с потерей точности из-за кругового отключения; Я ожидаю, чтоfloat(n) == n
будет внутренне обработан так, что r.h.s. преобразуется вfloat
, т. е. становится похожим наfloat(n) == float(n)
. - person a_guest   schedule 31.01.20203**64
сравнивается сfloat(n)
, оно не преобразуется вfloat
. Скорее точное математическое значение3**64
сравнивается с точным математическим значениемfloat(n)
. Поскольку они различаются, результат равенFalse
. Когда вы конвертируете3**64
вfloat
, оно преобразуется в значение, представляемое в типеfloat
, что приводит к некоторой ошибке. В документации неудачно сказано, чтоfloat
«шире», чемint
. Как правило, он не может представлять все значенияint
… - person Eric Postpischil   schedule 31.01.2020int
и все значенияfloat
, этой документации. - person Eric Postpischil   schedule 31.01.2020factorial(512) + 1.0
жалуется, что int слишком велик. - person Masklinn   schedule 31.01.2020float
? - person a_guest   schedule 31.01.2020int
является память вашего компьютера, аfloat
привязан к 64 битам, я думаю, что значение терминов «широкий» и «узкий» не следует воспринимать слишком буквально, а скорее следует рассматривать в рамках собственное определение документации для них, которое является целым числом, уже, чем с плавающей запятой, которое уже, чем сложное. Таким образом, после этого определенияint
действительно должно быть преобразовано вfloat
или, по крайней мере, результаты должны быть такими же, как если бы это было так, но фактическое поведение кажется другим. - person a_guest   schedule 31.01.20203**64
равен 3433683820292512484657849089281. Результатfloat(3**64)
равен 3433683820292512441173561835520. Они не равны, поэтому3**64 == float(3**64)
ложно. - person Eric Postpischil   schedule 31.01.2020float
было преобразовано вint
(а не наоборот)? Глядя на исходный код, преобразованиеfloat
кажется произойдет, еслиint
использует меньше или равно 48 битам. Действительно, проверкаn = 3**33
иn = 3**34
, похоже, связана с круговым обходомint(float(n)) == n
. - person a_guest   schedule 31.01.2020float(3**64)
. Преобразование из числа с плавающей запятой в целое число может привести к потере информации, поскольку целое число не представляет собой дробные части. Насколько мне известно, код сравнения, на который ссылается другой комментарий выше, эффективно сравнивает точные математические значения. Для этого не нужно делать полное преобразование. Еслиn
— целое число, аf
—float
, не являющееся NaN, то каждое из них представляет определенное число,… - person Eric Postpischil   schedule 31.01.2020n == f
оценивается какTrue
тогда и только тогда, когда они представляют одно и то же число. - person Eric Postpischil   schedule 31.01.20203**34
(то есть16677181699666569
) равно просто16677181699666569.0
, хотя это не может быть точно представлено вfloat
, посколькуfloat(3**34)
равно16677181699666568.0
, что также является его точным математическим значением. Преобразованиеint(float(3**34))
, следовательно, дает16677181699666568
, то есть3**34 - 1
. Однако, выполняя побитовый анализ задействованных чисел, можно получить доступ к этим точным значениям без необходимости преобразования в какой-либо тип данных. Это то, что происходит? - person a_guest   schedule 31.01.202016677181699666569
и16677181699666569.0
— это числа, которые также представляют это число. (Числа — это строки символов, представляющие числа. На самом деле они не являются числами, так же как слово «лиса» не является лисой.) - person Eric Postpischil   schedule 31.01.2020