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)

公众号【Python猫】, 本号连载优质的系列文章,有喵星哲学猫系列、Python进阶系列、好书推荐系列、技术写作、优质英文推荐与翻译等等,欢迎关注哦。

版权声明:本文版权归作者所有,遵循 CC 4.0 BY-SA 许可协议, 转载请注明原文链接
https://segmentfault.com/a/1190000020352477

灵魂导师 rms - 编程思维

Richard Matthew Stallman 教师节 今天是教师节, 专门查了一下, 发现 9.10 作为教师节, 1985年才确立; 对我人生影响最大的 "老师" 单人对整个世界发起进攻的 GNU 计划是在 1983年9月27日 ; 可惜, 直到 2002 年, 我才真正接触到 RMS 的思想/言行, 从而发生彻

用 python 生成有“灵魂”的二维码 - 编程思维

本文作者:HelloGitHub-LITTLECHIEH 这是 HelloGitHub 推出的《讲解开源项目》系列,今天给大家推荐一个 Python 开源生成二维码的项目——qrcode 一、介绍 1.1 二维码 二维码又称二维条码,常见的二维码为 QR Code,QR 全称 Quick Response。是一个近几年

markdown编辑器 - 编程思维

说起Markdown,肯定很多人都接触过。它是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式。真的是简单又实用哟~ 现在很多网站都在使用Markdown 来撰写帮助文档或是用于论坛上发表消息。例如:简书、reddit、GitHub、Diaspora、Stack Exch

python字符串中删除特定字符 - 编程思维

分析 在Python中,字符串是不可变的。所以无法直接删除字符串之间的特定字符。所以想对字符串中字符进行操作的时候,需要将字符串转变为列表,列表是可变的,这样就可以实现对字符串中特定字符的操作。 1、删除特定字符 特定字符的删除,思路跟插入字符类似。 可以分为两类,删除特定位置的字符 或者 删除指定字符。 1.1、删

好程序员python学习路线分享实现快速排序算法 - 编程思维

  好程序员Python学习路线分享实现快速排序算法快速排序算法是一种基于交换的高效的排序算法,由C.R.A.Hoare于1962年提出,是一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide and conquer algorithm)。 分治法的基本思想 将原问题分解为若干个规模更小但结构与原问

快速入门 python 数据分析实用指南 - 编程思维

Python 现如今已成为数据分析和数据科学使用上的标准语言和标准平台之一。那么作为一个新手小白,该如何快速入门 Python 数据分析呢? 下面根据数据分析的一般工作流程,梳理了相关知识技能以及学习指南。 数据分析一般工作流程如下: 数据采集 数据存储与提取 数据清洁与预处理 数据建模与分析 数据可视化 1.数据

numba,让python速度提升百倍 - 编程思维

python由于它动态解释性语言的特性,跑起代码来相比java、c++要慢很多,尤其在做科学计算的时候,十亿百亿级别的运算,让python的这种劣势更加凸显。 办法永远比困难多,numba就是解决python慢的一大利器,可以让python的运行速度提升上百倍! 什么是numba? numba是一款可以将pytho

python 的科学计算生态 - 编程思维

科学计算的开山之石:Python 第一章 Python 的科学计算生态 1.1 为什么是选择Python? 1.1.1 科学人员的需求 获取数据(模仿,验证控制) 操作、处理数据 易于反映问题的结果可视化和高质量适于发布的图形 1.1.2 Python的长处 丰富的基础数据处理方法,图形和数据处理工具,不需要重复

python科学生态之 numpy - 编程思维

未经许可,不得转载时间:2020年1月17日17:33:15 created by:Tower使用JupyterNotebook编辑 0x00 前言(NumPy 的设计理念) 对于一个技术的使用或许记背几个常用的函数和基本用法便好,但要理解一个技术和工具,设计理念便是其内核之一,就是文章诗词的风骨,嚼起来才有味道,

简单瞅瞅 numpy库transpose函数 - 编程思维

写在前面 接我的上一篇博客, 嘿嘿, 应该能看懂吧,如果numpy数组的维度懂了那就好理解transpose了 代码说话 transpose就是转置的意思,函数返回按你指定的方式转置的矩阵 np.transpose(narray, axis=None) 举个例子感性理解一下: >>> a = np.a

numpy数组维度理解终结版 - 编程思维

写在前面 可能你会不相信,我是从玩pytorch中过来的,我觉得有必要记录一下,transpose这个坑还非踩不可,为了说的清楚一点儿,我多铺垫一点儿,先说说numpy数组维度的理解 引子 >>> a = np.arange(start=0, stop=24) array([ 0, 1, 2,

python 中使用 c 代码:以 numpy 为例 - 编程思维

这个章节包含许多在python代码中支持c/c++本机代码的许多不同方法, 通常这个过程叫作包裹(wrapping)。本章的目的是让您大致知道有那些技术和它们分别的优缺点是什么,于是您能够为您自己的特定需要选择何时的技术。在任何情况下,一旦您开始包裹,您几乎一定将想要查阅您所选技术各自的文档。 简介 本章节包含以下