很长的十进制数转二进制数(大数除法)

  • 问题描述

Description

将一个很长的十进制数转换为二进制数

注意由于输入的十进制数可能很长,超过了C语言int、long long 、double等基本数据类型的存储范围,需要自行用字符数组等方式存储输入,并自行编写除法等进制转换必须的相关操作

Input

输入多组数据,请处理到文件结束。每组数据一行,是一个很长的十进制数,长度大于0,小于200

Output

对于每组数据将其转换为二进制

Sample Input 1 

123456789012345678901234567890
753951684269875454652589568545854758545824

Sample Output 1

1100011101110100100001111111101101100001101110011111000001110111001001110001111110000101011010010
10001010011110101010001101001000100100100000101001011010001010101001000100111101011001110001000111110010001000101101111110110110100110100000

注:题目来源OnlineJudge


  • 问题分析

题目要求转换一个很长的十进制数字,用int、long、long long、double显然是存不下的,所以这里创建一个char类型的数组接收数据,再进行处理。但是以字符串形式接收数据并存放到char类型的数组中后该数据的每一位数都被独立开了,即输入147时实际是得到字符1、4、7。那我们如何去处理接收到的数据呢?

我们知道进制转换,其核心就是除法的实现。所以下面先补充一个除法的实现过程,帮助大家理解除法的实现。

除法实现过程

//除法的实现
//举一个简单的例子,如用125除以2
//其实现过程如下:
//1.从最高位开始除,得到当前位的商和余数
//	1/2=0,1%2=1
//	所以这一次的结果是商0余1
//2.从次高位数开始,将上一位数除2后所得余数乘以10加上当前位置的数作为新的被除数,再进行除2操作,得当前位的商和余数
//	新的被除数是1*10+2=12
//	12/2=6,12%2=0
//3.继续取下一位数,将上一位数除2后所得余数乘以10加上当前位置的数作为新的被除数,再进行除2操作,得当前位的商和余数
//	新的被除数是0*10+5=5
//	5/2=2,5%2=1
//4.重复上面3中的步骤,直到新的被除数为0,此时余数为整个除法的最终余数,整个除法结束,依次记录每一步骤的商可得到最终的商
//	最终的商是062,即62
//	最终的余数是1

从上面的例子中,如果要将十进制数125转换成对应二进制数,我们只需按照上述方法处理每一轮除法,每一轮除法结束取最终余数和商,如果商不为0,去上一次的商作为新的被除数处理,直到商为0,余数依次按顺序存下,最后逆序即可得到对应二进制数。

进制转换实现过程

//二进制转换实现
//以125转对应二进制数为例
//1.第一轮除法,得到如下结果
//	最终的商是062,即62
//	最终的余数是1
//2.上一轮除法最终得到的商不为0,继续以上一轮的商作为新的被除数进行新一轮除法,即以62作为新的被除数,得到如下结果
//	最终的商是31
//	最终的余数是0
//3.继续2中的步骤,直到最终的商为0,整个转换结束,如果按顺序依次存放每一轮除法所得最终余数,那么我们逆序即所求对应二进制数

//第一轮,125作为被除数
//	最终的商:062
//	最终的余数:1
//第二轮,062作为被除数
//	最终的商:031
//	最终的余数:0
//第三轮,031作为被除数
//	最终的商:015
//	最终的余数:1
//第四轮,015作为被除数
//	最终的商:007
//	最终的余数:1
//第五轮,007作为被除数
//	最终的商:003
//	最终的余数:1
//第六轮,003作为被除数
//	最终的商:001
//	最终的余数:1
//第七轮,001作为被除数
//	最终的商:000
//	最终的余数:1
//第七轮中最终的商为0,整个转换过程结束
//	按顺序存放每一轮的最终余数:1011111
//	逆序余数可得所求二进制数:1111101

从上面的例子中,我们可以理解除法和进制转换的关系了,进制转换就是多次除法,每一次的被除数都是上一次除法所得的商。


以此为基础,考虑本题中的代码实现过程

         1.将char类型数组中的char类型数据转换成int类型数据并存放在int类型数组中

