C++高精度

高精度算法简介

在C++中当你用int、long long,甚至是unsigned long long 都无法处理的超级巨大数字,你会感到无比痛苦甚至到绝望,那么我们此时就只有一种方法了——高精度算法。

高精度算法:属于处理大数字的数学计算方法,是用计算机对于超大数据的一种模拟加,减,乘,除等运算。对于非常庞大的数字无法在计算机中正常存储,于是,将这个数字拆开,拆成一位一位的存储到一个数组中, 用一个数组去表示一个数字,这样这个数字就被称为是高精度数。

结构体解法

在这里,我们将每个高精度数存为一个结构体就叫BigInt好了,里面最主要的有两个变量:(PS:请务必已经掌握结构体)
1)num[ ]负责记录数字的每一位(num[1]代表个位,num[2]代表十位,num[3]代表百位…)。
2)len负责记录这个数的位数。

这里M为这个数位数的上限。

(PS:static int x 是让所有的高精度数都共用这一个变量,比如说我在第一个高精度数中改变了这个量,那么在剩下的高精度数中就都改变了这个量,可以看作是全局变量,只不过只能在这种结构体里使用而已,在此主要目的是为了优化一下空间,并且使BigInt结构体能够独立)。

接下来给一个初值0,并就连着一起建个清零函数。

结构体不同部分的思路:

  • 读入思路:先按字符数组读进来,再倒着装进int数组里。

  • 输出思路:倒着输出。

  • 比较运算思路(以小于号为例):
    1)比较位数len。
    2)一位一位num的去比较。
    3)还不行…就相等了。

  • 加法思路:一位一位的加,然后进位。
    每次让S.num[i] += num[i] + A.num[i];(记住一定是+=,因为S.num[i]可能因上一位的进位而变为1了)。
    接着判断如果S.num[i]是两位数了,即大于等于10,就进位:让S.num[i] -= 10,S.num[i + 1]++。

  • 减法思路:一位一位的减,然后借位。
    每次让S.num[i] += num[i] - A.num[i];
    接着判断如果S.num[i]小于0了,就向高一位借1:让S.num[i] += 10,S.num[i + 1]–。

  • 乘法思路:一位一位的去相乘,之后进位
    假设要让this的第i位与A的第j位相乘:
    举个例子,条件如下表,
    可以知道this.num[5] * A.num[3]加在了第7位,即(3 + 5 - 1)位。
    经推导可知this.num[i] * A.num[j]加在了第(i + j - 1)位
    dasadasdas
    这样每次让S.num[i + j - 1] += num[i] * A.num[j],之后再进位就行了。

  • 除法思路:列竖式。

    你可以根据上图,并结合文字来理解。
    开一个新的数R = 0,让它来记录现在的剩余,每次R的末尾加上一个num[i](R = R * 10 + num[i]),之后用此时的R去除以A.num[i]得出的商记为S.num[i],余数覆盖到R上,一直循环下去。最后将S整体反过来就OK了!(貌似说地太简略了)

  • 取余思路:因为除后的结果是取整的,所以令S = this - (this / A) * A就OK了。

接下来就是结构体形式的代码了。

# include <cstdio>
# include <iostream>
# include <cstring>
# include <algorithm>
# include <cmath>

using namespace std;

# define FOR(i, a, b) for(int i = a; i <= b; i++)
# define _FOR(i, a, b) for(int i = a; i >= b; i--)

struct BigInt
{
    static const int M = 1000;
    int num[M + 10], len;

    BigInt() { clean(); }	

	void clean(){
    	memset(num, 0, sizeof(num));
    	len = 1;
	}

    void read(){
    	char str[M + 10];
        scanf("%s", str);
        len = strlen(str);
        FOR(i, 1, len)
            num[i] = str[len - i] - '0';
    }

    void write(){
        _FOR(i, len, 1)
            printf("%d", num[i]);
        puts("");
    }
    
    void itoBig(int x){
    	clean();
    	while(x != 0){
    		num[len++] = x % 10;
    		x /= 10;
		}
		if(len != 1) len--;
	}

