冷知识 | 为什么招行消费金额排名第一位显示"负数"?

先插入一条快讯:对于信息泄露事件,招行终于有所行动了!短信为证:


招行安全提示

作为消费排名第50多万的我倍感欣慰,我猜,榜上前50名持卡人应该也会在海量的骚扰短信中找到这条提醒,并好好保护好自己的银行卡安全呢_

下面回到主题:
问:为什么招行消费金额排名第一位显示"负数"?
答:因为他/她刷到了2147483647元


招行消费金额排名

先看下维基百科上对这个数字的解释:


2147483647@wikipedia

我们再来看一段来自维基百科“天书” (计算机相关专业好好上课的剁友请笑而不语)~

在计算机科学中,整数的概念指数学上整数的一个有限子集。它也称为整数数据类型,或简称整型数、整型。通常是程序设计语言的一种基础数据类型,例如java及C 编程语言的int 数据类型,然而这种基础数据类型只能表示有限的整数,其范围受制于电脑的一个字组所包含的比特数所能表示的组合总数。当运算结果超出范围时,即出现演算溢出,微处理器的状态寄存器中的溢出旗标(overflow flag)会被设置,而系统则会产生溢出例外(overflow exception)或溢出错误(overflow error)。
电脑可处理带号(signed)及非带号(unsigned)整数,非带号整数不包括负数。由于一般情况下要同时处理正数及负数,带号整数把字组的最高有效比特(msb,即最左边的比特)视为正负号(0代表正,1代表负),而数字则以补码形式编码,以简化二进制运算的逻辑电路。

好了,看到这里,我猜各位剁友一定更加清(meng)晰(bi)了~ 下面我开始说“人话”~
当一条数据在计算机内生成时,它会占用计算机的一部分可用内存,当数字越大它会需要更多存储位。一台(CPU)32位机中最大的整型常量就是2,147,483,647(二十一亿四千七百四十八万三千六百四十七),它等于2^31-1 (为什么不是2^32? 因为第一位要放正负号,0代表正,1代表负)。

当排名第1的这位招行持卡人正好刷到过2,147,483,647元时,
计算机存储的数值为: 01111111111111111111111111111111 (一个“0”后面三十一个“1”)
当他/她再刷1元时,计算机存储为: 0000000000000000000000000000000( 三十二个“0”)
显示消费金额变成了0!

再再刷1元时,计算机存储为: 1000000000000000000000000000000 (一个“1”后面三十一个0)
还是0,因为"-0"还是0

...
再后面刷的,就会“显示”为负数。
那为什么负数还能显示到排名第一位呢?
因为只是排名程序用了32位的int, 而后台的程序用的int64,可以存储大得多的数,而不会溢出。int64即有符号 64 位整数数据类型,相当于C++中的long long、 C# 中的 long 和 SQL Server 中的 bigint,可以存储最大2^63-1(+9,223,372,036,854,775,807)的整数。
也就是缩,这位持卡人实际消费的金额是2,147,483,647+2+1,105,940=2,148,589,589元!(21亿多)

2014年上海藏家刘益谦刷卡支付2.8亿购买鸡缸杯,已经让羊毛哥大开眼界:


百夫长黑卡持卡人

这个数量级的钱还能买什么羊毛哥并没有概念,微博上的搜到的价值21亿的是波音787:


波音787宽体客机被中国买家匿名购买

回顾历史,因为计算机位存储位数不足而发生的事故和错误其实不只一次,众所周知的千年虫问题之外,还有很多案例。

阿丽亚娜5型运载火箭坠毁:
1996年6月4日,阿丽亚娜5型运载火箭的首次发射点火后,火箭开始偏离路线,最终被逼引爆自毁,整个过程只有短短30秒。阿丽亚娜5型运载火箭基于前一代4型火箭开发。在4型火箭系统中,对一个水平速率的测量值使用了16位的变量及内存,因为在4型火箭系统中反复验证过,这一值不会超过16位的变量,而5型火箭的开发人员简单复制了这部分程序,而没有对新火箭进行数值的验证,结果发生了致命的数值溢出。发射后这个64位带小数点的变量被转换成16位不带小数点的变量,引发了一系列的错误,从而影响了火箭上所有的计算机和硬件,瘫痪了整个系统,因而不得不选择自毁,4亿美金变成一个巨大的烟花。

阿丽亚娜5型运载火箭

PayPal系统错误:
2013年7月PayPal因系统错误而从用户Chris Reynolds的账号上扣除了92233万亿美元(具体扣除的金额是92,233,720,368,547,940.25美元,比2^63
− 1美分多出了182.18美元,扣除后账户余额为-92,233,720,368,547,800.00美元;相比之下,2012年美国全国的GDP总额“只有”16.24万亿美元[1]
)。PayPal后来更正了这一错误,并承诺将向Chris Reynolds指定的慈善团体提供一份捐助[2]。

Chris Reynolds账单

羊毛哥想说,错了,就是错了,为什么一份公开道歉这么艰难?

参考资料
[1] 2012年各国GDP统计 -- 世界银行
[2] PayPal Glitch Actually Put Man $92 Quadrillion in the Red. Daily Finance. 2013 [18 September 2013].

推荐阅读更多精彩内容