天天看點

精确乘幂

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=;
    //define the buffer to store the data
    char * str = (char *)malloc(sizeof(char)*(length+));
    memset(str, '\0', length+);
    memcpy(str, src, length);
    /*  puts(str);*/
    strrev(str);
    /*  puts(str);*/
    //transfer string to int
    //int temp = *number; //原有的資料不為零時,也需要考慮
    int i, j;
    for (i=, j=; 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=; i<lenB; i++)
    {
        for (j=; 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=; (i<lenA+lenB); i++)
    {
        if (results[i]>=)  //the low place to the high place, if the low number is >=
            
        {
            results[i+] += results[i] /;
            results[i] %= ;
        }
    }
    //calcute lenA
    for (i=lenA+lenB-; i>=; i--)
    {
        if (results[i] != )
        {
            break;
        }
    }
    return i+;
}

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

    int * pNumsA = (int *)malloc(length*n*sizeof(int));
    int * pResults = (int *)malloc(length*n*sizeof(int));
    memset(pNumsA, , length*n*sizeof(int));
    memset(pResults, , 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 = ;
    char * pString = (char *)malloc(sizeof(char)*length*n+);
    memset(pString, '\0', sizeof(char)*length*n+);
    if (n==)
    {
        printf("%s", str);
    }
    else
    {
        //求幂
        for (i=; i<n; i++)
        {
            lenA = BigNumberMultiplication(pNumsA, lenA, numsB, length,
                                           pResults);
            memcpy(pNumsA, pResults, lenA*sizeof(int));
            memset(pResults, , lenA*sizeof(int));
            //printf("LenA---%d\n", lenA);
        }

        //将結果由數組轉化為字元串并添加小數點
        i=;
        j = ;
        while (i<length*n)
        {
            if (pNumsA[i]==)
            {
                if (==bIsBegin)
                {
                    if ( i==(PointPlace*n) )
                    {
                        if (i!=)
                            pString[j++] = '.';
                    }
                    pString[j++] = pNumsA[i++] + '0';
                }
                else
                    i++;

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

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

                }

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

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

        //輸出結果:主要是處理小數點前0的個數
        if (PointPlace==)
        {
            for (i=; i<length*n; i++)
            {
                if (pString[i]!='0')
                    break;
            }
            printf("%s", &pString[i]);
        }
        else
        {
            for (i=; i<length*n; i++)
            {
                if (pString[i]!='0')
                {
                    if (pString[i]=='.')
                    {
                        i--;
                        break;
                    }
                    else
                    {
                        break;
                    }

                }

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

    free(pString);

    return ;
}
           

繼續閱讀