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

本文详细介绍了如何处理超长十进制数转换为二进制数的问题,包括理解除法过程、进制转换核心和代码实现策略。通过示例代码展示了如何用C语言处理超出基本数据类型范围的大数,以及如何进行大数除法和进制转换。文章还分享了作者从C语言入门到逐步掌握进制转换的心路历程,强调了扎实基础知识的重要性。
  • 问题描述

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,也是对我学习过程的一个阶段性总结。坚持做有意义的事,总会有收获。

<think>嗯,用户想了解如何用代码将十进制数换为二进制数。首先,我得回忆一下十进制进制的常规方法,比如除2取余法。然后,考虑不同的编程语言可能有不同的实现方式,但用户可能希望看到通用的思路或者某种具体语言的例子,比如Python,因为Python比较常用。 接下来,我需要确定步骤是否正确。比如,处理0的情况,因为如果输入是0,直接返回0就可以了。然后是处理负数的情况,用户可能没有提到,但应该考虑是否需要处理,或者假设输入是正整数。通常,在基础教程中可能只考虑正整数,但最好还是说明一下。 然后,考虑如何将除2取余的过程用代码实现。可能需要一个循环,不断除以2,记录余数,直到商为0。余数需要反向排列,因为最后得到的余数是二进制的高位。比如,十进制数10除以2得到余数0,商5;再除以2,余数1,商2;继续下去,余数0,商1;最后除以2余数1,商0。收集的余数是0,1,0,1,反过来就是1010,所以二进制1010。 那代码如何实现呢?可以用一个循环,在Python中,可以用while循环,然后每次取余数,添加到列表的前面,或者最后反列表。比如,初始化一个空列表,每次得到的余数插入到列表的前面,这样就不需要反了。或者,先添加到列表,最后反。 比如,对于n=10,余数依次是0,1,0,1,如果每次插入到前面,那么列表会是[0], [1,0], [0,1,0], [1,0,1,0]。或者先收集余数,然后反。哪种更高效?可能第二种,因为列表在前面插入元素的时间复杂度是O(n),而后面添加是O(1),最后反一次是O(n)。所以对于大数来说,后面添加再反可能更好。 另外,Python中还有内置函数bin(),可以直接返回二进制字符串,但用户可能希望自己实现算法,而不是用内置函数。所以应该说明这两种方法,但重点放在手动实现上。 此外,处理0的情况,如果输入是0,直接返回'0'。否则,如果输入是负数,可能需要处理符号,或者给出提示。假设用户输入的是正整数,但代码中应该包括对0的处理。 比如,在代码示例中,可以先检查n是否为0,如果是,返回'0'。否则,处理正整数的情况。 所以,可能的步骤是: 1. 处理特殊情况:n=0 → 返回'0'。 2. 处理负数:可能需要取绝对值并添加负号,但用户可能只需要处理正整数,所以假设n是正整数。 3. 初始化一个空列表来存储余数。 4. 循环:当n>0时,取余数n%2,添加到列表,然后n = n//2。 5. 反余数列表,组合成字符串。 或者,在循环中,余数是从低位到高位生成的,所以需要反得到正确的二进制顺序。 例如,10的余数依次是0,1,0,1,反后得到1010。 所以,代码的致结构是: def decimal_to_binary(n): if n == 0: return '0' binary_digits = [] while n > 0: remainder = n % 2 binary_digits.append(str(remainder)) n = n // 2 binary_digits.reverse() return ''.join(binary_digits) 测试一下这个函数是否正确。比如输入10,得到的列表是[0,1,0,1],反后是[1,0,1,0],所以结果是'1010',正确。输入0,返回'0'。输入1,返回'1'。输入2,得到'10',对吗?是的。这样看起来是正确的。 另外,用户可能需要递归的方法,但可能更复杂。或者用位运算,比如不断右移并取最低位,但和除以2的方法类似。 然后,在回答中,需要分步骤说明,先讲算法步骤,再给出代码示例,同时提到内置函数,但强调手动实现的方法。需要注意代码的正确性,比如Python中的整数除法是//,而/会得到浮点数,所以必须用//。 总结一下,用户的疑问可能包括: - 如何手动实现十进制进制的算法。 - 如何处理特殊情况,如0。 - 不同编程语言的实现方式,但可能以Python为例。 所以,回答的结构应该是: 1. 算法原理:除2取余,逆序排列。 2. 处理特殊情况:n=0。 3. 代码实现(Python示例)。 4. 测试示例。 5. 补充说明(内置函数)。 同时,提醒用户注意负数的情况,是否需要处理,或者在代码中添加对负数的判断。 可能还需要指出,上述代码仅适用于正整数,如果需要处理负数,可以采用补码或其他方式,但这可能超出基础范围。 最后,确保代码示例正确,语法正确,并且解释清晰。</think>将十进制数换为二进制数的核心算法是**除2取余法**。以下是分步说明及Python实现示例: --- ### 一、算法原理 1. **除2取余**:将十进制数不断除以2,记录每次的余数。 2. **逆序排列**:将所有余数按计算的**反向顺序**组合,即得到二进制结果。 3. **特殊情况**:若十进制数为0,直接返回`'0'`。 --- ### 二、Python代码实现 ```python def decimal_to_binary(n): if n == 0: return '0' # 处理0的特殊情况 binary_digits = [] is_negative = n < 0 n = abs(n) # 处理负数(可选,根据需求添加) while n > 0: remainder = n % 2 binary_digits.append(str(remainder)) n = n // 2 # 注意:必须用整数除法 # 逆序余数并组合成字符串 binary_str = ''.join(reversed(binary_digits)) # 添加负号(可选) return '-' + binary_str if is_negative else binary_str ``` --- ### 三、示例测试 ```python print(decimal_to_binary(10)) # 输出: 1010 print(decimal_to_binary(0)) # 输出: 0 print(decimal_to_binary(127)) # 输出: 1111111 print(decimal_to_binary(-5)) # 输出: -101(需启用负数处理) ``` --- ### 四、补充说明 1. **内置函数**:Python中可直接用`bin(n)`,例如`bin(10)`返回`'0b1010'`,截取下标2后得到`'1010'`。 2. **负数处理**:代码中可选添加对负数的支持(返回带负号的二进制字符串)。 3. **其他语言**:算法逻辑通用,只需调整语法(如Java用`Integer.toBinaryString(n)`)。 --- ### 五、关键点总结 - **核心步骤**:循环除以2 → 记录余数 → 逆序结果。 - **时间复杂度**:$O(\log n)$,与二进制位数成正比。 - **边界条件**:始终优先检查输入是否为0。 如有其他需求(如浮点数换),可进一步扩展算法!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

如何写出最优雅的代码

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

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

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

打赏作者

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

抵扣说明:

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

余额充值