原码、反码、补码——有符号的编码方式

本文详细介绍了原码、反码和补码在计算机中的定义,包括它们在有符号整数表示中的作用,并阐述了原码转反码和补码的过程。此外,文章还讨论了无符号数的编码方式,以及无符号数与有符号数之间的转换规则,以及位数扩展和截断的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原码、反码、补码定义

我们都知道计算机实际存储都是一个个二进制数字,这些数字并不是杂乱无章的,计算机会根据一定的编码方式,进行一一映射。这里讲到的原码、反码、补码就是一种编码方式,特别的是,他们都属于有符号整数的编码方式

假设一个宽度为 ω \omega ω的二进制 x ⃗ \vec{x} x 表示为:[x ω \omega ω-1,x ω \omega ω-2,…,x1,x0],下面定义下面编码方式的二进制如何转换为十进制。

  • 原码

最高有效位是符号位。用来确定剩下的位应该取正还是取负。0表示正,1表示负。

B T S ( x ⃗ ) = ( − 1 ) x ω − 1 × ( ∑ i = 0 ω − 2 x i 2 i ) BTS(\vec{x}) = (-1)^{x_{\omega-1}}\times(\sum_{i=0}^{\omega-2} x_i2^i) BTS(x )=(1)xω1×(i=0ω2xi2i)

  • 反码

B T O ( x ⃗ ) = − x ω − 1 ( 2 ω − 1 − 1 ) + ∑ i = 0 ω − 2 x i 2 i BTO(\vec{x}) =-x_{\omega-1}(2^{\omega-1}-1) + \sum_{i=0}^{\omega-2} x_i2^i BTO(x )=xω1(2ω11)+i=0ω2xi2i

  • 补码

B T T ( x ⃗ ) = − x ω − 1 2 ω − 1 + ∑ i = 0 ω − 2 x i 2 i BTT(\vec{x}) =-x_{\omega-1}2^{\omega-1}+ \sum_{i=0}^{\omega-2} x_i2^i BTT(x )=xω12ω1+i=0ω2xi2i

原码转反码、补码

假设原码值为:[0000 0001] 、[1000 0001]

  • 原码转反码

正数的反码是其本身,负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.

[ 00000001 ] 原 码 ⟹ [ 00000001 ] 反 码 [0000 0001]_{原码} \Longrightarrow[0000 0001]_{反码} [00000001][00000001]

[ 10000001 ] 原 码 ⟹ [ 11111110 ] 反 码 [1000 0001]_{原码} \Longrightarrow[1111 1110]_{反码} [10000001][11111110]

  • 原码转补码

正数的补码就是其本身,负数的补码是在其原码的基础上,符号位不变,其余各位取反, 最后+1。 (即在反码的基础上+1)

[ 00000001 ] 原 码 ⟹ [ 00000001 ] 补 码 [0000 0001]_{原码} \Longrightarrow[0000 0001]_{补码} [00000001][00000001]

[ 10000001 ] 原 码 ⟹ [ 11111111 ] 补 码 [1000 0001]_{原码} \Longrightarrow[1111 1111]_{补码} [10000001][11111111]

无符号编码方式

像C++中的unsigned、unsigned char、unsigned short、uint32_t、uint64_t都属于无符号类型的整型数据。假设一个宽度为 ω \omega ω的二进制 x ⃗ \vec{x} x 表示为:[x ω \omega ω-1,x ω \omega ω-2,…,x1,x0],无符号编码的二进制转为十进制方式如下:

B T U ( x ⃗ ) = ∑ i = 0 ω − 1 x i 2 i BTU(\vec{x}) =\sum_{i=0}^{\omega-1} x_i2^i BTU(x )=i=0ω1xi2i

无符号数和有符号数之间的转换

C++中运行类型之间存在隐式转换或显示转换,当无符号数和有符号数之间存在转换时,请记住这么一句话:它也许会改变数值(编码方式),但其二进制表示不会改变。

#include <stdio.h>
int main() {
	unsigned n = 4294967295; //这个类型的最大值,十六进制表示为0Xffffffff,占4个字节,即8个十六进制数字
	int i = int(n);
	printf("n = %u ,i = %d \n",n, i);
	int j = -1;
	unsigned m = unsigned(j);
	printf("m = %u ,j = %d", m, j);
	return 1;
}

上面代码中,n的二进制为[1111 1111 1111 1111 1111 1111 1111 1111 ],当n从无符号转为有符号的int类型的话,其二进制表示并没有改变,但其编码方式已经变成补码形式了,故其值变成-1.

位数的扩展和截断

扩展

  • 无符号数的零扩展

[1111 0000]从8位扩展成12位:[0000 1111 0000]

  • 补码的f扩展

[1111 0000]从8位扩展成12位:[1111 1111 0000]

#include <stdio.h>
int main() {
	unsigned short us = 0xcfc7;
	unsigned  sl = 0x0000cfc7; //无符号数的零扩展
	short sx = 0xcfc7; 
	int i = 0xffffcfc7; //补码的f扩展
	printf("us=%u,sl=%u\n", us, sl);
	printf("sx=%d,i=%d", sx, i);
	return 1;
}

截断数字

  • 无符号数的截断

二进制表达从宽度为 ω \omega ω截断到k,其结果为

B T U k ( x k − 1 , x k − 2 , . . . , x 0 ) = ∑ i = 0 k − 1 x i 2 i BTU_k(x_{k-1},x_{k-2},...,x_0) = \sum_{i=0}^{k-1} x_i2^i BTUk(xk1,xk2,...,x0)=i=0k1xi2i

  • 有符号的截断

B T U k ( x k − 1 , x k − 2 , . . . , x 0 ) = − x k − 1 2 k − 1 + ∑ i = 0 k − 2 x i 2 i BTU_k(x_{k-1},x_{k-2},...,x_0) = -x_{k-1}2^{k-1}+ \sum_{i=0}^{k-2} x_i2^i BTUk(xk1,xk2,...,x0)=xk12k1+i=0k2xi2i

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值