C语言数字表示

c语言中关于数字的知识点有一些是非常有用的,但是又容易忘,我在这里就想简单的总结一下(这里没有给出详细证明)。

一、c语言整数表示

(一)、有符号数和无符号数之间的转化

c语言允许不同的数字类型之间做强制类型转换,那转换的规则就是我们需要知道的,将一个有符号数t(int)转化成无符号数u(unsigned int),或者相反,会得到什么结果呢?我们想要的结果当然是数值保持不变。

请先记住关键的一点,强制类型转换的结果保持位值不变,只是改变了解释这些位的方式。

为了简单假设int_类型只有四个比特,举个例子:

1. int   ----->  unsigned int

int_ a = -8; // 在内存中的实际存储形式,补码:1000 (假设就是使用补码的机器)

unsigned int_ b = (unsigned int_)a; // b所对应的内存中还是1000,以无符号数的规则解释就是8

2. unsigned int -------> int

unsigned int_ a = 15; // 1111

int_ b = (int_)a; // 1111以有符号数规则解析就是负数-1

C 标准没有精确规定应如何进行这种转换,但大多数系统遵循的原则是底层的位表示保持不变

还有一点要注意就是:当执行一个运算时,如果一个操作数是有符号数,另一个是无符号数,则会隐式的将有符号数转化为无符号数。

(二)、扩展数字的位

当一个数据类型转换为更大的数据类型是会发生位的拓展。

1.无符号数的扩展

要将一个无符号数转换为一个更大的数据类型, 我们只要简单地在表示的开头添加 0。这种运算被称为零扩展

2.有符号数的扩展:

要将一个补码数字转换为一个更大的数据类型,可以执行一个符号扩展, 在表示中添加最高有效位的值。

(三)、截断数字

将一个较大的数据类型转化为较小的数据类型也是很常见的,但是截断可能会改变数字的值(这也是溢出的一种形式)

1.截断无符号数:

假设a是一个w位的无符号数,把它截断为k位的数字b,则b = a % (2^k)。

原理很简单,所有被截去的位的权重都是2^i,i >= k,每一位的值取模之后都是零。

2.截断有符号数:

有符号数截断跟无符号数的行为几乎一样,至需要按照无符号数的截断方式截断,最后把截断之后的最高位转化成符号位就可以了。

(四)、整数运算溢出(这里是加法的例子)

1.无符号数溢出

设x,y都是无符号数,w为位数,当x + y < 2^w时,x + y = x + y;当x + y >= 2 ^ w时,x + y = x + y - 2 ^ w(就是正常按位相加,最后截断超过w的位)。

还有一个判定是否溢出的方法:设x + y = s,如果s < x(或x < y),则发生了溢出。

简单证明:观察得x + y >= x,所以如果未溢出则s >= x,而如果溢出了则s = x + y - 2^w,又因为y - 2 ^ w < 0,所以s < x。

2.有符号数溢出:

设x,y都是无符号数,w为位数,当x + y < 2^(w-1)时,x + y = x + y + 2^w;当-2^(w-1)<=x+y<2^(w-1)时,x + y = x + y;当x + y >= 2 ^ (w-1)时,x + y = x + y - 2 ^ w。

补码加法跟无符号数加法有着相同的位级表示,所以可以将操作数转化为无符号数,进行加法操作,最后将计算结果转化为有符号数。

判定是否溢出:设Min是有符号数最小值,Max为最大值,根据上面公式可知,前提Min<=x,y<=Max,x + y = s,当且仅当x > 0,y > 0,但s<=0时,发生了正溢出;当且仅当x < 0,y < 0,但s>=0时,发生了正溢出。

这个就不给证明了,显而易见。

3.补码的非

Min<=x<=Max范围的每个数字都有自己的加法逆元,对于Min的非(也就是逆元)是自己,对于其他的数x的非是-x。

证明:设w为位数,Min+Min = -2^(w-1)+(-2^(w-1)) = -2^w,这将会发生溢出,有前面可知,负溢出需要加个2^w,所以Min+Min = -2^w + 2^w = 0;对于非Min的数,x + (-x) = 0。

 二、浮点数表示

(一)、IEEE(电气和电子工程师协会)浮点数表示

IEEE浮点标准用V = (-1)^s * M * 2^E的形式来表示一个浮点数。

符号:s用来标识符号位,除了数值为0的数字外,s用来标识一个数是正数(s=0)还是负数(s=1);

尾数:M是一个二进制小数,范围是1~2-ε或0~1-ε;

阶码:E是对浮点数加权,这个权重是2的ε次幂。

一个单独的位s编码符号s,k位的阶码字段e编码E,n位的尾数字段m编码尾数M。

在c语言中float(单精度浮点数)的s=1,k=8,n=23,double(双精度浮点数)的s=1,k=11,n=52。

根据阶码字段e的不同,可以分成三种情况:

1.规格化的

1)即阶码域位模式既全不为0,又全不为1。

2)阶码字段e被解释为以偏置形式表示的有符号整数,定义为E=e-bias,bias为2^(k-1)-1的偏置值。

3)尾数字段m被解释为小数值b,且0<=b<1,在这种情况下,尾数定义为M=b+1,即隐含的以1开头的表示,因为这种情况下小数总是以1开头,所以不需要显示的表示。

2.非规格化的

1)即阶码域位模式全为0。

2)阶码值定义为E=1-bias。

3)尾数值M=m,不隐式的包含1,所以0<=M<1。

3.特殊值

1)即阶码域位模式全为1。

2)当小数域m全为0时表示无穷大,当s=0时,表示正无穷大;当s=1时,表示负无穷大。

3)当小数域m全为1时为NaN,即Not a Number(不是一个数)。

(二)、浮点运算

浮点运算不具有结合性。例如,使用单精度浮点, 表达式(3.14+1e10)-1e10求值得到 0.0— 因为舍入,值 3.14 会丢失。另一方面, 表达式 3.14+(1e10-1e10)得出值 3.14。

浮点乘法在加法上不具备分配性。例如,单精度浮点情况下, 表达式1e20*(1e20-1e20)求值为 0.0, 而 1e20*1e20-1e20*1e20 会得出NaN(+∞-∞=NaN)。

浮点加法满足了单调性属性:如果 那么对于任何 a >= b,那么对于任何a、b以及x的值,除了NaN,都有x+a>=x+b(即使相加都为无穷大)。无符号或补码加法不具有这个实数(和整数)加法的属性。

(三)、int、float 和 double 格式之间进行强制类型转换

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

2.从 int 或 float 转换成 double,因为 double 有更大的范围,也有更高的精度,所以能够保留精确的数值。
3.从 double 转换成 float,因为范围要小一些,所以值可能溢出成+∞或-∞。另外,由于精确度较小,它还可能被舍人。

4.从 float 或者 double 转换成 int,值将会向零舍入。

  • 15
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清墨书晚风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值