信息的表示与和处理
自己想的小问题
我们知道常用的计算机信息就是 字符,数字(整数,浮点数)
- 整数(正负数)是如何表示的在计算机内存中?是无限大的吗?
- 小数是咋表示的,1/3 在计算机中小数能表示吗?
- 对于任意整型,说明 a&-a 的含义:
答:a & -a = a&~(a-1) ,且通过 a&-a 能得到 a 倒数第一个 1 的位置(该位置上是 1,取 余全 0)
对于有 10个手指的人类来说,使用十进制表示法是很自然的事情,但是当构造存储和处理信息的机器时,二进制的值工作得更好。二值信号能够很容易地被表示、存储和传输,例如,可以表示为穿孔卡片上有洞或无洞、导线上的高电压或低电压,或者顺时针或逆时针的磁场。对二值信号进行存储和执行计算的电子电路非常简单和可靠,制造商能够在一个单独的硅片上集成数百万甚至数十亿个这样的电路。
当把位组合在一起,再加上某种解 释(interpretation),即给不同的可能位模式赋予含义,我们就能够表示任何有限集合的元素。
- 使用一个二进制数字系统,我们能够用位组来编码非负数。
- 通过使用标准的字符码,我们能够对文档中的字母和符号进行编码。
在本章中,我们将讨论这两种编码,以及表示负数和对实数近似值的编码。
我们研究三种最重要的数字表示。
- 无符号(unsigned)编码基于传统的二进制表示法,表示大于或者等于零的数字。
- 补码(two’s-complement)编码是表示有符号整数的最常见的方式,有符号整数就是可以为正或者为负的数字。
- 浮点数(floating-point)编码是表示实数的科学记数法的以二为基数的版本。
计算机用这些不同的表示方法实现算术运算,例如加法和乘法,类似于对应的整数和实数运算。
学习本章注意的问题:
- 计算机的表示法是用有限数量的位来对一个数字编码,因此,当结果太大以至不能表示时,某些运算就会溢出(overflow)。溢出会导致某些令人吃惊的后果。例如,现在的大多数计算机(使用32位来表示数据类型int),计算表达式200300400*500会得出结果-884 901 888。
- 整数的计算机运算满足人们所熟知的真正整数运算的定律(交换律,优先级)。
- 浮点运算有完全不同的数学属性**。虽然溢出会产生特殊的值+无穷,但是一组正数的乘积总是正的。由于表示的精度有限,浮点运算是不可结合的。例如,在大多数机器上,C表达式(3.14+1e20))-1e20求得的值会是0.0,而3.14+(le20-le20)求得的值会是3.14。
- C++编程语言建立在C语言的基础之上,它们使用完全相同的数字表示和运算。本章中关于C的所有内容对C++都有效
整数运算和浮点数运算会有不同的数学属性是因为它们处理数字表示有限性的方式不同——整数的表示虽然只能编码一个相对较小的数值范围,但是这种表示是精确的;而浮点数虽然可以编码一个较大的数值范围,但是这种表示只是近似的。
1. 信息存储
大多数计算机使用8位的块,或者字节(byte),作为最小的可寻址的存储器单位,而不是在存储器中访问单独的位。机器级程序将存储器视为一个非常大的字节数组,称为虚拟存储器(virtualmemory)。存储器的每个字节都由一个唯一的数字来标识,称为它的地址(address),所有可能地址的集合称为虚拟地址空间(virtual address space)。顾名思义,这个虚拟地址空间只是一个展现给机器级程序的概念性映像
实际的实现: 将随机访问存储器(RAM)、磁盘存储器、特殊硬件和操作系统软件结合起来,为程序提供一个看上去统一的字节数组。
十六进制表示
一个字节由8位组成。在二进制表示法中,它的值域是 00000000~1111111; 十进制整数表示,它的值域就是0~255。
16进制的出现原因: 二进制表示法太冗长,而十进制表示法与位模式的互相转化又很麻烦。
以16为基数,或者叫十六进制(hexadecimal)数,来表示位模式。十六进制(简写为"hex")使用数字’0’~’9’,以及字符’A’~’F’来表示16个可能的值。 一个字节的值域为00~FF。
16进制的书写表示: 在C语言中,以0x或0X开头的数字常量被认为是十六进制的值。字符’A’~’F’既可以是大写,也可以是小写,甚至是大小写混合。例如,我们可以将数字FA1D37B。写作0xFAlD37B,
16进制与2进制的转化:
- 基本规则是4位一组做整合和拆分
- 窍门是记住16进制数字的 A,C,F对应的十进制,其他字母根据相对未知来算。
- 当值x是x=2的n次方,我们可以很容易地将x写成十六进制形式,只要记住x的二进制表示就是1后面跟n个0。十六进制数字0代表4个二进制0。所以,当n表示成 i+4j 的形式,其中 0≤i≤3 时,我们可以把x写成开头的十六进制数字为1(i=0)、2(i=1)、4(i=2)或者8(i=3),后面跟随着 j 个十六进制的0。比如,x=2048=2的11次方,我们有n=11=3+4×2,从而得到十六进制表示0x800。
16进制和10进制的转化:
十进制和十六进制表示之间的转换需要使用乘法或者除法来处理一般情况。
将一个十进制数字 x 转换为十六进制:
- 可以反复地用16除x,得到一个商g和一个余数r,也就是x=q×16+r。
- 我们用十六进制数字表示的 r 作为最低位数字,并且通过对 q 反复进行这个过程得到剩下的数字。
十六机制转化为10进制:
- 用相应的16的幂乘以每个十六进制数字。
字
每台计算机都有一个字长(word size),指明整数和指针数据的标称大小(nominal size)。
因为虚拟地址是以这样的一个字来编码的,所以字长决定的最重要的系统参数就是虚拟地址空间的最大大小。也就是说,对于一个字长为w位的机器而言,虚拟地址的范围为0~2",程序最多访问2"个字节。
数据大小
移植问题:
许多程序的编写都假设为图 2-3中列出的32位机器对应的字节分配。随着64 位机器的日益普及,在将这些程序移植到新机器上时,许多隐藏的对字长的依赖性就会显现出来,成为错误。 比如,许多程序员假设一个声明为 int 类型的程序对象能被用来存储一个指针。这在大多数32位的机器上能正常工作,但是在一台64 位的机器上却会导致问题。
可移植建议:
- 表达式sizeof(T)返回存储一个类型为T的对象所需要的字节数。使用sizeof,而不是一个固定的值,是向编写在不同机器类型上可移植的代码迈进了一步。
寻址和字节顺序
对于跨越多字节的程序对象,我们必须建立两个规则∶
- 这个对象的地址是什么
- 以及在存储器中如何排列这些字节。
对象地址
在几乎所有的机器上,多字节对象都被存储为连续的字节序列, 对象的地址为所使用字节中最小的地址。
举例: int的变量 x 的地址为 0x100, 地址表达式的 &x 的值为 0x100,那么x的4个字节就存储在存储器的 0x100, 0x101, 0x102,