大数高精度加减、乘除、开根(C++版全套最详细、最易懂)

大数高精度加减、乘除、开根

  • 一、前面铺垫
  • 二、加法
  • 三、减法
  • 四、乘法
  • 五、除法
  • 六、开根(待完善)

  大数高精度加减乘除主要用在超过long型的数字计算(比如1000位数), 最基本的思路就是换成string类型变量 / char数组进行计算,小白在这里胡说八道,有不足的欢迎大大、juju们斧正v( •̀ ω •́ )✧

大数高精度加减、乘除、开根(C++版全套最详细、最易懂)_第1张图片

一、前面铺垫

  这里主要用到两个函数,moveFrontZero()用来去除前面的0且一般用在最后将要输出结果的时候,align()用来给短的数字补0至两个数有相同位数(相同长度)。

/** 去除前面的0 */
void moveFrontZero(string &res){
    res.erase(0, res.find_first_not_of('0'));
    if(res.empty()) res = "0";
}

/** 补位对齐并返回最长的长度 */
int align(string &a, string &b){
    while(a.length() < b.length()) a = "0" + a;
    while(b.length() < a.length()) b = "0" + b;
    return a.length();
}

二、加法

  从最低位(个位)开始对应相加,超过10就进位+1,通过拼接字符串形成计算结果。
  可对应洛谷题:洛谷题

string add(string &a, string &b){
    string res;
    int len = align(a, b);
    for(int i = len-1; i >= 0; i--){
        int num1 = a[i] - '0';
        int num2 = b[i] - '0';
        if(num1 + num2 > 9 && i != 0){
            a[i-1]  = a[i-1] - '0' + 1 + '0';
            res = to_string(num1 + num2 - 10) + res;	//字符串拼接
        }
        else res = to_string(num1+num2) + res;
    }
    moveFrontZero(res);
    return res;
}

三、减法

  从低位开始对应相减,不够减就从借位减一。这里实现的还不是很优(有待优化),因为有个前提——两个数都必须是整数且不是负数。

string sub(string &a, string &b){       //subduction
    string res;
    int len = align(a, b);
    bool flag = false;		//用来判断最后结果是否为负数
    if(a<b){
        flag = true;
        a.swap(b);              //确保a是最大数
    }
    for(int i = len-1; i >= 0; i--){
        int num1 = a[i] - '0';
        int num2 = b[i] - '0';
        if(num1 < num2){
        	// -'0'-1是为了借位,+'0'是为了还原成char类型字符
            a[i-1] = a[i-1]-'0' - 1 + '0';
            res = to_string(num1+10 - num2) + res;
        }else{
            res = to_string(num1 - num2) + res;
        }
    }
    moveFrontZero(res);
    if(flag) res = "-" + res;
    return res;
}

四、乘法

 主要思想是把乘法转换成加法运算,分割相对小的数,如:
12345×24 可分割24成4个12345相加,20个123456相加(也就是2个123450相加),即 12345×24 = 4×12345 + 2×123450

/**
 * 版本一:通过string处理
 */
string mul(string &a, string &b){
    string res = "0";
    align(a, b);
    if(a < b) a.swap(b);       //固定:a永远是最大的,b永远是最小的
    for(int i = b.size()-1; i >= 0; i--){
        int num1 = b[i] - '0';
        if(i != b.size()-1) a = a + "0";
        for(int j = 0; j < num1; j++)
            res = add(res, a);
    }
    moveFrontZero(res);
    return res;
}

/**
 * 版本二:通过vector处理
 */
vector<int> mul(vector<int> a, int b){
	vector<int> c;
	int t = 0;			//进位
	for(int i = 0; i < a.size(); i++){
		t += a[i] * b;
		c.push_back(t % 10);
		t /= 10;
	}
	while(y){
		c.push_back(t % 10);
		t /= 10;
	}
	return c;
}

int main(){
	...
	vector<int> res;
	res.push_back(1);
	...
	for(int i = res.size()-1; i >= 0; i--)
		printf("%d", res[i]);
	puts("");
	return 0;
}

  看下图数据更易懂~
首先初始化
大数高精度加减、乘除、开根(C++版全套最详细、最易懂)_第2张图片
循环加上4次加上12345后结果res=49380
大数高精度加减、乘除、开根(C++版全套最详细、最易懂)_第3张图片
重复,循环2次加上123450,res=296280
大数高精度加减、乘除、开根(C++版全套最详细、最易懂)_第4张图片

五、除法

  这里用的是算商数、余数的除法,而直接除的算法有待研究和优化。
链接:大数除法
下面附上链接里算法的修正版式

string div(string &a, string &b){
    string res;
    stringstream sstream;		//定义个字符串流
    //被除数 除数 余数
    int dividend, divisor = stoi(b), remainder = 0, i;	 
	for(i = 0; i < a.length()-1; i++){
		dividend = (a[i] - '0') + remainder*10;
		if(dividend >= divisor){
            sstream << dividend / divisor;
			remainder = dividend % divisor;
		}
		else{
			//数字的首位小于除数时,不打印0
			if(i != 0) sstream << "0";		
			remainder = dividend;
		}
	}
	dividend = (a[i] - '0') + remainder*10;		//处理最后一位数
	string temp;
	sstream >> temp;
 	res =  temp + to_string(dividend / divisor) + "......" + to_string(dividend % divisor);
	moveFrontZero(res);
	return res;
}

六、开根(待完善)

  题目链接:题目跳转

你可能感兴趣的:(算法学习,c++,算法)