计算机系统漫游(一)、信息的表示和处理

信息存储

电路只有开关,分别以通电与不通电表示开关,由于这种特性,使得计算机能很简单的表示二进制,所以现在计算机及相关存储介质都是用二进制存储数据。一切的信息都会被翻译为二进制在计算机中存储并运算,简单的说,计算机就是一个存储器加计算器,先存储程序再交由运算器计算得出结果

一个二进制被称为一 一字节等于八位 ,单个的位并不具有太大意义,当足够多的位则能表示足够多的可能性,就具有了意义。字节是最小的可寻址的存储器单位,即计算机不能访问到位。

机器级程序将存储器视为一个很大的字节数组,通过访问数组下标来访问到每个字节,该下标就是地址,所有可能的地址集合,就称为 虚拟地址空间。这个虚拟地址空间只是一个概念性的映射,具体还是要靠随机访问存储器等等来实现映射

编译器和运行时系统的一个任务,就是将这个存储器单元分为更可管理的单元,来存放不同的程序对象

对于一个很长的位,计算机能够通过机械运算理解它的意义,但是人类却很难理解,需要一种计算机能够理解的位和人类能够读懂的语言之间的转换,这就是编码。编码就像古时密码本,编译使用编码来做对照翻译,将人类能够读懂的语言翻译为二进制语言,不同的编译技巧会带来不同的效果,我们下面会看到这些神奇的技巧。

每台计算机都有一个字长,指明整数和指针数据的标称大小。因为虚拟地址是以一字表示的,所以系统参数的字长,就代表了虚拟地址空间的范围。即,对于一个字长 n 的机器,地址表示的范围则是 0 ~ 2^n-1 ,则程序最多访问到 2^n 字节。例如:32位计算机的虚拟地址范围是 0 ~ 2^32,即,最多能访问到 2^32 字节(因为每个地址都必须是不同的),约为 4g

数据大小

计算机和编译器使用不同的方式编码数字,从而支持多种数据格式。

以 c 语言为例,语言的类型应该具有跨平台性,但是 c 的 long、int、*char 类型在 32 位机器是用 4 字节表示,在 64 位机器 long、*char 使用 8 字节表示,在原来的 32 位机器,使用 int 可以存储一个指针类型,但是这放在 64 位机器就会出错,而在 64 位平台上编译的代码更不能在 32 位上执行

寻址和字节顺序

对于跨越多字节对象的存储,一般都存储位连接的字节序列,并使用字节序列中的最小地址作为对象的地址,比如一个 int 类型的地址位 &001,它的字节序列位 &001、&002、&003、&004。对于字节序列的表示,有两种方法,将最低有效字节放在前称为小端法,Intel的机器大多采用,将最高有效字节放在前称为大端发,IBM机器大多采用

以十六进制 0x01234567 为例,小端法 67 45 32 01、大端法 01 23 45 67,我们书面语法就是大端法

为了避免在不同机器上产生错误,在网络上传输二进制时,必须按照网络规定转换为网络标准,机器从网络接受后再转化为机器标准

整数表示

在整数的编码中,常有两种形式,无符号整数和有符号整数,他们的编码方式不同,运算的属性也不同

无符号

无符号最简单粗暴,直接对数进行编码,空的地方补 0

有符号

有符号数有多种编码方式,这里介绍最常用而且神奇的补码方式

二进制数十进制数
000000000
000000011
01111111127
10000000-128
10000001-127
11111111-1

从本质上讲,计算机只能做加法运算,所有的减法和乘除都是通过加法运算间接模拟出来的,以这种编码方式,便于通过加法模拟出减法,例如:1 - 127 编码: 00000001 + 10000001 = 10000002 解码:-126,只需要一次加法就完成了减法运算

可以看出,从正数得到负数的方法,求其补码 + 1

注意:在一些语言中,有符号数强制转换为无符号数时,是直接将有符号数的二进制码以无符号数的方式解码,如果原来的数是正数,数值不会改变,如果是负数,则会得到一个特别大的正数

    var a int = -1
    var b int = -2
    fmt.Println(uint(a)) //18446744073709551615
    fmt.Println(uint(b)) //18446744073709551614

扩展一个数字的位表示

不同长度的数据之间可能会进行转换,将大类型转换位小类型不具有太大意义,容易造成数据丢失,而将小类型转为大类型,又分为两种。无符号数据在最高为补0即可,而补码表示的有符号数据在最高为补原来最高为的值,这样就能维持值不变

隐式类型转换总是会给你意想不到的惊喜,所以选择 go 吧,绝对没有任何隐式转换,防止你的程序被低级而隐蔽的错误入侵

整数运算

无符号数加法

两个太大的无符号数相加可能反而会得到一个比他们小的数,这是因为最高为溢出了,例如:11111111 + 00000001 = 00000000,因为字长的限制,他们反而会得到个 0

补码的加法

两个太大的正数相加可能会得到一个负数,而两太小的负数相加也可能会得到一个正数,例如:01111111 + 00000001 = 10000000 解码得 -128

整数乘法

在计算机内部,n*m 实质是将 n 做 m 次的累加,所以乘法是很耗费 cpu 的,即使你的编译器会帮助你做乘法的优化,但是不要过多相信编译器,能用位移运算或加法,就不要用乘法。最关键的是,小心溢出

使用位移运算,向左移动一位(丢弃最高为,最低位补0),等同于 *2,*2^n 等同于左移 n 位

二进制小数

在计算机中并不能精确的表示所有浮点数,而是得到近似值,例如 101.11 如果以二进制表示,则得到 1*2^2 + 0*2^1 + 1*2^0 + 1*2^-1 + 1*2^-2,除以 2 相当于将小数点向后移动一位。

并不是所有的数都能以 2 的次方相加表示,这时我们只能得到他的近似值,提高小数点后的位数可以提高精度

我们从将十进制数转为二进制数来展开浮点数的细节

    -235.125 转为二进制 -100100101001.001 = -1.00100101001001×2^11

-1.00100101001001×2^11 分为三个部分,符号位 - 或 +,尾数 1.00100101001001,阶码 11,在 IEEE 标准中规定了单精度和双精度的长度

类型长度符号阶码尾数指数偏移
单精度 float3231~3030~2322~0127
双精度 double6463~6262~5251~01023

V = (-1)^符号 * 尾数 * 2^阶码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值