除法中除的过程和取模的过程处理对象都是int类型,所以我们先将接收到的字符串数据转换成对应的int类型的数据并存放在一个int类型的数组中。

char类型数字转换成对应int类型数字,可用:int类型数字=char类型数字-'0'。原理其实也很简单,char接收的数据在内存中存放是其对应的ASCll值,所以这里用char类型数字减去字符0,差值即对应int类型的数字。我们写一个transform_int函数,函数实现代码如下:

char num_char[200] = { 0 };//用于存放输入的超长十进制数
int num_int[200] = { 0 };//用于存放转换成整型数据的超长十进制数存放

void transform_int(char num_char[], int num_int[])
{
	int sz = strlen(num_char);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		//按顺序存入输入的数据,num_char[0]是最高位
		num_int[i] = num_char[i] - '0';//数字(字符类型)转换成对应数字(整数类型)
	}
}

        2.在进行每一轮的除法前,判断当前的商是否为0

数据是以int类型数组存放,如果数组中元素全为0,那么当前转换结束,不进入下一次除法运算。即只需遍历该数组,若存在一个非0的数,则数据未处理结束,进行下一轮除法。因为进行下一次除法前都要进行判断,我们可以将判断的功能独立出来,分装成一个函数,每次判断时调用即可。这一部分的代码我们也写成一个函数is_allzero,函数实现代码如下:

int is_allzero(int num_int[], int sz)
{
	//判断是否存在非零的数
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		if ((num_int[i])!= 0)//写成if ((num_int[i])^ 0)也可,运用了异或运算符
		{
			return 1;//返回1表示仍存在非0的数
		}
	}
	return 0;//返回0表示数据全部处理为0
}

        3.进制转换的实现,处理到最终数据为全零0,进制转换的核心

基于上面给大家补充的除法实现过程,和进制转换实现过程,如果可以深刻的理解除法实现过程和进制转换实现过程,那么我们将其用一个函数transform_binary表示出来,其实现过程如下:

void transform_binary(int num_int[], int binary[], int sz)
{
	int i = 0;
	int count = 0;//计数器,用于计算结果的位数
	while (is_allzero(num_int, sz))//在开始每一轮大数除法前进行一次判断,处理到数据全为0时结束
	{
		//大数除法核心
		//下面进行一轮大数除法
		int temp_before = 0;//用于存放一轮大数除法结束后的余数,开始每一轮大数除法前,上一次余数置为0
		for (i = 0; i < sz; i++)
		{
			int temp = num_int[i] + temp_before * 10;//每一次的被除数=当前位置的数+上一次余数*10
			num_int[i] = temp / 2;//用每一次除得的商替换上一次的数据
			temp_before = temp % 2;//每一次取模值(余数)留给下一次处理
		}
		binary[count++] = temp_before;//每一轮大数除法结束后所得最终余数按顺序存放进binary数组
	}
	//逆序输出binary
	for (i = count-1; i >= 0; i--)//while循环结束时count多自增了1,binary中最后一个元素的下标为count-1
	{
		printf("%d", binary[i]);
	}
}

下面对transform_binary函数实现过程进行补充,帮助大家理解。

在进入while循环前,我们先进行一次判断,判断当前要处理的数据是否仍存在非0的数,若存在,则进入循环。

在上面的除法实现过程中,我们知道每一轮除法会产生一个余数,且下一次除法会进行使用,这里创建一个int类型变量temp_before,该变量用于存放一轮除法中每一次除法的余数,在该轮中一下除法时利用。另外创建一个int类型临时变量temp用于存放当前的被除数。所以进入下一次除法时,当前被除数=当前位+temp_before*10,即int temp = num_int[i] + temp_before * 10,本次除法余数又重新存放到temp_before中,即temp_before = temp % 2,同时将本次除法得到的商存放回当前位数,即num_int[i] = temp / 2,继续进行下一次除法,直到本轮除法结束,每一次除法的商都依次存放回原数组,覆盖上一次要处理的数据,最后的temp_before即本轮除法最终的余数,将每一轮的最终余数按顺序存放进binary数组中。

