高精度计算

利用计算机进行数值计算,有时会遇到这样的问题:有些计算要求精度高,希望计算的数的位数可达几十位甚至几百位,虽然计算机的计算精度也算较高了,但因受到硬件的限制,往往达不到实际问题所要求的精度。我们可以利用程序设计的方法去实现这样的高精度计算。介绍常用的几种高精度计算的方法。

高精度计算中需要处理好以下几个问题:

数据的接收方法和存贮方法

数据的接收和存贮:当输入的数很长时,可采用字符串方式输入,这样可输入数字很长的数,利用字符串函数和操作运算,将每一位数取出,存入数组中。

void init(int a[]) //传入一个数组
{
    string s;
    cin >> s;          //读入字符串s
    a[0] = s.length(); //用a[0]计算字符串s的位数
    for (i = 1; i <= a[0]; i++)
        a[i] = s[a[0] - i] - '0'; //将数串s转换为数组a,并倒序存储
}

另一种方法是直接用循环加数组方法输入数据。

void init(int a[])
{
    char num;
    int b[1000], _size = 0;
    while (scanf("%c", &num) && num <= '9' && num >= '0')
    {
        b[_size] = num - '0';
        _size++;
    }
    a[0] = _size ;
    for (int i = 1; i <= _size; i++)
    {
        a[i] = b[_size-i];
    }
}

高精度数位数的确定

位数的确定:接收时往往是用字符串的,所以它的位数就等于字符串的长度。

进位,借位处理

加法进位

//核心思想
c[i] = a[i] + b[i];
if (c[i] >= 10)
{
    c[i] %= 10;
    ++c[i + 1];
}
//核心算法代码
int c[100];
void add(int a[], int b[]) //a,b,c都为数组,分别存储被加数、加数、结果
{
    int i = 1, x = 0; //x是进位
    while ((i <= a数组长度) || (i <= b数组的长度))       
    {
        c[i] = a[i] + b[i] + x; //第i位相加并加上次的进位
        x = c[i] / 10;          //向高位进位
        c[i] %= 10;             //存储第i位的值
        i++;                    //位置下标变量
    }
}

【例1】高精度加法。输入两个正整数,求它们的和。

【分析】 输入两个数到两个变量中,然后用赋值语句求它们的和,输出。但是,我们知道,在C++语言中任何数据类型都有一定的表示范围。而当两个被加数很大时,上述算法显然不能求出精确解,因此我们需要寻求另外一种方法。在读小学时,我们做加法都采用竖式方法,如图1。 这样,我们方便写出两个整数相加的算法。

      A3A2A1

+    B3B2B1

————————————

    C4C3C2C1

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
    char a1[100], b1[100];
    int a[100], b[100], c[100], lena, lenb, lenc, i, x;
    memset(a, 0, sizeof(a));
    memset(b, 0, sizeof(b));
    memset(c, 0, sizeof(c));
    gets(a1);
    gets(b1); //输入加数与被加数
    lena = strlen(a1);
    lenb = strlen(b1);
    for (i = 0; i <= lena - 1; i++)
        a[lena - i] = a1[i] - 48; //加数放入a数组
    for (i = 0; i <= lenb - 1; i++)
        b[lenb - i] = b1[i] - 48; //加数放入b数组
    lenc = 1;
    x = 0;
    while (lenc <= lena || lenc <= lenb)
    {
        c[lenc] = a[lenc] + b[lenc] + x; //两数相加
        x = c[lenc] / 10;
        c[lenc] %= 10;
        lenc++;
    }
    c[lenc] = x;
    if (c[lenc] == 0)
        lenc--; //处理最高进位
    for (i = lenc; i >= 1; i--)
        cout << c[i]; //输出结果
    cout << endl;
    system("pause");
    return 0;
}

 减法借位

if (a[i] < b[i])
{
    --a[i + 1];
    a[i] += 10;
}
c[i] = a[i] - b[i];

【例2】高精度减法。输入两个正整数,求它们的差。

【算法分析】 类似加法,可以用竖式求减法。在做减法运算时,需要注意的是:被减数必须比减数大,同时需要处理借位。高精度减法的参考程序:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
    int a[256], b[256], c[256], lena, lenb, lenc, i;
    char n[256], n1[256], n2[256];
    memset(a, 0, sizeof(a));
    memset(b, 0, sizeof(b));
    memset(c, 0, sizeof(c));
    printf("Input minuend:");
    gets(n1); //输入被减数
    printf("Input subtrahend:");
    gets(n2); //输入减数
    if (strlen(n1) < strlen(n2) || (strlen(n1) == strlen(n2) && strcmp(n1, n2) < 0))
    //strcmp()为字符串比较函数,当n1==n2, 返回0;
    //n1>n2时,返回正整数;n1<n2时,返回负整数
    {                  //处理被减数和减数,交换被减数和减数
        strcpy(n, n1); //将n1数组的值完全赋值给n数组
        strcpy(n1, n2);
        strcpy(n2, n);
        cout << "-"; //交换了减数和被减数,结果为负数          
    }
    lena = strlen(n1);
    lenb = strlen(n2);
    for (i = 0; i <= lena - 1; i++)
        a[lena - i] = int(n1[i] - '0'); //被减数放入a数组
    for (i = 0; i <= lenb - 1; i++)
        b[lenb - i] = int(n2[i] - '0'); //减数放入b数组
    i = 1;
    while (i <= lena || i <= lenb)
    {
        if (a[i] < b[i])
        {
            a[i] += 10; //不够减,那么向高位借1当10
            a[i + 1]--;
        }
        c[i] = a[i] - b[i]; //对应位相减
        i++;
    }
    lenc = i;
    while ((c[lenc] == 0) && (lenc > 1))
        lenc--; //最高位的0不输出  
    for (i = lenc; i >= 1; i--)
        cout << c[i]; //输出结果
    cout << endl;
    system("pause");
    return 0;
}

乘法进位

c[i + j - 1] = a[i] * b[j] + x + c[i + j - 1];
x = c[i + j - 1] / 10;
c[i + j - 1] %= 10;

商和余数的求法

商和余数处理:视被除数和除数的位数情况进行处理

 

posted @ 2020-05-12 14:27  我等着你  阅读(295)  评论(0)    收藏  举报