有些计算要求精度高,希望计算的数的位数可达数十位或数百位,但因受到硬件的限制,往往很难达到实际问题所要求的精度。
(1)数据的接收方式/存贮方法:
输入的数很长,则可采用字符串方式输入,这样可输入位数很长的数,利用字符串函数和操作运算,将每一位数取出,存入数组。
void init(int a[]) //传入一个数组
{
string s;
cin>>s; //读入字符串s
len=s.length(); //用len计算字符串s的位数
for(i=1;i<=len;i++)
a[i]=s[len-i]-'0'; //将字符串s转换为数组a,并倒序储存
}
另一种方法是直接用循环加数组方法输入数据。
(2)高精度位数的确定
位数的确定:接受时往往是用字符串的,所以它的位数就等于字符串的长度。
(3)进位,借位处理(先简单理解)
加法进位:
c[i]=a[i]+b[i];
if(c[i]>=10)//进位条件
{
c[i]%=10;++c[i+1];//取余和进位
}
减法借位:
if(a[i]
乘法进位:
c[i+j-1]=a[i]*b[j]+x+c[i+j-1];
x=c[i+j-1]/10;
c[i+j-1]%=10;
商与余数处理:
与除数与被除数的位数(精度)情况进行处理。分为(1).高精除以低精 (2).高精除以高精
(1)高精度加法,2个正整数求和
#include
#include
#include
using namespace std;
int main()
{
char ca[100], cb[100];
int a[100], b[100], c[100], a_len, b_len, c_len, i, x;
memset(a, 0, sizeof(a));//memset()函数作用是在字符串a中,
memset(b, 0, sizeof(a));//从第一个存储单位开始,将后面
memset(c, 0, sizeof(a));//sizeof(a)个空间全部置为'\0',达到初始化字符串的目的。
gets_s(ca);//低版本可用gets()函数,c++中头文件为#includ
gets_s(cb);//输入两个相加的数
a_len = strlen(ca);
b_len = strlen(cb);
for (i = 0; i <= a_len - 1; i++)
{
a[a_len - i] = ca[i] - '0';//数组ca的字符型整数转化为整形放入数组a中,注意逆序
}
for (i = 0; i <= b_len - 1; i++)
{
b[b_len - i] = cb[i] - '0';//数组cb的字符型整数转化为整形放入数组b中,注意逆序
}
c_len = 1;
x = 0;
while (c_len <= a_len || c_len <= b_len)
{
c[c_len] = a[c_len] + b[c_len] + x;
x = c[c_len] / 10;
c[c_len] %= 10;
c_len++;
}
c[c_len] = x;
if (c[c_len] == 0)//第一位可能是0或1,如果是0则忽略不输出
c_len--;
for (i = c_len; i >= 1; i--)//逆序输出结果
{
cout << c[i];
}
cout << endl;
return 0;
}
(2)高精度减法,两个正整数求差。
#include
#include
#include
using namespace std;
int main()
{
//a-b=c
char ca[100], cb[100], cc[100];
int a[100], b[100], c[100], a_len, b_len, c_len, i;
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(a));
memset(c, 0, sizeof(a));
cout << "Please input minuend" << endl; gets_s(ca);//输入被减数
cout << "Please input subtrahend" << endl; gets_s(cb);//输入减数
a_len = strlen(ca);
b_len = strlen(cb);
if (strlen(ca) < strlen(cb) || (strlen(ca) == strlen(cb) && strcmp(ca, cb) < 0))
//strcmp()的作用是比较ca和cb,当ca==cb时,返回0;
//当ca>cb时,返回正整数;ca 1))
{
c_len--;//最高位可能位0,此时不输出此位
}
for (i = c_len; i >= 1; i--)
{
cout << c[i];//输出结果
}
cout << endl;
return 0;
}
(3)高精度乘法,两个正整数的积
先作分析:c数组的求和得:ci=c'i+c''i+c'''i+…由此可见,①ci与a[i]*b[j]有关②与上一位的进位有关③c1位上的单个数字与c1本身求得的数有关.
综上有:c[i+j-1]=a[i]*b[j]+x+c[i+j-1]; x=c[i+j-1]/10; c[i+j-1]%=10; 看不懂不要紧,在源码中作具体讲解。
#include
#include
#include
using namespace std;
int main()
{
char a1[100], b1[100];
int a[100], b[100], c[10000], a_len, b_len, c_len, i, j, x;
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
memset(c, 0, sizeof(c));
cin >> a1;
cin >> b1;
a_len = strlen(a1);
b_len = strlen(b1);
for (i = 0; i <= a_len - 1; i++)
{
a[a_len - i] = a1[i] - '0';//倒序输入到整型数组
}
for (i = 0; i <= b_len - 1; i++)
{
b[b_len - i] = b1[i] - '0';
}
for (i = 1; i <= a_len; i++)
{
x = 0;//存放进位
for (j = 1; j <= b_len; j++)//对乘数的每一位处理,相当于把乘数各位数拆出,一位数与另一个乘数相乘
{
c[i + j - 1] = a[i] * b[j] + x + c[i + j - 1];//当前乘积+进位+原数
x = c[i + j - 1] / 10;
c[i + j - 1] %= 10;
}
c[i + b_len] = x;//处理进位
}
c_len = a_len + b_len;
while (c[c_len] == 0 && c_len > 1)//删除前导0
c_len--;
for (i = c_len; i >= 1; i--)
cout << c[i];//输出结果
cout << endl;
return 0;
}
(4)除法,高精除以低精
做除法时,每一次的商都在0~9,每次求得的余数连接以后的若干位得到新的被除数,继续做除法。因此,在做高精度除法时,要涉及到乘法运算和减法运算,还有位移处理。当然,为了程序简洁,可以避免高精度乘法,用0~9次循环减法取代得到的商的值。这里,我们用按位相除法。
#include
#include
#include
using namespace std;
int main()
{
char a1[100];
int a[100], c[100], a_len, i, x = 0, c_len, b;
memset(a, 0, sizeof(a));
memset(c, 0, sizeof(c));
gets_s(a1);
cin >> b;
a_len = strlen(a1);
for (i = 0; i <= a_len - 1; i++)
{
a[i + 1] = a1[i] - '0';
}
for (i = 1; i <= a_len; i++)//按位相除
{
c[i] = (x * 10 + a[i]) / b;
x = (x * 10 + a[i]) % b;
}
c_len = 1;
while (c[c_len] == 0 && c_len < a_len)
{
c_len++;//删除前导0
}
for (i = c_len; i <= a_len; i++)
{
cout << c[i];
}
cout << endl;
return 0;
}
高精除以高精运用减法模拟除法,对被除数的每一位都减去除数,一直减到当前位置的数字(包含前面的余数)小于除数(由于每一位的数字小于10,所以对于每一位最多进行10次运算)较为复杂,此篇文章就不多做赘述。