精确乘幂

1. 算法思想

精确乘幂的思想秉承于大数乘法,但其实质仍是大数的相乘。只不过,由于底数可以为小数,相比较于大数相乘,需要处理小数点的问题。但是我们可以将采用分离的思想,记录小数点所在的位数(从右往左数,且从0开始)并去除小数点,先将小数换为大数,求出大数的成绩,再填入小数点。

2. 问题描述

2.1 问题描述
对一个实数R(R为0~1000之间的实数),编写程序精确计算R的N次方,其中N是整数且0<=N<=25.

2.2 输入
输入R和N,用空格分隔。

2.3 输出
R的N次方精确值,输出无需去掉无用的0,如果输出结果为整数,不要输出小数点。

3. 问题要点

在本题中,需要把握的要点有三点:
1)一个n位的整数和一个m位的整数相乘的结果,其位数最高为m+n;
2)两数相乘之后的小数点问题,可以迁移为:小数点位于第i位(从右往左数,且i从0开始,i=0代表该数为整数),相当于将小数点向左移动了i位。
那么,两个小数a和b相乘,a和b的小数点在第i,j位,那么处理完之后的结果中,小数点位于i+j位;
3)处理最终结果中无效的零,包括整数部分的0和小数部分的0.

4. 算法实现

4.1 重要函数声明

大数相乘算法声明

//大数相乘
//乘数:numsA,numsB
//长度:lenA, lenB
int BigNumberMultiplication(int * numsA, int lenA, int * numsB, int lenB, int *
                            results);

字符串向int转换函数实现

//change the string to the big-int and save them in array
//返回值:小数点的位数
//src: the String
//number: the array
//length: string's length
int string2int(char * src, int * number, int length);

4.2 算法完整实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//change the string to the big-int and save them in array
//返回值:小数点的位数
//src: the String
//number: the array
//length: string's length
int string2int(char * src, int * number, int length);

int string2int(char * src, int * number, int length)
{
    int flag=0;
    //define the buffer to store the data
    char * str = (char *)malloc(sizeof(char)*(length+1));
    memset(str, '\0', length+1);
    memcpy(str, src, length);
    /*  puts(str);*/
    strrev(str);
    /*  puts(str);*/
    //transfer string to int
    //int temp = *number; //原有的数据不为零时,也需要考虑
    int i, j;
    for (i=0, j=0; i<length; i++)
    {
        //temp *= 10;
        //原有数据为字符'A',顾需要减去'0'
        if (str[i]!='.')
        {
            number[j++] += (int)(str[i] - '0');
        }
        else
        {
            flag = j;
        }

    }
    //return the transfer number
    //*number = temp;
    //clear the dynamic memory
    free(str);
    str = NULL;
    return flag;
}

//大数相乘
//乘数:numsA,numsB
//长度:lenA, lenB
int BigNumberMultiplication(int * numsA, int lenA, int * numsB, int lenB, int *
                            results);
int BigNumberMultiplication(int * numsA, int lenA, int * numsB, int lenB, int * results)
{
    int i, j;
    //multi procedure
    for (i=0; i<lenB; i++)
    {
        for (j=0; j<lenA; j++)
        {
            //the i,j place number multi, and the result is on the i+j place
            results[i+j] += numsA[j] * numsB[i];
        }
    }
    //process the result
    for (i=0; (i<lenA+lenB); i++)
    {
        if (results[i]>=10)  //the low place to the high place, if the low number is >=
            10
        {
            results[i+1] += results[i] /10;
            results[i] %= 10;
        }
    }
    //calcute lenA
    for (i=lenA+lenB-1; i>=0; i--)
    {
        if (results[i] != 0)
        {
            break;
        }
    }
    return i+1;
}

int main()
{
    char str[7] = {'\0'};
    int numsB[5] = {0};
    int n;
    scanf("%s %d", str, &n);
    int length = strlen(str);
    //获取小数点的位数
    int PointPlace = string2int(str, numsB, length);
    if (PointPlace!=0) // reduce the . nums
    {
        length--;
    }

    int * pNumsA = (int *)malloc(length*n*sizeof(int));
    int * pResults = (int *)malloc(length*n*sizeof(int));
    memset(pNumsA, 0, length*n*sizeof(int));
    memset(pResults, 0, length*n*sizeof(int));
    memcpy(pNumsA, numsB, length*sizeof(int));
    // int i;
    // for (i=0; i<length; i++)
    // {
    //      printf("%d", pNumsA[i]);
    // }
    // printf("-%d\n", PointPlace);
    int lenA = length;
    /*printf("%d", lenA);*/
    int i, j;
    int bIsBegin = 0;
    char * pString = (char *)malloc(sizeof(char)*length*n+2);
    memset(pString, '\0', sizeof(char)*length*n+2);
    if (n==1)
    {
        printf("%s", str);
    }
    else
    {
        //求幂
        for (i=1; i<n; i++)
        {
            lenA = BigNumberMultiplication(pNumsA, lenA, numsB, length,
                                           pResults);
            memcpy(pNumsA, pResults, lenA*sizeof(int));
            memset(pResults, 0, lenA*sizeof(int));
            //printf("LenA---%d\n", lenA);
        }

        //将结果由数组转化为字符串并添加小数点
        i=0;
        j = 0;
        while (i<length*n)
        {
            if (pNumsA[i]==0)
            {
                if (1==bIsBegin)
                {
                    if ( i==(PointPlace*n) )
                    {
                        if (i!=0)
                            pString[j++] = '.';
                    }
                    pString[j++] = pNumsA[i++] + '0';
                }
                else
                    i++;

            }
            else
            {
                bIsBegin = 1; begin from the first non-zero value

                if ( i==(PointPlace*n) )
                {
                    if (i!=0)
                    {
                        pString[j++] = '.';
                    }

                }

                pString[j++] = pNumsA[i++] + '0';
            }
        }

        free(pNumsA);
        free(pResults);
        //反转字符串:之前的字符串一直是倒叙的
        strrev(pString);

        //输出结果:主要是处理小数点前0的个数
        if (PointPlace==0)
        {
            for (i=0; i<length*n; i++)
            {
                if (pString[i]!='0')
                    break;
            }
            printf("%s", &pString[i]);
        }
        else
        {
            for (i=0; i<length*n; i++)
            {
                if (pString[i]!='0')
                {
                    if (pString[i]=='.')
                    {
                        i--;
                        break;
                    }
                    else
                    {
                        break;
                    }

                }

            }
            printf("%s", &pString[i]);
        }
    }

    free(pString);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值