数据的表示与运算

Posted yimumengke

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据的表示与运算相关的知识,希望对你有一定的参考价值。

第二章 数据的表示与运算

https://i.cnblogs.com/posts/edit;postId=-1;templateId=811

【复习提示】

本章内容较为繁杂,由于计算机中数的表示和运算方法与人们日常生活中的表示和运算方法不同,因此理解也较为困难。纵观近几年的真题,不难发现 unsigned、shot、int、long、foat、 double等在C语言中的表示、运算、溢出判断、隐式类型转换、强制类型转换、IEEE754浮点数的表示,以及浮点数的运算,都是考研考查的重点,需要牢固掌握。

在学习本章时,请读者思考以下问题:

  • 1)在计算机中,为什么要采用二进制来表示数据?
  • 2)计算机在字长足够的情况下能够精确地表示每个数吗?若不能,请举例说明。
  • 3)字长相同的情况下,浮点数和定点数的表示范围与精度有什么区别?
  • 4)用移码表示浮点数的阶码有什么好处?

请读者在本章的学习过程中寻找答案,本章末尾会给出参考答案。

2.1 数制与编码

还是要系统学习一下,不然之前的0x1010还查了好久!

2.1.1 进位计数制及其相互转化

知识点回顾与重点考点(如果知道了,就不用看了)







  • 四级网络工程师考试,就用这个方法,妙!

知识回顾与重点考点

2.1.2 BCD码(Binary-Code Decimal码)

注意:这是为了表示0和9,所以1010~1111都是违法的,以前都没在意!

知识回顾与重要考点

2.1.4 字符与字符串

1.字符编码ASCII码



字符串


知识回顾与重要考点

2.1.5 校验码

任意两个码字之间最少变化的二进制位数称为码距,码距大于等于2的数据校验码开始具有检错的能力。码距越大,检错、纠错能力越强。奇偶校验码的码距等于2,可以检测出一位错误(或奇数位错误),但不能确定出错的位置,也不能检测出偶数位错误;海明码的码距大于2,因此不仅可以发现错误,还能指出错误的位置。仅靠增加奇偶校验位的位数不能提高正确性,还要考虑码距。

具有检、纠错能力的数据校验码的实现原理:在编码中,除合法码字外,再加入一些非法码字,当某个合法码字出现错误时,就变为非法码字。合理安排非法码字的数量和编码规则就能达到纠错的目的。

1.奇偶校验码

原编码上加一个校验位,码距等于2!


知识回顾与重要考点

2.海明(汉明)校验码







3. 循环冗余校验(CRC)码

终于知道了《UVM实战》中的CRC校验是什么回事了!





CRC校验码是可以纠错的,前面这个是因为信息位太长


2.2 定点数的表示和运算

2.3 浮点数的表示与运算

2.4 算数逻辑单元(ALU)

2.5 本章开头提出的问题回答

1)在计算机中,为什么要采用二进制来表示数据?

  • 1)在计算机中,为什么要采用二进制来表示数据?

    从可行性来说,采用二进制,只有0和1两个状态,能够表示0、1两种状态的电子器件很多,如开关的接通和断开、晶体管的导通和截止、磁元件的正负剩磁、电位电平的高与低等,都可表示0、1两个数码。使用二进制,电子器件具有实现的可行性。
    从运算的简易性来说,二进制数的运算法则少,运算简单,使计算机运算器的硬件结构大大简化(十进制的乘法九九口诀表有55条公式,而二进制乘法只有4条规则)从逻辑上来说,由于二进制0和1正好和逻辑代数的假( false)和真(true)相对应,有逻辑代数的理论基础,用二进制表示二值逻辑很自然。

2)计算机在字长足够的情况下能够精确地表示每个数吗?若不能,请举例说明。

  • 2)计算机在字长足够的情况下能够精确地表示每个数吗?若不能,请举例说明。

    计算机采用二进制来表示数据,在字长足够时,可以表示任何一个整数。而二进制表示小数时只能够用1(2)的和的任意组合表示,即使字长很长,也不可能精确表示出所有小数,只能无限逼近。例如0.1就无法用二进制精确地表示。

3)字长相同的情况下,浮点数和定点数的表示范围与精度有什么区别?

  • 3)字长相同的情况下,浮点数和定点数的表示范围与精度有什么区别?

    字长相同时,浮点数取字长的一部分作为阶码,所以表示范围比定点数要大,而取一部分作为阶码也就代表着尾数部位的有效位数减少,而定点数字长的全部位都用来表示数值本身,精度要比同字长的浮点数更大。

