高精度加减乘除

一。高精度乘法(敲了好久。。头秃)

//str1,str2是存数字的字符串,返回最后的位数,c存储结果
int highmult( char str1[], char str2[], int c[] )
{
    int len1 = strlen(str1), len2 = strlen(str2);
    int a[len1 + 1] = {0}, b[len2 + 1] = {0};
    int i, j;

    memset(a, 0, sizeof(a));
    memset(b, 0, sizeof(b));
    memset(c, 0, sizeof(c));
/*
*用这个函数写1000阶乘时这句话没用了,
*不知道为啥,可把我无奈坏了,找了半天错,
*好像memset对int数组不好用,有时候出问题
*/
    //把字符变成数字,方便运算
    for( i = len1 - 1, j = 0; i >= 0; i--)
        a[j++] = str1[i] - '0';

    for( i = len2 - 1, j = 0; i >= 0; i--)
        b[j++] = str2[i] - '0';

    for( i = 0; i < len1; i++)//i, j是权重,i+j就是c[]里面的权重
        for( j = 0; j < len2; j++)
        {
            c[i + j] += a[i] * b[j];
            printf("%d\n", c[i + j]);
            if( c[i + j] >= 10 )//因为9 + 9 * 9 < 100,所以只进一位
            {
                int k = c[i + j];
                c[i + j + 1] += k / 10;
                c[i + j] = k % 10;
            }
        }
    
    //找位数。。。这个大概可以在前面的代码里优化,,懒,,
    for( i = len1 + len2 + 2; (c[i] == 0) && (i >= 0); i-- )
        ;

    return i + 1;
}

二。高精度加法

这个是我还不知道高精度是啥东西时百度的算法,记不得找的哪儿的了,一直存着,稍微改了点,,,原创看见了误喷一定加上链接。

恩!原创棒棒的!

//加起来存进c
int highadd( char num1[], char num2[], int c[] )
{
    int lena = strlen(num1), lenb = strlen(num2), lenc, i, x;//x 是进位用的
    int a[100], b[100];

    memset(a, 0, sizeof(a));
    memset(b, 0, sizeof(b));
    memset(c, 0, sizeof(c));

    //存数字
    for( i = 0; i < lena; i++)
        a[lena - i - 1] = num1[i] - '0';

    for( i = 0; i < lenb; i++)
        b[lenb - i - 1] = num2[i] - '0';

    lenc = 0;
    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--;

    return lenc;
}

三。高精度减法

//贼他妈难写,
int highsub( char a[], char b[], int c[] )
{
    for(int i = 0; i < MAXLEN; ++i)
        c[i] = 0;

    int la = strlen(a), lb = strlen(b);
    int sign(0), m(0);
    int com = compare(a, b);
    
    //记录符号
    if( com > 0 )
    {
        sign = 1;
        m = la;
    }
    else if( com < 0)
    {
        sign = -1;
        m = lb;
    }
    else
        return 1;//一位以便于输出0

    if(sign == 1)
    {
        int sub = la - lb;
        for(int i = 0; i < sub; ++i)//先把前面的权重高的解决了
            c[i] = a[i] - '0';

        for(int i = sub; i < m; ++i)//和我写的乘法一样,算一次就处理一次进位
        {
            if( a[i] > b[i - sub])
                c[i] = a[i] - b[i - sub];
            else if( a[i] == b[i - sub] )
                ;
            else//小于时向上一位要一个,后面再集中处理如果上一位也是零的情况
            {
                --c[i - 1];
                c[i] = (a[i] - '0') + 10 - (b[i - sub] - '0');
            }
        }
    }
    else//一样的
    {
        int sub = lb - la;
        for(int i = 0; i < sub; ++i)
            c[i] = b[i] - '0';

        for(int i = sub; i < m; ++i)
        {
            if( b[i] > a[i - sub])
                c[i] = b[i] - a[i - sub];
            else if( a[i - sub] == b[i])
                ;
            else
            {
                --c[i - 1];
                c[i] = (b[i] - '0') + 10 - (a[i - sub] - '0');
            }
        }
    }

    for(int i = m - 1; i >= 0; --i)//处理退位时产生的负数问题
        if( c[i] < 0 )
        {
            --c[i - 1];
            c[i] += 10;
        }

    if(c[0] == 0)//处理a, b中前几位相同以至于c前几位是0的问题
        for(int i = 1; i < MAXLEN; ++i)
            if( c[i] != 0 )
            {
                for(int j = i; j < m; ++j)
                    c[j - i] = c[j];
                m -= i;
                break;
            }

    c[0] *= sign;

    return m;
}

