数据表示——原码/反码/补码/移码/浮点数

计算机中的数值信息分成整数和实数两大类。整数不使用小数点,或者说小数点总是隐含在个位数的右边,所以整数也称为“定点数”,包含原码、反码、补码移码。相应地,实数也称为“浮点数”。

正数负数
原码最高位为符号位0,其他位为真值的二进制。最高位为符号位1,其他位为真值的二进制。
反码等于原码。按原码除符号位外,其他位取反。
补码等于原码。等于反码+1 或者 求(2机器字长-负数的绝对值)的原码。
移码补码的符号位取反。补码的符号位取反。

1. 原码

最高位是符号位,0表示正号,1表示负号,其余的n-1位表示数值的绝对值(真值)。

数值+0-0
原码(按8位二进制示例)0 00000001 0000000
数值+2-2
原码(按4位二进制示例)0 0101 010

原码运算——加法

运算数值原码原码转十进制
1000000011
+2000000102
=3000000113

原码运算——减法

运算数值原码原码转十进制
1000000011
+-110000001-1
=010000010-2

注意,计算机中减法相当一个正数加上一个负数,原码减法出现问题,一个数加上它本身的相反数不等于0,于是反码登场。

2.反码

正数的反码,等于原码。
负数的反码,按原码除符号位外,其它位取反。

数值+0-0
原码(按8位二进制示例)0 00000001 0000000
反码(按8位二进制示例)0 00000001 1111111
数值+2-2
原码(按4位二进制示例)0 0101 010
反码(按4位二进制示例)0 0101 101

之前原码中减法出现问题,一个数加上它本身的相反数不等于0,我们现在用反码再试一下。

运算数值原码反码反码转原码转十进制
100000001000000011
+-110000001111111110-1
=0-11111111-0

反码相加的最后结果11111111,要先转成原码(即除符号位外的相反数)为10000000,原码再转十进制,最终结果为-0(负零也是零,算是对了吧!)。

那么,如果(-1)+(-3)结果是多少?

运算数值原码反码反码转原码转十进制
-11000000111111110-1
+-31000001111111100-3
=-4-11111010-5

注意,两个不同负数值相加,采用反码运算的结果也不正确,于是补码登场。

3.补码

正数的补码,等于原码。
负数的补码,等于反码+1。

数值+0-0
原码(按8位二进制示例)0 00000001 0000000
反码(按8位二进制示例)0 00000001 1111111
补码(按8位二进制示例)0 00000000 0000000
数值+2-2
原码(按4位二进制示例)0 0101 010
反码(按4位二进制示例)0 0101 101
补码(按4位二进制示例)0 0101 110

负数还有一种计算补码的方法,公式:负数的补码 =(2机器字长 - |负数的绝对值|)的原码
例如,若机器字长为4,求-2的补码。
套入公式过程如下:
( 24 - 2) = 14,
14的原码 = 1110,
-2的补码 = 1110。

之前反码计算不同负数值相加出现问题,我们现在再用补码试一下。

运算数值原码反码补码补码转十进制
-11000000111111110111111111-1
+-3100000111111110011111101-3
=-4--11111100-4

补码转十进制的过程如下:

补码11111100
补码的反码10000011
补码的反码的补码10000100
补码的反码的补码转十进制-(1*22) = -4

计算机中均采用补码进行加减运算。

4. 移码

移码就是补码的符号位取反。 主要用在表示浮点数的指数(阶码)。

数值+2-2
原码(按4位二进制示例)0 0101 010
反码(按4位二进制示例)0 0101 101
补码(按4位二进制示例)0 0101 110
移码(按4位二进制示例)1 0100 110

5.浮点数

实数又称浮点数,通常是既有整数部分又有小数部分的数,整数和纯小数只是浮点数的特例。 例如:3.1415926,-9527,0.01579等都是实数。

任何一个浮点数都可以表示一个乘幂和一个纯小数的乘积。 例如:
3.1415926 = ( 0.31415926 ) * 101
-9527 = ( -0.9527 ) * 104
0.01579 = ( 0.1579 ) * 10-1

其中,乘幂中的指数部分用来指出浮点数中小数点的位置,括号括出的是一个纯小数。 二进制数的情况完全相同,例如:
10101.01 = ( 0.1010101 ) * 2101
0.000111 = ( 0.111 ) * 2-11

  • 浮点表示法: F = 尾数 * 基数指数

尾数: 是一个纯小数,用补码表示,位数决定数的有效精度,位数越多精度越高。
基数: 取进制数,即十进制基数为10,二进制基数为2,八进制基数为8,十六进制基数为16。
指数: 又称阶码,是一个整数,用移码表示,位数决定数的表示范围,位数越多范围越大。

浮点数运算过程先后分为:对阶、尾数计算结果格式化

对阶就是将指数对齐,原则是从小向大看齐,通过较小数的尾数向右移动实现

运算浮点数浮点表示法对阶后的浮点数
3141.59260.31415926*1040.0031415926*106
+314159.260.31415926*1060.31415926*106
=-0.3173008526*106
浮点数补码加减操作在C语言中通常涉及到库函数,因为它们涉及底层的硬件处理和内存管理。但是,为了理解原理,你可以简单地学习如何手动计算单精度(float)和双精度(double)的补码加减。这里是一个简单的示例: 1. **单精度(float)补码加法**: ```c #include <stdio.h> #include <stdint.h> // 补码表示的整数部分和小数部分分开处理 int32_t add_int(uint32_t a, uint32_t b) { int32_t sum = (a ^ b) & ~((a & b) << 31); return sum; } float float_add(float a, float b) { uint32_t a_int = *(uint32_t*)&a; // 转换为整型 uint32_t b_int = *(uint32_t*)&b; int32_t int_sum = add_int(a_int & 0x7FFFFFFF, b_int & 0x7FFFFFFF); // 小数点后的加法 if ((a_int & 0x80000000) != 0 || (b_int & 0x80000000) != 0) { // 检查是否需要调整负号 int_sum ^= 0x80000000; // 如果有任何一个数为负,则结果为正 } float result; *(float*)&result = *((uint32_t*)(&int_sum) + 1); // 再转换回浮点并填充符号位 return result; } // 类似的方法可以编写用于减法,只需修改符号判断条件 ``` 2. **双精度(double)补码加减**: ```c #include <math.h> double double_add(double a, double b) { uint64_t a_int = *(uint64_t*)&a; // 转换为整型 uint64_t b_int = *(uint64_t*)&b; // 加法处理同单精度,只是扩展到64位 // 减法则需要先取绝对值,然后相加,最后根据原始符号确定结果的符号 double result; *(double*)&result = *((uint64_t*)(&int_sum) + 1); // 再转换回双精度 return result; } ``` 注意这只是一个简化版的例子,实际应用中应使用标准库函数如`__builtin_addf`和`__builtin_subfd`,它们更高效、准确。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值