下一轮以上一轮覆盖原数组后的数据在while中重复上述过程,处理到num_int数组中数据全部为0时结束进制转换过程,最后就是逆序输出binary数组中的数据,即对应二进制数。


  • 解决方案 

通过上面的整个分析过程,AC代码如下:

#pragma warning(disable:4996)
#pragma warning(disable:6031)
#pragma warning(disable:6054)
#pragma warning(disable:6385)

#include<stdio.h>
#include<string.h>

void transform_int(char num_char[], int num_int[]);//将字符类型的数据转换成整数类型的数据
void transform_binary(int num_int[], int binary[], int sz);//将输入的十进制数转换成二进制数
int is_allzero(int num_int[], int sz);//判断需处理的数据是否为全0

int main()
{
	//创建的数组大小根据题目而定
	char num_char[200] = { 0 };//用于存放输入的超长十进制数
	int num_int[200] = { 0 };//用于存放转换成整型数据的超长十进制数存放
	int binary[1000] = { 0 };//用于存放二进制数据结果

	while (scanf("%s", num_char) != EOF)//按顺序存入输入的数据,num_char[0]是最高位
	{
		int sz = strlen(num_char);
		transform_int(num_char, num_int);

		if (is_allzero(num_int, sz) == 0)//处理前先进行一次判断,若输入的数据是全0,则输出0
		{
			printf("0");
		}
		else
		{
			transform_binary(num_int, binary, sz);
		}

		printf("\n");
	}

	return 0;
}

void transform_int(char num_char[], int num_int[])
{
	int sz = strlen(num_char);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		//按顺序存入输入的数据,num_char[0]是最高位
		num_int[i] = num_char[i] - '0';//数字(字符类型)转换成对应数字(整数类型)
	}
}

void transform_binary(int num_int[], int binary[], int sz)
{
	int i = 0;
	int count = 0;//计数器,用于计算结果的位数
	while (is_allzero(num_int, sz))//在开始每一轮大数除法前进行一次判断,处理到数据全为0时结束
	{
		//大数除法核心
		//下面进行一轮大数除法
		int temp_before = 0;//用于存放一轮大数除法结束后的余数,开始每一轮大数除法前,上一次余数置为0
		for (i = 0; i < sz; i++)
		{
			int temp = num_int[i] + temp_before * 10;//每一次的被除数=当前位置的数+上一次余数*10
			num_int[i] = temp / 2;//用每一次除得的商替换上一次的数据
			temp_before = temp % 2;//每一次取模值(余数)留给下一次处理
		}
		binary[count++] = temp_before;//每一轮大数除法结束后所得最终余数按顺序存放进binary数组
	}
	//逆序输出binary
	for (i = count-1; i >= 0; i--)//while循环结束时count多自增了1,binary中最后一个元素的下标为count-1
	{
		printf("%d", binary[i]);
	}
}

int is_allzero(int num_int[], int sz)
{
	//判断是否存在非零的数
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		if ((num_int[i])!= 0)//写成if ((num_int[i])^ 0)也可,运用了异或运算符
		{
			return 1;//返回1表示仍存在非0的数
		}
	}
	return 0;//返回0表示数据全部处理为0
}

  • 总结

 本题的难点在于题目要求处理的是超长的数据,我们只能用字符串接收存放于char类型数组中,其次要深刻理解除法、进制转换及他们之间的关系,最后用代码把他们表达出来。这种超长数据进制转换处思路,在其他进制转换中也可以使用,如果读者能够理解掌握上面的思路,在遇到类似题目时,相信大家可以如行云流水般写出AC代码。

