计算机基础知识整理
⽂章⽬录
1、单位换算
电脑世界是由 0 与 1 组成,其中有数以万计的线路,⼀条线路传递⼀个信号,⽽ 0 代表没有信号,1 代表有信号,就像电源开关⼀样,同⼀时间只可能有⼀种状态,所以电脑最基本的单位就是⼀条线路的信号,我们就把它称作 “位” ,英⽂叫做 bit,缩写为 b。
“位”和“字节”其实都是电脑的计量单位,我们可以理解成字节是由位组成的,⼀个字节等于8 位。
“位”(bit)这个单位太⼩,所以字节 (Byte) 是电脑存储容量的基本计量单位。Byte 可简写为B,⼀个字节由⼋个⼆进制位组成,其最⼩值为0,最⼤值为11111111。
单位之间的换算关系为:
Kilo K
1K 字节 =1024个字节(B)
Mega M
1M 字节 = 1024 K=1024 * 1024= 1048576 字节
Giga G
1G字节 =1024 M=1024 * 1024 * 1024 = … …
Tera T
1T 字节 = 1024 G = = … …
bigdecimal取值范围Peta P
1P 字节 = 1024 T … …
Exa E
E字节= 1024P … …
Zetta Z
1Z字节 = 1024E = … …
Yotta Y
1Y字节= 1024 Z = … …
计算机存储容量⼤⼩以字节数来度量,1024 进位制:
1024B=1K(千)B
1024KB=1M(兆)B
1024MB=1G(吉)B
1024GB=1T(太)B
2、表⽰数的基本编码⽅式
在⼆进制世界中,表⽰数的基本编码⽅式有 原码、反码 和 补码 三种。
原码:
符号位和实际值的结合。正数数值部分是数值本⾝,符号位为 0;负数数值部分是数值本⾝,符号位为 1 (0 正 1 负) 。 8 位⼆进制数的表⽰范围是 [-127,127]。
反码:
正数数值部分是数值本⾝,符号位为 0;负数的数值部分是在正数表⽰的基础上对各个位取反,符号位为 1 。8 位⼆进制数的表⽰范围是 [-127,127]。
补码:
正数数值部分是数值本⾝,符号位为 0;负数的数值部分是在正数表⽰的基础上对各个位取反后加 1 ,符号位为 1。8 位⼆进制数的表⽰范围是 [-128,127]。
补码不仅能解决运算的问题,⽽且在占⽤相同位数的条件下,补码的表达区间⽐原码和反码的⼤。
⼆进制整数最终是以补码形式出现的。
3、位移运算
>>> ⽆符号向右移动
(不存在 <<< ⽆符号向左移动),⽆符号即藐视符号位,符号位失去特权,正负数⾼位均补 0 .。正数不断向右移动的最⼩值是 0,⽽负数不断向右移动的最⼩值是 1 。(点解呢? 在实际编程中,位移运算仅⽤于整型 (32 位) 和 长整型 (64位)数上,假如在整型数上移动的位数是字长的整数倍,⽆论是否带符号位以及移动⽅向,皆为本⾝。因为对于整型,移动的位数是⼀个 mod 32 的结果,即 35>>1 与 35 >> 33 是⼀样的结果。如果是长整型,mod64 ,即 35 <<1 与 35 << 65 的结果是⼀样的。 负数在⽆符号往右移动 63 位时,除最右边为 1 外,左边均为 0,达到最⼩值 1 ,如果 >>> 64,则为原数本⾝。)
逻辑或、逻辑与运算只能对布尔类型的条件表达式进⾏运算。7 && 8 这种运算表达式是错误的。
4、浮点数
计算机定义了两种⼩数,定点数【⼩数点位置固定,在确定字长的系统中⼀旦指定⼩数点的位置后,它的整数部分和⼩数部分也随之确定,所以定点数能表⽰的范围⾮常有限。】和浮点数。
浮点数表⽰就是如何⽤ ⼆进制 表⽰符号位、有效数字 和 指数。
如,-4.86e9 等价于 -4.86 ✖ 10 ⁹ 。科学计数法的有效数字为第 1 个⾮零数字开始的全部数字,指数决定⼩数点的位置,符号表⽰该数的正与负。⼗进制科学计数法要求有效数字的整数部分必须在 [1,9]
区间内,满⾜这个要求的表现形式被称为 “规格化” 。科学计数法可以唯⼀地表⽰任何⼀个数,且所占⽤的存储空间会更少,计算机就是利⽤这⼀特性表⽰极⼤或极⼩的数值。
浮点数⽆法表⽰零值,所以取值范围分为正数区间和负数区间。
从数学世界的科学计数法映射到计算机世界的浮点数时,数制从⼗进制改为⼆进制,还要考虑内存硬件设备的实现⽅式。在规格化表⽰上存在差异,称谓有所改变,指数称为 “阶码”,有效数字称为 “尾数”。
(1)符号位
在最⾼⼆进制位上分配 1 位表⽰浮点数的符号,0 表⽰ 正数,1 表⽰负数。
(2)阶码位
在符号位右侧分配 8 位⽤来存储指数,IEEE754 标准规定 阶码位存储的是指数对应的移码 ,⽽不是指数的原码或补码。根据计算机组成原理中对移码的定义可知,移码是将⼀个真值在数轴上正向平移⼀个偏移量之后得到的即 [x]移 = x+ 2^n-1 (n 为 x 的⼆进制位数,含符号位)。移码的⼏何意义是把真值映射到⼀个正数域,其特点是可以直观地反映两个真值的⼤⼩,即 移码⼤的真值也⼤。基于这个特点,对计算机来说,⽤移码⽐较两个真值的⼤⼩⾮常简单,只要⾼位对齐后逐个⽐较即可,不⽤考
虑负号的问题。
由于阶码实际存储的是指数的移码,所以指数与阶码之间的换算关系就是指数与它的移码之间的换算关系。假设指数的真值为 e ,阶码为 E ,则有 E = e + (2 ^ (n-1) - 1),其中 2 ^ (n-1) - 1 是 IEEE754 标准规定的偏移量,n=8 是阶码的⼆进制位数。
为什么偏移量是 2 ^ (n-1) - 1 ⽽不是 2^(n-1) 呢?因为 8 个⼆进制位能表⽰指数的取值范围为 [-128,127] ,现在将指数变成指数表⽰,即 将区间 [-128,127] 正向平移到正数域,区间⾥的每个数都需要加上 128,从⽽得到阶码范围为 [0.255]。 由于 计算机规定阶码全为 0 或 全为 1 两种情况被当作特殊值处理(全 0 被认为是 机器零,全 1 被认为是⽆穷⼤) ,去掉这两个特殊值,阶码的取值范围变成了 [1,254]。如果偏移量不变仍为 128 的话,则根据换算关系公式 [x]阶 = x + 128 得到指数的范围变成 [-127,126] ,指数最⼤只能取到126,显然会缩⼩浮点数能表⽰的取值范围。所以 IEEE754 标准规定单精度的阶码偏移量为 2^(n-1) -1 (即 127),这样能表⽰的指数范围为 [-126,127],指数最⼤值能取到 127。
(3)尾数位
最右侧分配连续的 23 位⽤来存储有效数字,IEEE754 标准规定尾数以原码表⽰。
加减运算
(1)零值检测
检查参加运算的两个数中是否存在为 0 的数(0 在浮点数是⼀种规定,即 阶码与尾数全为 0),因为浮点数运算过程⽐较复杂,如果其中⼀个数为 0 ,可以直接得出结果。
(2)对阶操作
通过⽐较阶码的⼤⼩判断⼩数点位置是否对齐。当阶码不相等时表⽰当前两个浮点数的⼩数点位置没有对齐,则需要通过移动尾数改变阶码的⼤⼩,使⼆者最终相等,这个过程便称为 对阶 。尾数项右移动 1 位,则 阶码值 加 1,反之减 1 。在移动尾数时,部分⼆进制位将会被移出,但向左移会使⾼位被移出,对结果造成的误差更⼤。所以 IEEE754 规定对阶的移动⽅向为向 右 移动,即选择阶码⼩的数进⾏操作。
(3)尾数求和
对阶完成后,直接按位相加即可完成求和(如果是负数则需要先转换成补码再进⾏运算)。这个道理与⼗进制数加法相同。
(4)结果规格化
尾数位向右移动称为右规,反之称为左规。
(5)结果舍⼊
在对阶过程或右规时,尾数需要右移,最右端被移出的位会被丢弃,造成精度损失。为了减少这种损失,先将移出的这部分数据保存起来,称为保护位,等到规格化后再根据保护位进⾏舍⼊处理。
吗
在数学中,进⾏两个⼩数的加减运算时,⾸先要将⼩数点对齐,然后同位数进⾏加减运算。对两个采⽤科学计数法表⽰的数做加减运算时,为了让⼩数点对齐,就要确保指数⼀样。当⼩数点对齐后,再将有效数字按照正常的数进⾏加减运算。
则双精度下,偏移量为1023,11位⼆进制取值范围为[0,2047],因为全0是机器零、全1是⽆穷⼤都被当做特殊值处理,所以E的取值范围为[1,2046],减去偏移量,可得e的取值范围为 [-1022,1023] 。
使⽤浮点数存储和计算的场景⽆处不在,若使⽤不当则容易造成计算值与理论值不⼀致,如:
例 1 :
float a =1;
float b=0.9f;
float f =a - b;
//结果为 0.100000024
1 - 0.9 等价于 1 + (-0.9),⾸先分析 1.0 与 -0.9 的⼆进制编码:
( 将⼀个float型转化为内存存储格式的步骤 为:
(1)先将这个实数的绝对值化为⼆进制格式,注意实数的整数部分和⼩数部分。⼩数部分由⼗进制转换成⼆进制就是 ✖2 取整数部分,直到⽆⼩数为⽌。
(2)将这个⼆进制格式实数的⼩数点左移或右移 n 位,直到⼩数点移动到第⼀个有效数字的右边。如 1.0 应保持原状,⽽ -0.9 的 ⼆进制表⽰为 0.11100110011001 1001循环…它的第⼀个有效数字是 “1”,所以⼩数点移动后,变为 1.1100110011001 1001 循环。
(3)从⼩数点右边第⼀位开始数出⼆⼗三位数字放⼊第 22 到 第0位 。
(4)如果实数是正的,则在第 31 位放⼊“0”,否则放⼊“1”。
(5)如果 n 是左移得到的,说明指数是正的,第30位放⼊“1”。如果n是右移得到的或n=0,则第30位放⼊“0”。
(6)如果n是左移得到的,则将n减去1后化为⼆进制,并在左边加“0”补⾜七位,放⼊第29到第23位。如果n是右移得到的或n=0,则将 n 化为⼆进制后在左边加“0”补⾜七位,再各位求反,再放⼊第29到第23位。
其实 (5)(6)步也可以参考阶码位的定义,⽤有效数字加上 127 即可,⽐如 1.0 的指数为 0,加上 127 得到阶码位 127,⽤⼆进制表⽰即为 011-1111-1;0.9的指数为 -1,加上 127 得到阶码位 126,⽤⼆进制表⽰即为 111 1110。)
1.0 的⼆进制为 0011-1111-1000-0000-0000-0000-0000-0000。
-0.9 的⼆进制为 1011-1111-0110-0110-0110-0110-0110-0110。
从上可得,1.0 和 -0.9 的符号、阶码、尾数三部分的数据如下表所⽰:
尾数位的最左端标红的是⼀个隐藏位。以下运算是基于实际的尾数位进⾏的:
(1)对阶。
1.0 的阶码是 127,-0.9 的阶码是 126,⽐较阶码⼤⼩后 需要右移 -0.9 的尾数的补码,使其阶码变为 127,同时⾼位需要补 1,(这是为什么 因为是负数吗 )移动后的结果为 1000-1100-1100-1100-1100-1101,最左的 1 是⾼位补进的。
(2)尾数求和。
因为尾数都要转换成补码,所以可以直接按位相加,注意符号位也要参与运算。
其中最左端位符号位,计算结果位 0 ,尾数位计算结果为 0000-1100-1100-1100-1100-1101。
(3)规格化
上⼀步计算的结果并不符合要求,尾数的最⾼位必须是 1 ,所以需要将结果向左移动 4 位,同时阶码需要 减 4 (左减右加 )。移
动后尾数为 1100-1100-1100-1100-1101-0000,阶码等于 123 (⼆进制为111 1011)。再隐藏尾数的最⾼位,进⽽变为 100-1100-1100-1100-1101-0000。
综上所述,得出运算后结果的符号为 0,阶码为 1111011、尾数为 100-1100-1100-1100-1101-0000,三部分组合起来就是
1.0-0.9 的结果,对应的⼗进制值是 0.100000024 。
⽽浮点数的悬案不⽌于此。
例2 :
public class DoubleAndFloat {
public static void main(String[] args){
float g=1.0f-0.9f;
float h=0.9f-0.8f;
//第⼀种,判断浮点数是否相等的⽅式
if(g==h)
{
System.out.println("true");
}
else
{
System.out.println("false");
}
//第⼆种
Float x=Float.valueOf(g);
Float y=Float.valueOf(h);
if(x.equals(y))
{
System.out.println("true");
}
else
{System.out.println("false");}
//第三种
Float m=new Float(g);
Float n=new Float(h);
if(m.equals(n))
{System.out.println("true");}
else
{
System.out.println("false");
}
}
}
以上代码的运⾏结果是 3 个 false! 1.0f-0.9f 与 0.9f-0.8f 的结果理应都为 0.1,但实际是不相等的。上⾯已经分析出 1.0f - 0.9f = 0.100000024 ,那么 0.9f - 0.8f 的结果为多少呢? 和以上运算过程,得到 0.9 - 0.8 = 0.099999964。所以就得到 3 个 false。
因此在浮点数⽐较时正确的写法:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论