    bool operator < (const BigInt &cmp) const {
        if(len != cmp.len) return len < cmp.len;
        _FOR(i, len, 1)
            if(num[i] != cmp.num[i]) return num[i] < cmp.num[i];
        return false;
    }

    bool operator > (const BigInt &cmp) const { return cmp < *this; }
	bool operator <= (const BigInt &cmp) const { return !(cmp < *this); }
	bool operator != (const BigInt &cmp) const { return cmp < *this || *this < cmp; }
	bool operator == (const BigInt &cmp) const { return !(cmp < *this || *this < cmp); }

    BigInt operator + (const BigInt &A) const {
        BigInt S;
        S.len = max(len, A.len);
        FOR(i, 1, S.len){
            S.num[i] += num[i] + A.num[i];
            if(S.num[i] >= 10){
                S.num[i] -= 10;
                S.num[i + 1]++;
            }
        }
        while(S.num[S.len + 1]) S.len++;
        return S;
    }

    BigInt operator - (const BigInt &A) const {
        BigInt S;
        S.len = max(len, A.len);
        FOR(i, 1, S.len){
            S.num[i] += num[i] - A.num[i];
            if(S.num[i] < 0){
                S.num[i] += 10;
                S.num[i + 1]--;
            }
        }
        while(!S.num[S.len] && S.len > 1) S.len--;
        return S;
    }

    BigInt operator * (const BigInt &A) const {
        BigInt S;
        if((A.len == 1 && A.num[1] == 0) || (len == 1 && num[1] == 0)) return S;
        S.len = A.len + len - 1;
        FOR(i, 1, len)
            FOR(j, 1, A.len){
                S.num[i + j - 1] += num[i] * A.num[j];
                S.num[i + j] += S.num[i + j - 1] / 10;
                S.num[i + j - 1] %= 10;
            }
        while(S.num[S.len + 1]) S.len++;
        return S;
    }

    BigInt operator / (const BigInt &A) const {
        BigInt S;
        if((A.len == 1 && A.num[1] == 0) || (len == 1 && num[1] == 0)) return S;
        BigInt R, N;
        S.len = 0; 
        _FOR(i, len, 1){
        	N.itoBig(10);
			R = R * N;
			N.itoBig(num[i]);
			R = R + N;
        	int flag = -1;
        	FOR(j, 1, 10){
        		N.itoBig(j);
        		if(N * A > R){
        			flag = j - 1;
        			break;
				}
			}
			S.num[++S.len] = flag;
			N.itoBig(flag);
			R = R - N * A;
		}
		FOR(i, 1, S.len / 2) swap(S.num[i], S.num[len - i + 1]);
		while(!S.num[S.len] && S.len > 1) S.len--;
        return S;
    }
    
    BigInt operator % (const BigInt &A) const {
    	BigInt S;
    	BigInt P = *this / A;
    	S = *this - P * A;
    	return S;
    }
};

int main()
{
	return 0;
}

函数解法

思路大体与上述一样,只不过这次用string来写一些函数而已。
(PS:开头的NR是指位数的上限)

函数形式的代码。

# include <cstdio>
# include <iostream>
# include <cstring>
# include <algorithm>
# include <cmath>

using namespace std;

# define FOR(i, a, b) for(int i = a; i <= b; i++)
# define _FOR(i, a, b) for(int i = a; i >= b; i--)

const int NR = 1000;

bool STRcompare(string str1, string str2){
	int len1 = str1.size(), len2 = str2.size();
    if(len1 != len2) return len1 < len2;
    FOR(i, 0, len1 - 1)
        if(str1[i] != str2[i]) return str1[i] < str2[i];
    return false;
}

string STRaddition(string str1, string str2){
    int sum[NR + 10], a[NR + 10], b[NR + 10];
    memset(sum, 0, sizeof(sum));
    memset(a, 0, sizeof(a));
    memset(b, 0, sizeof(b));
    int len1 = str1.size(), len2 = str2.size();
    FOR(i, 1, len1) a[i] = str1[len1 - i] - '0';
    FOR(i, 1, len2) b[i] = str2[len2 - i] - '0';
    int lenS = max(len1, len2);
    FOR(i, 1, lenS){
        sum[i] += a[i] + b[i];
    	if(sum[i] >= 10){
            sum[i] -= 10;
            sum[i + 1]++;
    	}
    }
    while(sum[lenS + 1]) lenS++;
    string ans;
    _FOR(i, lenS, 1) ans += sum[i] + '0';
    return ans;
}