四。高精度除法

这个代码对于大数不能算位数相差超过六位的,太慢了,因为是用减法实现的,循环减,减了几次答案就是几

以后灵光一闪优化了(偷偷百度一下)再修改吧

(最难写的高精度。。)

//要存小数点就用字符数组c了,n是确定小数点后几位,默认c里面都是0,懒得加memset
int highdiv( char a[], char b[], char c[], int n )
{
    int d[MAXLEN];
    int j(0), k(0);
    int zs;//记录小数点位置,便于小数部分运算
    
    //代码核心,把除降解为减
    while( compare( a, b ) >= 0 )
    {
        int len = highsub(a, b, d);
        memset(a, 0, sizeof(0));
        for(int i = 0; i < len; ++i)
            a[i] = d[i] + '0';
        a[len] = '\0';

        ++c[j];

        if(c[j] >= 10)//烦人的进位问题
        {
            for(int i = j; i > 0; --i)
                if( c[i] >= 10 )
                {
                    ++c[i - 1];
                    c[i] %= 10;
                }

            if(c[0] >= 10)//进到头了就把c整体往后挪一位
            {
                for(int i = j; i >= 0; --i)
                    c[i + 1] = c[i];
                c[0] = 1;
                c[1] = 0;
                ++j;
            }
        }
    }

    zs = j + 2;//实际上是指向了小数点后一位

    //把减的比b小的a膨胀开来,添加n + 1个0,模拟手算的加0过程
    for(int i = strlen(a); i < MAXLEN && k <= n; ++i, ++k)
    {
        a[i] = '0';
        if( k == n )
            a[i + 1] = '\0';
    }

    j += 2;//j指向第一个小数位,再来一波和上面差不多的操作
    while( compare( a, b ) >= 0 )
    {
        int len = highsub(a, b, d);
        memset(a, 0, sizeof(0));
        for(int i = 0; i < len; ++i)
            a[i] = d[i] + '0';
        a[len] = '\0';

        ++c[j];

        if(c[j] >= 10)
        {
            for(int i = j; i > zs; --i)
                if( c[i] >= 10 )
                {
                    ++c[i - 1];
                    c[i] %= 10;
                }

            if(c[zs] >= 10)
            {
                for(int i = j; i >= zs; --i)
                    c[i + 1] = c[i];
                c[zs] = 1;
                c[zs + 1] = 0;
                ++j;
            }
        }
    }

    k = j;
    if( c[k] >= 5 )//四舍五入,循环是怕一入就出现了10
        do
        {
            ++c[k - 1];
            c[k] = 0;
        }
        while( c[--k] >= 10 );

    j = zs + n;

    for(int i = 0; i <= j; ++i)//数字变字符,便于小数点打印
        c[i] += '0';

    c[zs - 1] = '.';

    c[j] = '\0';

    return j + 1;
}

最后把compare也贴出来吧,不复杂

int compare(char a[], char b[])
{
    int la = strlen(a), lb = strlen(b);

    if( la > lb )
        return 1;
    else if( la < lb )
        return -1;
    else
        for(int i = 0; i < la; ++i)
            if( a[i] > b[i] )
                return 1;
            else if( a[i] < b[i] )
                return -1;

    return 0;
}

还是初学者,自己敲可能有bug,也应该还可以优化,比如处理进位写成函数什么的。

要是以后变大佬了就回来优化一波算法。




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值