1.大整数的存储
大整数存储用于基本数据类型无法存储的高精度整数,整数的高位存在数组的高位,整数的低位存在数组的低位。
(1)大整数初始化结构体代码:
struct bign{
//存储大整数,这里设置可存储的最大为1000位
int d[1000];
int len;
bign(){//初始化结构体
//memset将数组d的所有元素赋值为0
memset(d,0,sizeof(d));
len = 0;
}
};
(2)输入大整数时,先用字符串读入,再把字符串另存为到bign结构体。由于使用char数组读入时,整数的高位会变成数组的低位,因此为了让整数在bign中为顺位存储,得让字符串逆着赋值给d数组。
代码:
bign change(char str[]){//将整数转化为bign
bign a;
a.len = strlen(str);
//bign的长度就是字符串的长度
for(int i = 0 ; i < a.len ; i ++){
//逆着赋值
a.d[i] = str[a.len - i - 1] - '0';
}
return a;
}
(3)大整数比较
如果比较两个bign变量的大小:先判断两者的len大小,如果不相等,长的为大;若相等,则依次从高位到低位进行比较,知道出现某一位不等,大的数字为大。
代码:
int compare(bign a, bign b){
//比较ab大小,前者大返回1,后者大返回-1,否则返回0
if(a.len < b.len){
return -1;
}
else if(a.len > b.len){
return 1;
}
else{
for(int i = a.len - 1 ; i >= 0 ; i ++){
if(a.d[i] > b.d[i]){
return 1;
}
else if(a.d[i] < b.d[i]){
return -1;
}
}
}
return 0;
}
2.高精度加法
对一位进行加法,就是将该位上的两个数字与进位相加,得到的结果作为该位结果,取十位数作为新的进位。然后从低位到高位重复该步骤。
代码:
bign add(bign a, bign b){//加法
bign c;
int carry = 0;//carry是进位
for(int i = 0 ; i < a.len || i < b.len ; i ++){//以较长的为界限
int temp = a.d[i] + b.d[i] + carry;//两个对应位与进位相加
c.d[c.len++] = temp % 10;//个位数为该位结果
carry = temp / 10;//十位数为新的进位
}
if(carry != 0){//最后进位不为0,直接赋值给结果的最高位
c.d[c.len++] = carry;
}
return c;
}
3.高精度减法
对某一步,比较被减位和减位,若不够减,则令被减位的高位减1,被减位加10再进行减法;如果够减,则直接减。最后一步时,要注意减法后高位可能有多余的0,要去除它们,但也要保证结果至少有1位数。
代码:
bign sub(bign a, bign b){//减法
bign c;
int carry = 0;//carry是退位
for(int i = 0 ; i < a.len || i < b.len ; i ++){//以较长的为界限
int temp = a.d[i] - b.d[i] - carry; //存储当前位
if(temp >= 0){//没有借位,carry = 0
c.d[c.len++] = temp;
carry = 0;
}else{//不够减 , 高位借1, 低位加10
c.d[c.len++] = temp + 10;
carry += 1;
}
}
while(c.len - 1 >= 1 && c.d[c.len - 1] == 0){//除去最高位的0,保留最低一位
c.len --;
}
return c;
}
4.高精度与低精度的乘法
取bign 的某位与int型整体进行相乘,再与进位相加,所得结果的个位数作为该位结果,高位部分作为新的进位。
代码:
bign multi(bign a, int b){//高精度与低精度的乘法
bign c;
int carry = 0;//进位
for(int i = 0 ; i < a.len ; i ++){
int temp = a.d[i]*b + carry; //当前存储值
c.d[c.len++] = temp % 10; //个位作为当前位的结果
carry = temp / 10; //更高位的进位
}
while(carry != 0){
c.d[c.len++] = carry % 10;
carry /= 10;
}
return c;
}
5.高精度与低精度的除法
上一步的余数乘以10加上该步的位的值,得到该步临时的被除数,将其与除数比较;若不够除,则该位的商为0;若够除,商即为对应的商,余数即为对应的余数。最后一步要注意减法后高位可能有多余的0,要去除它们,但也要保证结果至少有一位数。
代码:
bign divide(bign a, int b, int& r){
//高精度与低精度的除法
//r为余数
bign c;
c.len = a.len; //被除数的每一位和商的每一位是一一对应的,因此先令长度相等
for(int i = a.len -1 ; i >= 0 ; i --){ //从高位开始
r = r * 10 + a.d[i];//和上一位遗留的余数组合,临时的被除数
if(r < b) c.d[i] = 0;//不够除,该位为0
else{ //够除
c.d[i] = r / b; //商
r = r % b; //新的余数
}
}
while(c.len - 1 >= 1 && c.d[c.len - 1] == 0){
c.len --; //去除高位的0,至少保留一位最低位
}
return c;
}
6.总代码示例
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct bign{
int d[1000];
int len;
bign(){
memset(d,0,sizeof(d));
len = 0;
}
};
bign change(char str[]){//将整数转化为bign
bign a;
a.len = strlen(str); //bign的长度就是字符串的长度
for(int i = 0 ; i < a.len ; i ++){
a.d[i] = str[a.len - i - 1] - '0';//逆着赋值
}
return a;
}
bign add(bign a, bign b){//加法
bign c;
int carry = 0;//carry是进位
for(int i = 0 ; i < a.len || i < b.len ; i ++){//以较长的为界限
int temp = a.d[i] + b.d[i] + carry;//两个对应位与进位相加
c.d[c.len++] = temp % 10;//个位数为该位结果
carry = temp / 10;//十位数为新的进位
}
if(carry != 0){//最后进位不为0,直接赋值给结果的最高位
c.d[c.len++] = carry;
}
return c;
}
int compare(bign a, bign b){//比较ab大小,前者大返回1,后者大返回-1,否则返回0
if(a.len < b.len){
return -1;
}
else if(a.len > b.len){
return 1;
}
else{
for(int i = a.len - 1 ; i >= 0 ; i ++){
if(a.d[i] > b.d[i]){
return 1;
}
else if(a.d[i] < b.d[i]){
return -1;
}
}
}
return 0;
}
bign sub(bign a, bign b){//减法
bign c;
int carry = 0;//carry是退位
for(int i = 0 ; i < a.len || i < b.len ; i ++){//以较长的为界限
int temp = a.d[i] - b.d[i] - carry; //存储当前位
if(temp >= 0){//没有借位,carry = 0
c.d[c.len++] = temp;
carry = 0;
}else{//不够减 , 高位借1, 低位加10
c.d[c.len++] = temp + 10;
carry += 1;
}
}
while(c.len - 1 >= 1 && c.d[c.len - 1] == 0){//除去最高位的0,保留最低一位
c.len --;
}
return c;
}
bign multi(bign a, int b){//高精度与低精度的乘法
bign c;
int carry = 0;//进位
for(int i = 0 ; i < a.len ; i ++){
int temp = a.d[i]*b + carry; //当前存储值
c.d[c.len++] = temp % 10; //个位作为当前位的结果
carry = temp / 10; //更高位的进位
}
while(carry != 0){
c.d[c.len++] = carry % 10;
carry /= 10;
}
return c;
}
bign divide(bign a, int b, int& r){//高精度与低精度的除法 //r为余数
bign c;
c.len = a.len; //被除数的每一位和商的每一位是一一对应的,因此先令长度相等
for(int i = a.len -1 ; i >= 0 ; i --){ //从高位开始
r = r * 10 + a.d[i];//和上一位遗留的余数组合,临时的被除数
if(r < b) c.d[i] = 0;//不够除,该位为0
else{ //够除
c.d[i] = r / b; //商
r = r % b; //新的余数
}
}
while(c.len - 1 >= 1 && c.d[c.len - 1] == 0){
c.len --; //去除高位的0,至少保留一位最低位
}
return c;
}
void print(bign a){//输出bign
for(int i = a.len - 1 ; i >= 0 ; i --){
cout<<a.d[i];
}
}
int main(){
char s1[1000],s2[1000];
int c,r = 0;
scanf("%s%d",s1,&c);
//scanf("%s%s",s1,s2);
bign a = change(s1);
print(divide(a, c, r));除法
cout<<endl;
cout<<r;//余数
//print(multi(a,c));乘法
//bign b = change(s2);
/*int k = compare(a,b);//正负系数
if(k > 0){//说明a > b
print(sub(a,b));
}else if(k < 0){
cout<<"-";
print(sub(b,a));
}else{
cout<<0;
} *///减法
//cout<<endl;
//print(add(a,b)); 加法
return 0;
}