某位 A 同学发了我一张截图, 问为何结果中出现了负数?
看了图, 我第一感觉就是数据溢出了. 数据超出能表示的最大值, 就会出现奇奇怪怪的结果.
然后, 他继续发了张图, 内容是 print(100000*208378), 就是直接打印上图的 E[0]*G[0], 结果是 20837800000, 这是个正确的结果.
所以新的问题是: 如果说上图的数据溢出了, 为何直接相乘的数却没有溢出?
由于我一直忽视数据的表示规则(整型的上限是多少?), 而且对 Numpy 了解不多, 还错看了图中结果, 误以为每一个数据都是错误的, 所以就解答不出来.
最后, 经过学习群里的一番讨论, 我才终于明白是怎么回事, 所以本文把相关知识点做个梳理.
在正式开始之前, 先总结一下上图会引出的话题:
Python 3 中整数的上限是多少? Python 2 呢?
Numpy 中整数的上限是多少? 出现整数溢出该怎么办?
关于第一个问题, 先看看 Python 2, 它有两种整数:
一种是短整数, 也即常说的整数, 用 int 表示, 有个内置函数 int(). 其大小有限, 可通过 sys.maxint() 查看(取决于平台是 32 位还是 64 位)
一种是长整数, 即大小无限的整数, 用 long 表示, 有个内置函数 long(). 写法上是在数字后面加大写字母 L 或小写的 l, 如 1000L
当一个整数超出短整数范围时, 它会自动采用长整数表示. 举例, 打印 2**100 , 结果会在末尾加字母 L 表示它是长整数.
但是到了 Python 3, 情况就不同了: 它仅有一种内置的整数, 表示为 int, 形式上是 Python 2 的短整数, 但实际上它能表示的范围无限, 行为上更像是长整数. 无论多大的数, 结尾都不需要字母 L 来作区分.
也就是说, Python 3 整合了两种整数表示法, 用户不再需要自行区分, 全交给底层按需处理.
理论上, Python 3 中的整数没有上限(只要不超出内存空间). 这就解释了前文中直接打印两数相乘, 为什么结果会正确了.
PEP-237(Unifying Long Integers and Integers)中对这个转变作了说明. 它解释这样做的 目的:
这会给新的 Python 程序员 (无论他们是否是编程新手) 减少一项上手前要学的功课.
Python 在语言运用层屏蔽了很多琐碎的活, 比如内存分配, 所以, 我们在使用字符串, 列表或字典等对象时, 根本不用操心. 整数类型的转变, 也是出于这样的便利目的.(坏处是牺牲了一些效率, 在此就不谈了)
回到前面的第二个话题: Numpy 中整数的上限是多少?
由于它是 C 语言实现, 在整数表示上, 用的是 C 语言的规则, 也就是会区分整数和长整数.
有一种方式可查看:
- import numpy as np
- a = np.arange(2)
- type(a[0])
- # 结果: numpy.int32
也就是说它默认的整数 int 是 32 位, 表示范围在 -2147483648 ~ 2147483647.
对照前文的截图, 里面只有两组数字相乘时没有溢出: 100007*4549,100012*13264, 其它数据组都溢出了, 所以出现奇怪的负数结果.
Numpy 支持的数据类型要比 Python 的多, 相互间的区分界限很多样:
- import numpy as np
- q = [100000]
- w = [500000]
- # 一个溢出的例子:
- a = np.array(q)
- b = np.array(w)
- print(a*b) # 产生溢出, 结果是个奇怪的数值
- # 一个解决的例子:
- c = np.array(q, dtype='int64')
- d = np.array(w, dtype='int64')
- print(c*d) # 没有溢出:[50000000000]
来源: https://www.cnblogs.com/pythonista/p/11503117.html