大数加(2大数) 乘 除 取余(一大数) + 大数m进制转n进制

两大数相加,一大一小相乘,相除,取余,这类的大数相对简单,只需要用字符串细心模拟计算过程即可。

m转n进制:

  • 先将m进制转10进制:
    • 从低位到高位遍历m进制每一位,乘以相应的权值(m^0, m^1…)加和即可
  • 在将10进制转化为n进制:
    • 除n取余法

如果加上 大数 , 就先将主体写清楚,具体的加法,乘除,取余,就用大数模拟。

详细的写在代码注释:

#include <bits/stdc++.h>
using namespace std ;
const int AX = 1e6 + 666 ;
char s[AX] ;	// 存储要转为n进制的m进制大数
char res[AX] ;  // 存储10->n进制的结果
int a[AX] , b[AX] ; // a[]:在m转10进制过程中,存储每次的s[i]*m^base   b[]:存储m进制转为10进制的结果
int k , kb , tot ;  // k : a[]索引,kb:b[]索引 , tot : res[]索引
int m , n ; 		// m -> n 进制

void add() {       //大数加法:两个大数存于a[],b[],结果覆盖在b[],长度kb(索引起止:1->kb)
	int len = max( k , kb );
	int c = 0 ;
	for( int i = 1 ; i <= len ; i++ ) {
		b[i] = b[i] + a[i] + c ;
		c = b[i] / 10000 ;
		b[i] %= 10000 ;
	}
	if( c ) b[++len] += c ;
	kb = len ;
}
 /*大数乘法(一个大数,一个非大数<这里是进制m和m进制每位置的数>相乘),
 结果存于a[],长度k,索引起止 1-k*/
void mul( int num , int x ) {
	for( int i = 1 ; i <= num ; i++ ) { //从低位到高位,幂次为num,则乘num次(m^num)
		int c = 0 ;
		for( int j = 1 ; j <= k ; j++ ) { 
			a[j] = a[j] * x + c ;
			c = a[j] / 10000 ;
			a[j] %= 10000 ;
		}
		if( c ) a[++k] = c ;
	}
}
/*大数取余,一个大数存于b[],要转n进制,故对非大数n取余*/
int module() {
	int remain = 0 ;
	for( int i = kb ; i >= 1 ; i-- ) {  //从高位开始除,模拟除法过程
		int t = ( remain * 10000 + b[i] ) / n ; //因为从高位,且每个位置存10000,故余数*10000
		int r = ( remain * 10000 + b[i] ) % n ;
		remain = r ;
	}
	return remain ;
}
/*大数除法,一个大数存于b[],要转n进制,除以n*/
void div() {
	int remain = 0 ;
	for( int i = kb ; i >= 1 ; i-- ) {
		int t = ( remain * 10000 + b[i] ) / n ;
		int r = ( remain * 10000 + b[i] ) % n ;
		b[i] = t ;
		remain = r ;
	}
	for( int i = 1 ; i <= kb ; i++ ) {  //去除高位0
		if( !b[i] ) {
			kb = max( 0 , i - 1 ) ;
			break ;
		}
	}
}

void ten_to_n() { // 10进制b[]转n进制的除n取余法主体,结果存于res[],长度tot,索引起止[0,tot).
	tot = 0 ;
	while(1) {
		int r = module() ;  //b[]对n取余,结果存于r
		if( r >= 10 ) res[tot++] = r - 10 + 'A';
		else res[tot++] = r + '0' ;
		div(); 	//对b[]做除法
		if( !b[kb] ) break ; //被除数为0,跳出循环
	}

}
void m_to_ten( int len ) { //m进制转10进制
	int base = 0 ;     	//每位对应的权,如2转10进制,第一位2^0 ,第二位2^1...
	kb = 1 ;
	memset( b , 0 ,sizeof(b) );
	for( int i = len - 1 ; i >= 0 ; i-- ) { 
		k = 1 ;
		a[1] = 1 ;
		int x ;
		mul(base,m) ;//得到每一位处要乘的权值
		if( s[i] >= '0' && s[i] <= '9' ) x = (int)(s[i]-'0');  //处理10进制以上的符号表示
		else {
			if( s[i] >= 'a' && s[i] <= 'z' ) s[i] = s[i] - 'a' + 'A' ;
			x = ( 10 + (int)(s[i]-'A') ) ;
		} 
		mul(1,x); //将每一位x与权相乘
		add();    //加和每次的x*m^base,得到b[],即10进制形式
		base ++ ;
	}
	ten_to_n();   //m进制转十进制成功,存于b[],开始用10进制转n进制
}
int main() {
	scanf("%d",&m);
	scanf("%s",s);
	scanf("%d",&n);
	int len = strlen(s);
	m_to_ten(len);
	/*
	print the result of m_to_len : verified   测试转10进制结果

	int f = 0 ;
	for( int i = kb ; i >= 1; i-- ) {
		if( i == k && !b[i] ) continue ;
		if( f ) printf("%04d",b[i]);
		else {
			printf("%d",b[i]);
			f = 1 ;
		}
	}
	printf("\n");
	*/
	for( int i = tot - 1 ; i >= 0 ; i-- ) {  //最终10进制转n进制的结果
		printf("%c",res[i]);
	}
	printf("\n");
	return 0 ;
}

猜你喜欢

转载自blog.csdn.net/FrankAx/article/details/104753239