string STRsubtraction(string str1, string str2){
    int sum[NR + 10], a[NR + 10], b[NR + 10];
    memset(sum, 0, sizeof(sum));
    memset(a, 0, sizeof(a));
    memset(b, 0, sizeof(b));
    if(STRcompare(str1, str2)) swap(str1, str2);
    int len1 = str1.size(), len2 = str2.size();
    FOR(i, 1, len1) a[i] = str1[len1 - i] - '0';
    FOR(i, 1, len2) b[i] = str2[len2 - i] - '0';
    int lenS = max(len1, len2);
    FOR(i, 1, lenS){
        sum[i] += a[i] - b[i];
    	if(sum[i] < 0){
            sum[i] += 10;
            sum[i + 1]--;
    	}
    }
    while(sum[lenS] == 0 && lenS > 1) lenS--;
    string ans;
    _FOR(i, lenS, 1) ans += sum[i] + '0';
    return ans;
}    

string STRmultiplication(string str1, string str2){
	if(str1.size() == 1 && str1[0] == '0') return str1;
	if(str2.size() == 1 && str2[0] == '0') return str2;
	int sum[NR + 10], a[NR + 10], b[NR + 10];
    memset(sum, 0, sizeof(sum));
    memset(a, 0, sizeof(a));
    memset(b, 0, sizeof(b));
    int len1 = str1.size(), len2 = str2.size();
    FOR(i, 1, len1) a[i] = str1[len1 - i] - '0';
    FOR(i, 1, len2) b[i] = str2[len2 - i] - '0';
    int lenS = len1 + len2 - 1;
    FOR(i, 1, len1)
        FOR(j, 1, len2){
            sum[i + j - 1] += a[i] * b[j];
            sum[i + j] += sum[i + j - 1] / 10;
        	sum[i + j - 1] %= 10;
        }
    while(sum[lenS + 1]) lenS++;
    string ans;
    _FOR(i, lenS, 1) ans += sum[i] + '0';
    return ans;
}

string char_to_string(char c){
	string str;
	str += c;
	return str;
}

string int_to_string(int x){
	int a[NR + 10], len = 0;
	while(x != 0){
		a[++len] = x % 10;
		x /= 10;
	}
	string str;
	_FOR(i, len, 1) str += a[i] + '0';
	if(len == 0) str = "0";
	return str;
}

string STRdivision(string str1, string str2){
    if(str1.size() == 1 && str1[0] == '0') return str1;
	if(str2.size() == 1 && str2[0] == '0') return str2;
	if(STRcompare(str1, str2)) swap(str1, str2);
	string R = "0", ans;
	bool not_zero = false;
    FOR(i, 0, str1.size() - 1){
		R = STRaddition(STRmultiplication(R, "10"), char_to_string(str1[i]));
        int flag = -1;
        FOR(j, 1, 10)
        	if(STRcompare(R, STRmultiplication(int_to_string(j), str2))){
        		flag = j - 1;
        		break;
			}
		if(flag != 0 || not_zero){
			ans += flag + '0';
			not_zero = true;
		}
		R = STRsubtraction(R, STRmultiplication(int_to_string(flag), str2));
	}
    return ans;
}

string STRremainder(string str1, string str2){
	if(str1.size() == 1 && str1[0] == '0') return str1;
	if(str2.size() == 1 && str2[0] == '0') return str2;
	if(STRcompare(str1, str2)) swap(str1, str2);
    string P = STRdivision(str1, str2);
    string ans = STRsubtraction(str1, STRmultiplication(P, str2));
    return ans;
};

int main()
{
	return 0;
}

God Bless You For Ever!

发布了33 篇原创文章 · 获赞 47 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/SkeletonKing233/article/details/92200315