前言
在程序中,我们经常会涉及到数值计算操作,比如从最简单的数值的表示,到加、减、乘除,再到移位等等,而对于这些往往我们都信心十足,常常用直觉告诉自己:这么做没错!但是,计算机并不是靠直觉来感知数值的,它可是个很严谨的家伙,如果你只是用直觉告诉它你要做的事,那么它也会告诉你:哼!想要我帮你做事情,那么就按我的规则来吧! 想要知道计算机有哪些规则?那好,本篇就带你了解计算机关于信息表示和处理内容,但我们绝不是简单的了解,我同时还会揭开隐藏在数值计算中的陷阱,这样,在以后的编码过程中,我们就能避免可能的风险。
你可能会某一个瞬间蒙头写下如下代码intn =500*400*200*300;然后执行后发现结果居然是个负值,或者苦苦的等待循环退出。可能再回去看的时候才恍然大悟,哦,溢出了。亦或者你不明白这两个表达式的结果为什么不同?(3.14+1e20)-le20 ,3.14+(le20-le20).又或者意想类似这样的表达式会始终成立x*x>0,(x>0)||(x-1)<0, x<0 || -x>=0。噢,你可能会说从没遇到过这样的场景,或者说从来都是假设数据在一定的范围之内的,不会取到那么极端的数据。更何况那样的表达式不一定会用的到。我们会这么想,假设在数据取值的范围内,我们的计算没有任何差错,我们就以为程序是没有问题,而其实这离程序的”绝对正确”还差一步。你可能会反驳,追求绝对的正确有意义?我们始终能够满足业务要求就是正确的?更何况你那出现的情况几乎是不可能的?可能,我们还没遇到过由于数值计算的误差所带来的风险和损失,或者由于计算机某一程序的算术计算的微妙细节而产生的计算机安全漏洞,最终被黑客所利用。是的,这些情况出现的概率很低,但我们有必要深究保证程序的绝对正确,有必要深究数值计算的细节,因为关乎我们程序的正确性和安全性。
整数编码
我们先看C语言中支持的整数类型和它对应的取值范围:
说明:C语言标准只是定义了每种数据类型必须能够表示的最小的取值范围。
1. 无符号数的编码
假设一个整数数据类型有w位,位向量为x=[xw-1,xw-2,…..,x0]表示向量中的每一位,那么我们用下面的公式来表示无符号数:
其中B2Uw的范围{0,…….2w-1},最大值为UMaxw= 2w-1.
2. 补码编码
在计算机中,最常见的有符号数的负数值就是通过补码来表示的。同样我们也能给出补码的公式:
公式中最高有效为xw-1称为符号位,它的权重为-2w-1.符号位为1表示为负,否则为正数,下面我们看几个例子:
明白了补码运算,那么,让我们考虑下w位补码所能表示的值得范围。它能表示的最小值为位向量[1000…..0],其整数值为TMinw=-2w-1,而最大值为位向量[011111….1],其整数值为TMaxw =2w-1-1.
3.有符