十进制、二进制、八进制、十六进制、进制转换、二进制负数的反码与补码

十进制、二进制、八进制、十六进制对应表

十进制二进制八进制十六进制
000000000
010001011
020010022
030011033
040100044
050101055
060110066
070111077
081000108
091001119
10101012a
11101113b
12110014c
13110115d
14111016e
15111117f

二进制转十进制

(10111011)2 = ( ? )10
1 x 28-1 + 0 x 27-1 + 1 x 26-1 + 1 x 25-1 + 1 x 24-1 + 0 x 23-1 + 1 x 22-1 + 1 x 21-1 = 128 + 0 + 32 + 16 + 8 + 0 + 2 + 1 = (187)10

#include <stdio.h>
#include <math.h>
int main(){
	int a;
	int sum = 0;
	int c = 0;
	scanf("%d",&a);
	for(; a != 0; a /= 10){
		sum += (a % 10) * pow(2, c++);
	}
	printf("%d",sum);
	return 0;
}    //注意输入的二进制数的范围限制,int型存储最大整数为2147483647
//所以输入的最大二进制数为1111111111

在这里插入图片描述
在这里插入图片描述

//该段代码功能:
//将二进制数转换为十进制,输入的二进制数最大为31个1
//因为int型存储范围为2的31次方减1
//如果输入了0和1以外的数字,提示输入错误重新输入
#include <stdio.h>
#include <math.h>
int main(){
	int er[31];    //将二进制数存入数组,因为C语言中没有任何数据类型能够存放31个1这么大的数
	int i, j, count, k, m, flag, a, sum; 
	char digit;   //digit接收输入的字符
	printf("请输入一个二进制数(该二进制数最大为1111111111111111111111111111111):\n");
	do{        //do-while循环实现输入一个二进制数的功能,如果输入了0和1以外的数字,提示输入错误重新输入
		flag = count = 0;     //count统计输入二进制的位数
		for (i = 0; i <= 31; i++){      //for循环接收来自键盘的输入
			digit = getchar();
			if (digit == '1'){     //输入的字符为1时
				er[i] = 1;
				count++;     //count为二进制的位数
			}
			else if (digit == '0'){      //输入的字符为0时
				er[i] = 0;
				count++;     //count为二进制的位数
			}
			else if (digit == '\n')
				break;     //输入了回车结束循环
			else{
				printf("输入错误!请重新输入!\n");
				flag = 1;      //输入了0和1以外的数字,提示输入错误,改变flag的值为1
			}
		}
	} while (flag == 1);   //flag的值为1,重新输入
	sum = m = 0;   //初始化sum和m,m作为数位,sum作为最后要输出的数
	for (k = count - 1; k >= 0; k--){    //count-1倒着循环
		sum = sum + er[k] * pow(2, m);    //二进制转换十进制存入sum中
		m++;    //数位加1
	}
	printf("%d", sum);
	return 0;
}

在这里插入图片描述
在这里插入图片描述

8421码和十进制之间的对应关系

8421码又称为BCD码(Binary Coded Decimal)

8421
23222120
1111

(1111)2 = 8 + 4 + 2 + 1 = (15)10

十进制BCD码
00000
10001
20010
30011
40100
50101
60110
70111
81000
91001

十进制转二进制

十进制转二进制——除二运算
在这里插入图片描述

#include <stdio.h>
int main(){
	int a;
	int b[31];
	int i = 0, c = 0;
	printf("请输入一个十进制数(该十进制数最大为2147483647): ");
	scanf("%d",&a);
	while(a != 0){
		b[i++] = a % 2;
		a /= 2;
		c++;
	}
	for(c = c - 1; c >=0; c--)
		printf("%d",b[c]);
	return 0;
}

在这里插入图片描述

二进制、十进制互相转换(小数)

222120.2-12-2
101.11

(101.11)2 = 1 x 22 + 0 x 21 + 1 x 20 + 1 x 2-1 + 1 x 2-2 = 4 + 0 + 1 + 0.5 + 0.25 = (5.75)10

