Подтвердить что ты не робот

Почему numpy целочисленное вычитание создает float64?

В numpy, почему вычитание целых чисел иногда приводит к номерам с плавающей запятой?

>>> x = np.int64(2) - np.uint64(1)
>>> x
1.0
>>> x.dtype
dtype('float64')

Кажется, что это происходит только при использовании нескольких разных целых типов (например, подписанных и неподписанных) и когда не существует более крупного целочисленного типа.

4b9b3361

Ответ 1

Это сознательное дизайнерское решение авторов numpy. При выборе результирующего типа учитываются только типы операндов, а не их фактические значения. И для операции, которую вы выполняете, существует риск получить результат вне допустимого диапазона, например. если вы вычтите очень большое число uint64, результат не будет соответствовать int64. Таким образом, безопасный выбор преобразуется в float64, что, безусловно, будет соответствовать результату (возможно, с уменьшенной точностью).

Сравните с примером x = np.int32(2) - np.uint32(1). Это всегда можно безопасно представить как int64, поэтому выбран этот тип. То же самое верно для x = np.int64(2) - np.uint32(1). Это также даст int64.

Альтернативой будет следовать, например, правила c, которые будут отбрасывать все на uint64. Но это может, конечно, привести к очень странным результатам с превышением/недостатками.

Если вы хотите заранее знать, какой тип вы закончите, просмотрите np.result_type(), np.can_cast() и np.promote_types(). Чтение об этом в документах также может помочь вам понять проблему немного лучше.

Ответ 2

Я не эксперт по numpy, однако, я подозреваю, что поскольку float64 - это наименьший тип данных, который может соответствовать как домену int64, так и uint64, что вычитание преобразует оба операнда в float64 так что операция всегда будет успешной.

Например, в с int8 и uint8: +128 - (256) не может поместиться в int8, так как -128 недействителен в int8, так как он может только вернуться к -127. Точно так же мы не можем использовать a uint8, поскольку в этом случае нам явно нужен знак. Следовательно, мы устанавливаем на float/double, так как он отлично подходит для обоих направлений.