程序的表示、转换和链接(一)计算机中数据的表示

一、 数据的表示和存储

  机器级数据包括:

   数值数据:定点数与浮点数

  非数值数据:逻辑数,字符

  真值和机器数

  机器数:0/1序列 

  真值:算术、逻辑意义上的值

  •   数值数据三要素:
    •   进位计数值(就是进制)

    二进制、十六进制(后缀H, 前缀0x)、八进制(后缀O)

    •   定、浮点表示(计算机中不显式地标注小数点的位置,约定位置)

      定点小数是什么?和浮点小数的区别?

      三个数来SME来表示一个数,分别是符号、尾数、阶数;

       其中尾数是一个定点小数,阶数是定点整数 

     问:123与-123在8位二进制下的补码,在16位二进制下的补码;

        如何由机器数(补码)迅速计算得到真值?

        带有符号位的原码,取反加一,得到补码;

        符号位为1的补码转为原码:除符号位外取反加一

  整数的机器数的表示与运算规则,请看下面的例子  :

#include<iostream>
#define INT32_MAX 2147483647
using namespace std;
int main(){
    cout << 2147483647+1 << endl;
    cout <<  (INT32_MAX > -INT32_MAX-1) << endl; // true
    cout << (INT32_MAX > -INT32_MAX-2) << endl; // false
    cout << -INT32_MAX-2 << endl; //发现溢出为INT32_MAX了
    cout << endl;

    cout << (-1 < 0u) << endl;
    // 结果为false, -1的补码为FFFFFFFFH,即最大的无符号整数!
    // 下面可以验证:
    unsigned unsigned_int32_max = INT32_MAX*2+1;
    cout << "Max unsigned int32 : " << unsigned_int32_max << endl;
    cout << (-1u == unsigned_int32_max) << endl; // 输出为true
    cout << (-1 + 0u) << endl;
    /*
    通过上面的输出我们可知,将有符号数化为无符号数
    就是直接按照原码方式解释内存中的机器码
    */

    cout << ((unsigned)INT32_MAX > -INT32_MAX-1) << endl; 
    // false, 实际上比较的是原码 7FFFB 与 8000B
    cout << (INT32_MAX > int(2147483648U)) << endl;
    // true, 右边2147483648U在内存中是7000H,如果按照有符号
    // 数进行解释则是-2147483648
    cout << (-INT32_MAX-1 == int(2147483648U)) << endl;
    
    cout << endl;
    int a = -2147483648; // 机器码 0x8000
    cout << hex << (a + 0u) << ' ' << (a + 0u) << endl;
    //输出0x8000, 1*2^31也就是2147483648
    unsigned b = 1;
    cout << a + b << endl;// 输出0x8001
    unsigned c = -1; // -1机器码0xffff
    cout << c << endl;// 输出无符号32位最大
    // 结果发现int是64位的
    system("pause");
}

 

  因此可以总结为:

  0. 对于没有参加运算的字面值常数,可以正常输出,并且编译器自动将其识别为int,long,long long;参加运算的字面值则先强制转换为相同的类型,再进行运算;

  1. 当unsigned字面值与有符号字面值运算时,会将有符号数强制转换为无符号数,

然后按照无符号数的规则(原码表示)解释、计算内存中的机器码;

  2. 表达式中的变量同样也要先被强制转换为相同类型,再进行计算。

 

   浮点数的表示与运算

  请思考,32位浮点数(1位符号,8位阶数,23位尾数)能够表示的实数范围?

  请思考0,正负无穷的机器数形式。规范数与非规范数。

 

  数据的基本宽度:

  计算机中存储的最小单位是8bit一个字节(Byte),字节是最小的可寻址单位。

  字 和 字长 的概念有所不同。(字长:数据通路的宽度,部件、总线的宽度和运算器的位位数要一致)x86的字都是16位,而字长从386开始就是32位了。

  大端存放与小端存放:存储数据的地址是最低有效字节LSB的地址还是MSB的地址。

  

