【算法】大数除法

最近在九度oj上看了几个关于大数的问题,特意在这里总结一番。

要知道我们要将一个1000多位的十进制数转换为二进制数,是没有哪个类型能装得下的,所以在这里我们的手动模拟辗转相除法。实现将一个很长的十进制数字符串转换成二进制的字符数组。

首先我们来看看这些int,long等等的取值范围,明白它们到底可以存多大,我们才能放心到底什么时候可以用,什么时候不可以用。

 

数据类型名称 字节数 别名 取值范围
int * signed,signed int 操作系统决定,即与操作系统的"字长"有关
unsigned int * unsigned 由操作系统决定,即与操作系统的"字长"有关
__int8 1 char,signed char –128 到 127
__int16 2 short,short int,signed short int –32,768 到 32,767
__int32 4 signed,signed int –2,147,483,648 到 2,147,483,647
__int64 8 –9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
bool 1 false 或 true
char 1 signed char –128 到 127
unsigned char 1 0 到 255
short 2 short int,signed short int –32,768 到 32,767
unsigned short 2 unsigned short int 0 到 65,535
long 4 long int,signed long int –2,147,483,648 到 2,147,483,647
long long 8 none (but equivalent to __int64) –9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
unsigned long 4 unsigned long int 0 到 4,294,967,295
enum * 由操作系统决定,即与操作系统的"字长"有关
float 4 3.4E +/- 38 (7 digits)
double 8 1.7E +/- 308 (15 digits)
long double 8 1.7E +/- 308 (15 digits)
wchar_t 2 __wchar_t 0 到 65,535

 

 

 

类型标识符 类型说明 长度
(字节)
范围 备注
char 字符型 1 -128 ~ 127 -27 ~ (27 -1)
unsigned char 无符字符型 1 0 ~ 255 0 ~ (28 -1)
short int 短整型 2 -32768 ~ 32767 2-15 ~ (215 - 1)
unsigned short int 无符短整型 2 0 ~ 65535 0 ~ (216 - 1)
int 整型 4 -2147483648 ~ 2147483647 -231 ~ (231 - 1)
unsigned int 无符整型 4 0 ~ 4294967295 0 ~ (232-1)
float 实型(单精度) 4 1.18*10-38 ~ 3.40*1038 7位有效位
double 实型(双精度) 8 2.23*10-308 ~ 1.79*10308 15位有效位
long double 实型(长双精度) 10 3.37*10-4932 ~ 1.18*104932 19位有效位

 


 

具体的转换思想(转载):在数据结构课关于栈的这一章中,我们都学过用“模2取余法”来将一个10进制数转换为一个二进制数,进而可以推广到“模n取余法”,经其转换为n进制(n任意指定)。

确实,这是一个很基础的题目,可你是否想过如果这个10进制数是一个大数(其位数可能上千位,此时用一般数据类型肯定是会溢出的),那么这个问题又如何来求解呢?

当然,也许你会说很简单嘛,自己写一个大数类(当然至少要写一个大数除法才行),或者你用的是Java这种现代化语言,就更轻松了,直接用BigInteger这样的大数类就可以来表示一个大数,进而用书上教的方法来实现。

但是,真的需要用到大数类吗?事实上,“杀鸡焉用牛刀“,我们在纸上模拟一番上述运算后就可以发现,只要做一些小小的改进,就可以在不使用大数的情况下,也可以通过“模n

取余”的原理来实现大数的进制转换的。(当然,整体的思想仍然是“模n取余”原理!!!)。

举个简单的例子,就比如说把10进制数12转换为2进制形式,书上的方法可以用下图来表示

按照 “先余为低位,后余为高位“这条铁律,其结果为1100.

这是书上教我们的常规思路(可惜按这个的话,大数是没法考虑的,因为假如这里不是12,而是一个1000位的大数,由于是是对大数的整体进行取余运算,不使用大数类及其

除法操作,又如何得以进行呢?),可我们的目的是不使用大数类,那么现在我们就来换一个视角来看这个问题,12是一个十位数,十位上是1,个位上是2,按照我们正常的

思维来看,这个计算应该是下面这样的:

那么我们发现在第一轮运算时,十位上的1作为被除数,2作为除数,得到的商是0,余数是1(可以断言只考虑当前这一个数位的计算,余数或是0,或是1,若是1的话,则进

下一数位(这里即对个位进行运算)时,要用1乘上进制(这里是10)再加上下一个数位上的值(这里是2)),即得到运算进入个位时被除数是12,除数是2,得到的商是6,

数是0。第一轮运算的结果是商是06,余数是0.

进入第二轮运算,则上一轮的商6(这里首先要去掉前面多余的0)变成本轮的被除数,如此下去,即可得到每轮的余数。

推广开来,如果被除数是一个1000位的大数,例如“12343435154324123……342314324343”

那么我们照样可以从第一个数位开始逐位考虑,比如第一位是1(作为被除数),2是除数,得到的商是0,余数是1,然后是第二个数位2,由于上一位留下了余数1,则此时被

除数应该是1*10+2 = 12,所以得到的商是6,余数是0,即运算到此时的商是06,然后是第三个数位3,由于上一个数位留下的余数是0,所以此时被除数就是3,。。。如此下去

就完成第一轮的运算,这一轮完毕后,需要把得到的商变成下一轮的被除数,继续上述的运算,直到被除数为0才停止。

 


复制代码
 1 /*题目1138:进制转换
 2 题目描述:
 3 将一个长度最多为30位数字的十进制非负整数转换为二进制数输出。
 4 */
 5 #include "stdafx.h"
 6 #pragma warning(disable:4996)
 7 #include <stdio.h>
 8 #include <cstring>
 9 #include <string>
10 #include <iostream>
11 using namespace std;
12 char binvec[1001];
13 
14 
15 void tenToBin(string str)  
16 {  
17     int j=0;
18     int sum=1;
19     int len=str.size();
20 
21     while (sum)
22     {
23         sum=0;
24         for (int i=0;i<len;++i)
25         {
26             int temp=(str[i]-'0')/2;
27             sum+=temp;
28             if (i==len-1)
29             {
30                 binvec[j++]=(str[i]-'0')%2+'0';
31             }else
32             {
33                 str[i+1]=str[i+1]+(str[i]-'0')%2*10;//算出下一个被除数
34             }
35             //记录该次得出的商
36             str[i]=temp+'0';
37         }
38     }
39     
40 
41 } 
42 void resout()
43 {
44     //逆序
45     int len1=strlen(binvec);
46     for (int i=0,j=len1-1;i<len1/2;++i,--j)
47     {
48         char temp=binvec[j];
49         binvec[j]=binvec[i];
50         binvec[i]=temp;
51     }
52     cout<<binvec<<endl;
53 }
54 int main()
55 {
56     string str;
57     while(cin>>str)
58     {
59         memset(binvec,'\0',sizeof(binvec));
60         tenToBin(str);
61         resout();
62     }
63     return 0;
64 }
复制代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值