以本题为基础,实现k(1<k<=10)进制其实是用一样的套路将上述操作数2改为k即可


  • blog心路历程

        我 21年9月入学,此前并没有接触过编程类相关知识,那时的我对C语言入门真的毫无头绪,找学姐学长、还有预科的兄弟请教如何入门C,你们对我的帮助真的很多,在这里先表示感谢。        

        我至今仍记得第一次在小黑窗打印出hello world时的兴奋,这是我模仿课本《C语言程序设计》(第四版何钦铭)打出的第一个代码,在那之后,我跟着课本在dev++打出例题的代码,编译运行,每一次运行成功,小黑窗显示出期待的内容真的是一件令人鼓舞的事情。在简单地跟着课本例题过了一遍C语言大部分知识点后,通过中国大学MOOC、B站、网易公开课等平台继续对知识进行补充。

        当然在学习C语言过程中,测试和期考是必不可少的过程,在第一次上机作业的发布,那时的刚入门C语言,对于解决这种Online Judge的题目还是毫无头绪的,因此一次作业、二次作业并不理想,当时的我还在入门C阶段。到第三次作业发布时,那时已成功入门C,已经能自己解决问题、找解题思路、调试、提交前的数据自测,应该说C语言相关知识我已经掌握了大部分了,基本能解决一些问题,看得懂别人的代码。

        11月14日晚上18:30西综合,期中考试如约而至,确实如老师所说,六题中四题出自平时作业题库,另外两题是新题。而我只做出最基本的三道题,那两道新题,此前未接触过,做不出那就不说了,但是有一题考前我是做过的,就是这篇blog中的题目,超长十进制转换二进制。虽然考前作业做过,但是考试时,我却完全做不出来,失分于这种已经做过的题目真的是耻辱。在考试结束当天晚上,我自己也进行了思考:我真的学会C语言了吗?显然,我接触到的C语言只是皮毛,关于C语言还有很多知识需要去学习并彻底掌握,所以我打算再详细地过一遍C语言,总结知识点,通过网课等途径继续学习C语言相关知识。打好基础真的很重要,总不能等这个学期结课了,C语言还没掌握。同时,我也计划通过重新做OJ题并继续解决问题的总结以加深理解。结合学习C语言和做OJ题的过程,根据实际情况和时间安排,可以写一些blog。

        这就是我写这篇blog的历程,开学这么久,这其实是我的第一篇blog,也是对我学习过程的一个阶段性总结。坚持做有意义的事,总会有收获。

  • 16
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
十进制数转二进制的方法是将十进制不断除以2,将每次的余从下往上排列,直到商为0为止。最后将排列好的余从上往下读取,得到的就是对应的二进制。例如,将十进制13转换为二进制的过程如下:13 ÷ 2 = 6 余 1,6 ÷ 2 = 3 余 0,3 ÷ 2 = 1 余 1,1 ÷ 2 = 0 余 1。将这些余从下往上排列,得到的二进制为1101。\[1\] 十进制数转八进制的方法是将十进制不断除以8,将每次的余从下往上排列,直到商为0为止。最后将排列好的余从上往下读取,得到的就是对应的八进制。例如,将十进制156转换为八进制的过程如下:156 ÷ 8 = 19 余 4,19 ÷ 8 = 2 余 3,2 ÷ 8 = 0 余 2。将这些余从下往上排列,得到的八进制为234。\[2\] 十进制数转十六进制的方法是将十进制不断除以16,将每次的余从下往上排列,直到商为0为止。对于余大于9的情况,可以用A、B、C、D、E、F来表示10、11、12、13、14、15。最后将排列好的余从上往下读取,得到的就是对应的十六进制。例如,将十进制156转换为十六进制的过程如下:156 ÷ 16 = 9 余 12(C),9 ÷ 16 = 0 余 9。将这些余从下往上排列,得到的十六进制为9C。\[1\] 因此,十进制13转换为二进制为1101,转换为八进制为15,转换为十六进制为D。十进制156转换为二进制为10011100,转换为八进制为234,转换为十六进制为9C。 #### 引用[.reference_title] - *1* *2* *3* [二进制、八进制、十进制、十六进制之间的转换](https://blog.csdn.net/qq_39353597/article/details/126417436)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

如何写出最优雅的代码

感谢支持,我将继续努力!

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

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

打赏作者

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

抵扣说明:

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

余额充值