二、运算电路基础

  • 真值表、逻辑表达式、与或非、异或
  • 从逻辑门到n位逻辑门
  • 组合逻辑电路与时序逻辑电路
  • n位加法器以逻辑门和全加器为基础,实现了n位无符号数的加法运算
  • 整数加/减运算器以加法器和多路选择器为基础,实现整数加减法
  • 最终实现ALU, 整数乘除与浮点运算  

 

 三、乘除运算与浮点数运算

   整数乘法运算

  n位整数相乘,在运算电路中得到的结果实际上是2*n位,但是通常只取低n位的值赋给结果。

#include<iostream>
using namespace std;
int main(){
    int a = 100000,b = 100000;
    // 2 1 4 7 4 8 3 6 4 7
    // 1 0 0 0 0 0 0 0 0 0
    cout << a*b << endl; // 溢出得到1410065408
    a = 111111, b = 111111; // 溢出得到负数!-539247567
    cout << a*b << endl;
    system("pause");
    return 0;
}

  无符号/有符号整数的乘法,都可以检测高n位来检测是否溢出。

  硬件不判定溢出,只把2n位给软件。无符号乘法与带符号乘法是两个不同的指令!(而加减运算不区分有符号/无符号)。利用整数乘法的溢出漏洞可以申请超大的堆区空间,然后恶意改写堆缓冲区,对系统进行攻击。

  变量与常数之间的乘运算不使用乘法电路,而是用编译器通过移位、加法和减法的组合进行运算。

  整数除法运算

  • 只有2^(n-1)/-1这种情形会出现整数溢出
  • 当除数无法整除被除数时,正数/负数截断的方式不同(地板/天板)
  • 整除0的结果无法用机器数表示!
  • 除法指令比乘法指令所需时间更长!(要优化程序可以代替除法用其他方式实现)
  • 有符号数变量除以2的幂,正数直接右移(右移的位直接丢弃,如果是整数则丢弃的全是0,无影响),负数则需要先加偏移量  

  浮点数运算

  • 规格化浮点数的加减法 乘除法
  • 阶码上溢/下溢 尾数溢出等异常情况
  • 机器码只能精确表示1/(2的幂)这样的小数!1/3,1/10都是没法精确表示的!
  • IEEE 754的double浮点数8字节64位,必然最多只能表示2^64个小数,精度的损失不可避免
  • int整除0无法用机器码(0和1的组合)表示,因为机器码都用完了。但浮点数可以用全1阶码/全0尾数表示无穷大!
  • 通过附加位保证更高的精度
  • 将同一实数赋给float和double类型的数据,结果不同,因为float最多只能精确表示小数点后7位,后面的数位是舍/入的结果(可能大也可能小)
  • C语言中float/double都是IEEE754的标准,而long double则与编译器和处理器类型有关
  • int转float,不会溢出但可能发生舍入。double转int/float很可能损失精度

  

int x;
float f;
double d;
x == (int)(float)x; // 可能false,int转float会损失精度
x == (int)(double)x; // true,因为int无非是31个有效数字,而double是53个有效数字
f == (float)(double)f;// true
f == -(-f);  //true
d*d >= 0; // true
f*f >= 0; // true
x*x >=0; // false 高n位丢弃
(d+f)-d == f; // false 因为d很大 f很小时,对阶,右移高位变成0
  • 范围和精度

  float最大3.4*10^38, double最大1.8*10^308

  对于浮点数,加法结合律是不成立的!(大数吃小数,对阶右移全0了)

  精度问题可能导致严重问题!(火箭爆炸,水平速率数值溢出)

  不同数据类型之间的转换很容易出现问题,导致严重错误。非常小的精度误差,积累起来将导致可观的误差。

  并不是所有小数都适合用浮点数表示,如果需要将一个整型变量乘以一个确定的小数常量,可以先用定点整数相乘,再移位得到结果。

 

 

 

 

  

posted @ 2019-06-19 21:11  LiaoQian1996  阅读(353)  评论(0编辑  收藏  举报