本篇博客将阐述、讨论的内容:

int

      int的范围根据计算机的不同存在16位或32位的差异,以16位举例,最大值为1111 1111 1111 1111,也就是65535,如果出现65536,就会溢出。

     ●unsigned int(无符号整型)

      以16位系统为例,unsigned int能存储的数据范围是0~65535(需要注意整数是以补码形式存放)。其进行的是模数计算,也就是所谓的二进制相加减,计算方法和十进制加减并无区别,但是unsigned int有着正溢出和负溢出的问题。

      对于正溢出与负溢出,诸多基础概念便不再赘述,不懂的朋友可以去回顾计算机组成原理的相关知识。

这里仅举出一个负溢出的例子:

进行自然丢弃后,可知结果为0。很明显,产生了负溢出。

     ●接下来,我们说说unsigned int和int的相互转化,代码如下:

float sum_elements(float a[],unsigend length){
    float result = 0;
    for(int i = 0; i <= length - 1; i++){
        result += a[i];
        return result;
    }
}

      很显然,计算一个数组所有元素之和。但当数组为空时,length输入0,会返回一个存储器错误。为什么呢?请看unsigned int的计算,length是unsigned int 类型,进行的是模数运算,只代表正数,如果出先了0000000(这里有32个0)-00000..01(31个0,1个1)=111…11111(32个1)=UMAX。一个本该为-1的数变成了无符号数最大值,当i取任何不为0的数都发生了非法访问,自然出现了存储器错误,并且任何数都小于UMAX,出现判别式永远为真,进入死循环。解决办法有两种,做一个判断,当传入length<1,直接返回0 or 在之前就将length转化为int。

浮点数

     ●定点数以及定点数的缺点

      用10进制表示小数早已司空见惯,那么就会想要对二进制做同样的操作,为它也加上小数点。

但是如此的二进制小数,会出现一些问题不可避免

​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​
整数部分小数部分二进制(Representation)
53/4$101.11_2 $
27/8$10.111_2$
17/16$1.0111_2$

很明显可以发现,只能准确的表示 (x/2^k) 的小数,而不为 (x/2^k) 只能近似。

​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​
十进制小数部分二进制(Representation)
1/3$0.01010101[01]… _2$
1/5$0.001100110011[0011]… _2$
1/10$0.0001100110011[0011]… _2$
而为什么会出现如上结果,就要知到1/3 和 1/5是如何计算的。

由此可见,当小数无法描述(x/2^k)时,二进制小数便只能取近似值(多采用close to even(靠近偶数))。

这就暴露定点数的一个重要缺点 ---- 定点数无法标准化。也就是说,关于小数点的位置无法给出一个标准的定点数计算方式,不同小数点的位置给计算定点数增加了难度。与此同时,定点数表示的范围有限,32位的定点数,假设没有整数位,那么所能表示的小数的最小值为:2-32,而32位浮点数仅指数位便可以表示到2-126,由此不难看出,定点数虽然精度高,但标准化和范围大小都比较差。

所以此时便引出了浮点数来统一二进制小数的表示:

注:s:表示符号位,只用一个bit表示

M:表示尾数(significand)(frac)也表示小数位,即能准确表示小数位

E:表示指数位。

常用的float,double组成:

可以看出float有8位指数位,23位尾数位。指数最大可表示的范围为-127~126

浮点数所表示的一个范围:

可以得到,浮点数随着大小的不同被分为不同种类,接近0的称为Denormalized,较大的数字被分为Infinity。(关于Denormalized、Infinity等名词请自行了解,这里不再做过多的赘述)。

Denormalized到NaN的变化:

浮点数相加的公式:

浮点数的加法和乘法由于近似的原因,经常无法实现加法的结合律和乘法分配律,如下所示:

(3.14+le10)-1e10=0.0,因为3.14+1e10会舍入,3.14会丢失(1e10表示1*101010)

然而3.14+(1e10-1e10)=3.14

le20*(le20-le20)=0.0

le20le20-le20le20=NaN,由于溢出的关系,可见在数字大的情况下不满足加法结合律和乘法分配律。

最后,关于int,float,double之间相互转换可能的问题:

当在int,float以及double格式之间进行强制转换时,程序改变数值和位模式的原则如下(假设int为32位):

●从int转换成float,数字不会溢出,但可能被舍入。

●从int或float转换成double,因为double有更大的范围(也就是可表示值得范围),也有更高得精度(即有效位数),所以能保留精确得数值。

●从double转换成float,因为范围要小一些,所以值可嫩溢出为+∞或-∞。且由于精度较小,它还可能被舍入。

●从float或double转换成int,值将会向0舍入。例如1.999将转换为1。进一步说,值可能会溢出。C语言标准没有对这种情况指定固定的结果。而与Inter兼容的微处理器指定位模式[10…00](字长为ω时的TMinω)为整数不确定值。一个从浮点数到整数的转换,如果不能为该浮点数找到一个合理的整数近似值,就会产生一个这样的值。因此,表达式(int)+le10会得到-21483648,即从一个正值变成了一个负值。

参考博主:写代码的柯长(CSDN)、Jamesjiang2050(博客园)

内容来源于网络如有侵权请私信删除

文章来源: 博客园

原文链接: https://www.cnblogs.com/RpgMaker/p/13896060.html

你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!