//将二进制小数转换为十进制数输出
#include <stdio.h>
#include <math.h>
int main(){
	char a[20];
	int b = 0;
	double sum = 0;
	for(int i = 0; i < 20; i++)
		a[i] = 0;   //初始化字符数组 
	printf("请输入一个二进制小数,位数限制在20位,小数点算一位: "); 
	while((a[b++] = getchar()) != '\n');
	int c = 0;
	for(int i = 0; a[i] != '.'; i++)   //统计点之前的位数
		c++;
	int d = c - 1;
	for(int i = 0; i < c; i++)
		sum += (a[i] - '0') * pow(2, d--);
	for(int i = c + 1; i < b - 1; i++)
		sum += (a[i] - '0') * pow(2, d--); 
	printf("%.10f",sum);
	return 0;
}
// 注意输入规范,注意范围限制

在这里插入图片描述
十进制小数转换为二进制:乘二运算,直到为1
(0.67578125)10 = ( ? )2
0.67578125 x 2 = 1.3515625 取个位数1··· ···0.1
0.3515625 x 2 = 0.703125 取个位数0··· ···0.10
0.703125 x 2 = 1.40625 取个位数1··· ···0.101
0.40625 x 2 = 0.8125 取个位数0··· ···0.1010
0.8125 x 2 = 1.625 取个位数1··· ···0.10101
0.625 x 2 = 1.25 取个位数1··· ···0.101011
0.25 x 2 = 0.5 取个位数0··· ···0.1010110
0.5 x 2 = 1 取各位数1··· ···0.10101101
(0.67578125)10 = (0.10101101)2

