Python 的整数与 Numpy 的数据溢出
某位 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 的多,相互间的区分界限很多样:
截图来源:https://www.runoob.com/numpy/numpy-dtype.html
要解决整数溢出问题,可以通过指定 dtype 的方式:
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]
好了,前面提出的问题就回答完了。来作个结尾吧:
- Python 3 极大地简化了整数的表示,效果可表述为:整数就只有一种整数(int),没有其它类型的整数(long、int8、int64 之类的)
- Numpy 中的整数类型对应于 C 语言的数据类型,每种“整数”有自己的区间,要解决数据溢出问题,需要指定更大的数据类型(dtype)
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
源码分析RocketMQ ACL实现机制
有关RocketMQ ACL的使用请查看上一篇《RocketMQ ACL使用指南》,本文从源码的角度,分析一下RocketMQ ACL的实现原理。 备注:RocketMQ在4.4.0时引入了ACL机制,本文代码基于RocketMQ4.5.0版本。 根据RocketMQ ACL使用手册,我们应该首先看一下Broker服务器在开启ACL机制时如何加载配置文件,并如何工作的。 1、BrokerController#initialAcl Broker端ACL的入口代码为:BrokerController#initialAcl private void initialAcl() { if (!this.brokerConfig.isAclEnable()) { // @1 log.info("The broker dose not enable acl"); return; } List<AccessValidator> accessValidators = ServiceProvider.load(ServiceProvider.ACL_VALIDATOR_ID, AccessVa...
- 下一篇
数据结构与算法之约瑟夫问题
约瑟夫问题介绍: 据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。 编程描述: 有N个孩子手拉手围成一圈,从第M个孩子开始报数,报到第K个孩子出队,然后从下一个孩子继续开始报数,问:所有孩子的出队顺序?如下图: 约瑟夫问题的数据结构引出:图 1-1: 问:用什么数据结构来处理这个问题比较合适呢?我们不妨将图1-1稍作处理,如下图1-...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Hadoop3单机部署,实现最简伪集群
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- 设置Eclipse缩进为4个空格,增强代码规范
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Windows10,CentOS7,CentOS8安装Nodejs环境
- CentOS7设置SWAP分区,小内存服务器的救世主
- CentOS关闭SELinux安全模块
- SpringBoot2更换Tomcat为Jetty,小型站点的福音