4)用移码表示浮点数的阶码有什么好处?

  • 4)用移码表示浮点数的阶码有什么好处?

    移码的两个好处
    ①浮点数进行加减运算时,时常要比较阶码的大小,相对于原码和补码,移码比较大小更方便。
    ②检验移码的特殊值(0和max)时比较容易。阶码以移码编码时的特殊值如下。0:表示指数为负无穷大,相当于分数分母无穷大,整个数无穷接近0,在尾数也为0时可用来表示0:尾数不为零表示未正规化的数。max:表示指数正无穷大,若尾数为0,则表示浮点数超出表示范围(正负无穷大);尾数不为0,则表示浮点数运算错误

2.6 常见问题

1.如何表示一个数值数据?计算机中的数値数据都是二进制数吗?

  • 1.如何表示一个数值数据?计算机中的数値数据都是二进制数吗?

    在计算机内部,数值数据的表示方法有以下两大类。
    ①直接用二进制数表示。分为无符号数和有符号数,有符号数又分为定点数表示和浮点数表示。无符号数用来表示无符号整数(如地址等信息);定点数用来表示整数;浮点数用来表示实数。
    ②二进制编码的十进制数,一般都采用8421码(也称NBCD码)来表示,用来表示整数。
    所以,计算机中的数值数据虽然都用二进制来编码表示,但不全是二进制数,也有用十进制数表示的。后面一章有关指令类型的内容中,就有对应的二进制加法指令和十进制加法指令。

2.在高级语言编程中所定义的 unsigned/short/int/long/float/double型数据是怎么表示的?什么称为无符号整数的“溢出”?

  • 2.在高级语言编程中所定义的 unsigned/short/int/long/float/double型数据是怎么表示的?什么称为无符号整数的“溢出”?

    unsigned型数据就是无符号整数,不考虑符号位。直接用全部二进制位对数值进行编码得到的就是无符号数,一般都用补码表示。

    int型数据就是定点整数,一般用补码表示。int型数据的位数与运行平台和编译器有关,一般是32位或16位。例如,真值是-12的int型整数,在机器内存储的机器数(假定用32位寄存器寄存)是1111-1111-1111-1111-1111-1111-1111-0100.

    long型数据和short型数据也都是定点整数,只是位数不同,分别是长整型和短整型数,通常用补码表示。

    float型数据是用来表示实数的浮点数。现代计算机用IEEE754标准表示浮点数,其中32位单精度浮点数就是float型,64位双精度浮点数就是 double型。

    需要注意的是,C语言中的int型和 unsigned型变量的存储方式没有区别,都按照补码的形式存储,在不溢出范围内的加减法运算也是相同的,只是int型变量的最高位代表符号位,而unsigned型中的最高位表示数值位,两者在C语言中的区别体现在输出时到底是采用%d还是采用%u。

    对于无符号定点整数来说,若寄存器位数不够,则计算机运算过程中一般保留低n位,舍弃高位。这样,会产生以下两种结果。
    ①保留的低n位数不能正确表示运算结果。在这种情况下,意味着运算的结果超出了计算机所能表达的范围,有效数值进到了第n+1位,称此时发生了“溢出”现象
    ②保留的低n位数能正确表达计算结果,即高位的舍去并不影响其运算结果。

3.如何判断一个浮点数是否是规格化数?

  • 3.如何判断一个浮点数是否是规格化数?

    为了使浮点数能尽量多地表示有效位数,一般要求运算结果用规格化数形式表示。“规格化浮点数的尾数小数点后的第一位一定是个非零数。因此,对于原码编码的尾数来说,只要看尾数的第一位是否为1就行:对于补码表示的尾数,只要看符号位和尾数最高位是否相反。需要注意的是,IEEE754标准的浮点数尾数是用原码编码的。

4.对于位数相同的定点数和浮点数,可表示的浮点数个数比定点数个数多吗?

  • 4.对于位数相同的定点数和浮点数,可表示的浮点数个数比定点数个数多吗?

    不是,可表示的数据个数取决于编码所采用的位数。编码位数一定,编码出来的数据个数就是一定的。m位编码只能表示2m个数,所以对于相同位数的定点数和浮点数来说,可表示的数据个数应该一样多(有时可能由于一个值有两个或多个编码对应,编码个数会有少量差异)。

5.浮点数如何进行舍入?

  • 5.浮点数如何进行舍入?

    舍入方法选择的原则是:①尽量使误差范围对称,使得平均误差为0,即有舍有入,以防误差积累。②方法要简单,以加快速度。
    IEEE754有4种舍入方式。
    ①就近舍入:舍入为最近可表示的数,若结果值正好落在两个可表示数的中间,则一般选择舍入结果为偶数。
    ②正向舍入:朝+∞方向舍入,即取右边的那个数
    ③负向舍入:朝-∞方向舍入,即取左边的那个数。
    ④截去:朝0方向舍入,即取绝对值较小的那个数