//将十进制小数转换为二进制小数
#include <stdio.h>
int main(){
	double a;
	scanf("%lf",&a);
	int b;
	int c;
	int d = 0;
	printf("0.");
	while(a != 0){
		c = a * 2;
		a *= 2;
		printf("%d",c);
		if(c == 1)
			a -= 1;
		d++;
	}
	return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
由以上运行结果就可以看出,十进制小数与二进制小数的转换有时候并不是一定准确的,所以部分情况下,计算机在进行运算的时候会有一定的细微误差,这些细微误差可能会导致一些bug。一些无限循环的二进制小数在转换为十进制的时候,是做了一些近似处理的:
在这里插入图片描述
误差案例:
在这里插入图片描述
无论是C语言、Java还是Python,都会有这种小数细微误差的情况,本质上都是一样的,因为Java和Python的内核都是C或C++写的

十六进制、八进制、二进制互相转换

  • 每四位二进制数对应一位十六进制数,四位四位拆分,左右两端位数不够补零:
    (10101010001110.1011111111)2
    = (0010 1010 1000 1110.1011 1111 1100)2
    = (2 a 8 e.b f c)16
    反过来,十六进制转二进制亦是如此

  • 每三位二进制数对应一位八进制数,三位三位拆分,左右两端位数不够补零:
    (10101010001110.1011111111)2
    = (010 101 010 001 110.101 111 111 100)2
    = (2 5 2 1 6.5 7 7 4)8
    反过来,八进制转二进制亦是如此

//输入任意长度的二进制数,包括小数在内,将其转换为十六进制输出
//动态数组
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void Output(char* p, char* q);
void Transf(char* a);
int main(){
	char getC;
	int count = 0;  //count统计字符的长度
	char* p = NULL;
	char* q = NULL;
	char* m = NULL;
	int flag = 0;
	int n;
	printf("请输入任意长度的二进制字符: \n");
	while((getC = getchar()) != '\n')count++;
	if((p = (char*)malloc(count)) == NULL){printf("内存申请失败!");exit(1);}   //如果动态内存申请失败退出程序
	printf("请再输入一遍: \n");  //第一遍输入统计长度分配动态存储空间,第二次输入存入数据
	scanf("%s",p); 
	q = p;
	for(; q < p + count; q++)
		if(*q == '.'){  //判断是否输入了小数点 
			flag = 1;
			m = q;  //m纪录小数点的位置 
		} 
	if(flag == 0){   //若没有输入小数点
		if(count % 4 == 0)  //如果输入的二进制位数正好是4的倍数直接转换 
			Output(p, p + count); 
		else{   //不是4的倍数 
			int t = count % 4;
			char* n = p - 4 + t;
			for(; n < p; n++)  //前面的位数补零 
				*n = '0';
			Output(p - 4 + t, p + count); 
		} 
	}
	else{    //若输入了小数点 
		if((m - p) % 4 == 0){   //小数点前面位数恰好为4的整数倍时
			Output(p, m);
			putchar('.');
		}
		else{
			int t = (m - p) % 4;
			char* n = p - 4 + t;
			for(; n < p; n++)  //前面的位数补零 
				*n = '0';
			Output(p - 4 + t, m);
			putchar('.');
		}
		if((p + count - m - 1) % 4 == 0)   //小数点后面位数恰好为4的整数倍时
			Output(m + 1, p + count); 
		else{
			int t = (p + count - m - 1) % 4;
			//printf("%d\n",t);
			char* n = p + count;
			for(; n < p + count + 4 - t; n++)  //后面的位数补零 
				*n = '0';
			Output(m + 1, p + count + 4 - t);
		}
	}
	return 0;
}
void Output(char* p, char* q){
	char a[4] = {'0','0','0','0'};
	int i = 0;
	for(; p < q; p++){
		a[i++] = *p;
		if(i == 4){
			Transf(a);
			i = 0;
		}
	}
}
void Transf(char* a){
	if(strcmp(a, "0000")==0)printf("0");
	else if(strcmp(a, "0001")==0)printf("1");
	else if(strcmp(a, "0010")==0)printf("2");
	else if(strcmp(a, "0011")==0)printf("3");
	else if(strcmp(a, "0100")==0)printf("4");
	else if(strcmp(a, "0101")==0)printf("5");
	else if(strcmp(a, "0110")==0)printf("6");
	else if(strcmp(a, "0111")==0)printf("7");
	else if(strcmp(a, "1000")==0)printf("8");
	else if(strcmp(a, "1001")==0)printf("9");
	else if(strcmp(a, "1010")==0)printf("a");
	else if(strcmp(a, "1011")==0)printf("b");
	else if(strcmp(a, "1100")==0)printf("c");
	else if(strcmp(a, "1101")==0)printf("d");
	else if(strcmp(a, "1110")==0)printf("e");
	else printf("f");
}

测试:经过验证,转换正确无误
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二进制负数的反码与补码

原码:没经过处理的二进制码
反码:反码只针对负数,符号位不变,其他位取反,即0变成1,1变成0
补码:补码也只针对负数,负数的反码加1得到的二进制代码即为补码

[[X]] = [X]
[[X]] = [X]
[X]反+[Y] = [X + Y]
[X]补+[Y] = [X + Y]

之所以有反码和补码,是为了简化减法运算,使减法可以用加法电路实现。在计算机的内部,正数还是原码,而负数都以补码的形式存在,即将负数的原码取反后再加一。实际生活中的算术运算,比如(-7) + (+5),要考虑符号和绝对值大小的问题,这样就会非常麻烦,如果计算机电路也这样设计,就会出现许多复杂的步骤,为了简化计算机算术电路,所以负数采用补码。在计算机中,加、减、乘、除运算全部通过移位和加法来实现。

拿8位二进制数来说,最高位为符号位,最高位如果为1,则这个二进制数为负数,反之则为正数。例如:0000 0001表示+11000 0001表示-11000 0001-1的原码,取反符号位不变,其他位取反1111 1110,再加1得到补码1111 1111,所以-1在计算机中的代码为(以8位为例)1111 1111,在计算机中计算1 - 1实际上是0000 00011111 1111,进位舍去:
1 - 1=0000 0001+1111 1111=0000 0000
4 - 2=0000 0100+1111 1110=0000 0010
9 - 5=0000 1001+1111 1011=0000 0100
43 - 75 = 00101011+10110101=11100000(-32的补码)

9 * 5=1001 * 101=
001001+
00000+
1001=101101=
00001001 * 00000101=
00001001+
00000000+
00100100=00101101

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jackey_Song_Odd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值