6.现代计算机中是否要考虑原码加减运算?如何实现?

  • 6.现代计算机中是否要考虑原码加减运算?如何实现?

    因为现代计算机中浮点数采用IEEE754标准,所以在进行两个浮点数的加减运算时,必须考虑原码的加减运算,因为IEEE754规定浮点数的尾数都用原码表示。
    原码的加减运算可以有以下两种实现方式
    1)转换为补码后,用补码加减法实现,结果再转换为原码。
    2)直接用原码进行加减运算,符号和数值部分分开进行(具体过程见原码加减运算部分)。

7.长度为n+1的定点数,按照不同的编码方式,表示的数值范围是多少?

  • 7.长度为n+1的定点数,按照不同的编码方式,表示的数值范围是多少?

    各编码方式的数值范围见表2.8

8.设阶码和尾数均用补码表示,阶码部分共K+1位(含1位阶符),尾数部分共n+1位(含1位数符),则这样的浮点数的表示范围是多少?

  • 8.设阶码和尾数均用补码表示,阶码部分共K+1位(含1位阶符),尾数部分共n+1位(含1位数符),则这样的浮点数的表示范围是多少?

    浮点数的表示范围见表2.9。

与运算 递归

【题目描述】
给定 n 个数,找出两个,使得它们经过与运算后结果最大。
注意,选出来的两个数在原数组中的位置不能一样,但是数值可以一样。
【输入格式】
第一行一个整数 n,表示数字个数。
第二行 n 个数,表示给定的数。
【输出格式】
一个整数表示答案。
【样例输入】
3
1 2 1
【样例输出】
1
【数据范围】
对于 20%的数据点,n <= 1000
对于另外 20%的数据点,只有 0 和 1
对于 100%的数据点,n <= 100000, 0 <= 数值 <= 10^9


 

我们知道当当前位都是1时与出来才是1,所以我们考虑从位数高的地方开始统计。

如果当前位数字数量大于2,那么就符合条件,然后递归继续找低位有没有满足条件的。

代码:

 

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

#define ll long long
#define il inline
#define db double

using namespace std;

il int gi()
{
	int x=0,y=1;
	char ch=getchar();
	while(ch<‘0‘||ch>‘9‘)
		{
			if(ch==‘-‘)
				y=-1;
			ch=getchar();
		}
	while(ch>=‘0‘&&ch<=‘9‘)
		{
			x=x*10+ch-‘0‘;
			ch=getchar();
		}
	return x*y;
}

int point[100045];

int stackk[100045];

int stack[100045];

int ci[45];

int num[31][100005];

int s[31];

int er[100005][31];

int check(int now,int tot)//now是当前2的几次方,tot是有多少数满足
{
	//printf("now=%d tot=%d\n",now,tot);
	if(now==0)
		return 1;
	for(int next=1;now-next>=0;next++)
		{
			int cnt=0;
			for(int i=1;i<=tot;i++)
				if(er[stack[i]][now-next])
					stackk[++cnt]=stack[i];
			if(cnt>=2)
				{
					for(int i=1;i<=cnt;i++)
						stack[i]=stackk[i];
					return ci[now]+check(now-next,cnt);
				}
		}
	return ci[now];
}

int main()
{
	freopen("and.in","r",stdin);
	freopen("and.out","w",stdout);

	int n=gi();

	ci[0]=1;
	for(int i=1;i<=30;i++)
		ci[i]=ci[i-1]*2;

	int x;
	bool flag=0;
	for(int i=1;i<=n;i++)
		{
			x=gi();
			if(x!=0)
				flag=1;
			point[i]=x;
			for(int j=30;j>=0;j--)
				if(x>=ci[j])
					{
						x-=ci[j];
						er[i][j]=1;
						num[j][++s[j]]=i;
					}
		}
   
	int now=30;
	while(s[now]<2&&now>=0)
		{
			now--;
		}

	for(int i=1;i<=s[now];i++)
		stack[i]=num[now][i];

	if(flag)
		printf("%d\n",check(now,s[now]));
	else
		printf("0\n");

	return 0;
}

 

以上是关于数据的表示与运算的主要内容,如果未能解决你的问题,请参考以下文章

数据的表示与运算

数据的表示与运算

数据表示运算与校验

数据的表示和运算

与运算 递归

(计算机组成原理)第二章数据的表示和运算-第一节:字符与字符串在计算机中的表示详解