• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • 設計高精度乘法計算函數

    發表于:2007-07-14來源:作者:點擊數: 標簽:
    重慶建設中學 楊宏偉 我們知道計算機的計算精度不是無限大的,甚至是十分有限的。CPU的字長和操作系統的處理能力直接制約著運算精度和運算能力。隨著計算機應用的深入,人們對計算能力的 需求 ,尤其是精度的需求,越來越高。雖然目前32位CPU及操作系統提供
    重慶建設中學 楊宏偉

      我們知道計算機的計算精度不是無限大的,甚至是十分有限的。CPU的字長和操作系統的處理能力直接制約著運算精度和運算能力。隨著計算機應用的深入,人們對計算能力的需求,尤其是精度的需求,越來越高。雖然目前32位CPU及操作系統提供的計算精度,較之從前已有很大的提高,而且精度更高的64位CPU及操作系統正在普及,但是,對許多計算機應用課題來說,能不能具有不直接依賴硬件條件的高精度、高性能計算能力仍是至關重要的。為此,設計高精度計算的軟件包,用軟件方法實現高精度計算,是一件有實用價值的工作。例如,目前在電子商務應用中,密碼的校驗及計算就是對高精度計算的典型需求。

    分析問題

    由于C語言具有執行效率高、支持動態存儲分配等特點,我們選用C語言編寫了一套工具函數,供高精度計算使用。乘法運算在計算機運算中是一種基本運算,它的計算過程對整個計算效率有舉足輕重的影響。仔細研究乘法運算對高精度計算十分必要。

    為了實現高精度計算,首先要建立高精度的數據表示方法。我們采用將整數和小數分開,組成兩個隊列的方法存儲數據。這種方法不僅節約存儲空間,而且有利于確保整數運算的精度。

    描述運算對象的數據結構如下:

    struct VARARRAY {

    char cDigit; //保存數據位

    //指向下一個數據位

    struct VARARRAY * spNext;

    };

     

    struct SUPERNUMBER

    {

    //指向最低位整數

    struct VARARRAY * spIntPart;

     

    //指向最低位小數

    struct VARARRAY * spDecPart;

     

    //指向最高位整數

    struct VARARRAY * spIntLast;

     

    //指向最高位小數

    struct VARARRAY * spDecLast;

     

    int iNumberInt; //整數位數

    int iNumberDec; //小數位數

    char cSign;

    }; //符號位

    在用SUPERNUMBER結構描述運算對象的基礎上,我們定義了一套函數,全面實現SUPERNUMBER型數據的輸入、輸出、賦值、比較、加、減、乘、除、整除等運算功能。本文重點介紹無精度損失的乘法計算方法及主要函數的設計。

    乘法算法

    為了不損失計算精度,我們將乘法轉換為加法實現,基本算法如下:

    1.將數符較多的數據表示為X,作為加數,數符較少的數據表示為Y,控制加法次數;

    2.如果Y含有小數部分,將Y轉變為純整數YDEC,并記錄小數點的右移位數I;

    3.初始化返回值T為0,取得Y的位數WIDTH,設計數器COUNT為0;

    4.取Y右側第COUNT+1位,以此數為次數加X,再左移COUNT位,加到T中;

    5.把COUNT加1;

    6.若COUNT等于WIDTH,轉下一步,否則轉第4步;

    7.將T中的小數點左移I位;

    8.返回T,得到乘法結果。

    本算法的特點是加法次數少,若Y的寬度為W,最多進行9×W次加法及W次移位即可。

    乘法函數

    乘法函數通過把兩個SUPERNUMBER型的數據相加實現運算目的,其結果通過指針返回。

    struct SUPERNUMBER * su_mu(

    struct SUPERNUMBER * spSourceOne,

    struct SUPERNUMBER * spSourceTwo)

    {

    struct SUPERNUMBER * spNew;

    struct SUPERNUMBER * spYDec;

    struct SUPERNUMBER * spX,* spY,* spC,* spT;

    struct VARARRAY * spTem;

    int iYDec,iWidth,iDigit,iC1,iC2;

    spNew=su_as(“0”);

    if (spSourceOne->iNumberInt+spSourceOne->iNumberDec>=spSourceTwo->iNumberInt+

    spSourceTwo->iNumberDec){

    spX=su_co(spSourceOne);

    spY=su_co(spSourceTwo);

    }

    else{

    spY=su_co(spSourceOne);

    spX=su_co(spSourceTwo);

    }

    iYDec=spY->iNumberDec;

    spYDec=su_mo(spY,iYDec);

    iWidth=spYDec->iNumberInt;

    spTem=spYDec->spIntPart;

    for(iC1=0;iC1<iWidth;iC1++)

    {

    iDigit=(int)(spTem->cDigit-‘0’);

    spTem=spTem->spNext;

    spC=su_as(“0”);

    for(iC2=0;iC2<iDigit;iC2++)

    {

    spT=su_ad(spC,spX);

    su_fr(spC);

    spC=su_co(spT);

    su_fr(spT);

     

    }

    spT=su_mo(spC,iC1);

    su_fr(spC);

    spC=su_ad(spNew,spT);

    su_fr(spNew);su_fr(spT);

    spNew=su_co(spC);

    su_fr(spC);

    }

    spT=su_mo(spNew,-iYDec);

    su_fr(spNew);

    spNew=su_co(spT);

    su_fr(spT);

    su_fr(spYDec);

    su_fr(spX);

    su_fr(spY);

    return spNew;

    }

    在此函數中,我們使用了在高精度計算軟件包中定義的其他函數(本文省略其實現代碼),主要有:

    1.將字符串轉化為SUPERNUMBER類型:

    struct SUPERNUMBER * su_as(char*zpSource);

    2.將一個SUPERNUMBER復制到另一個SUPERNUMBER中:

    struct SUPERNUMBER * su_co(struct SUPERNUMBER * spSource);

    3.兩個SUPERNUMBER的“等于”關系運算,若相等,返回1:

    int su_ee(struct SUPERNUMBER * spSource, struct SUPERNUMBER * spDesti);

    4.兩個SUPERNUMBER數的加法運算:

    struct SUPERNUMBER * su_ad(struct

    SUPERNUMBER * spSource,struct SUPERNUMBER * spDestination);

    5.SUPERNUMBER與用整數表示的數據的加法運算:

    struct SUPERNUMBER * su_si(

    struct

    SUPERNUMBER * spSource, int iDesti);

    6.移動小數點:

    struct SUPERNUMBER * su_mo(struct

    SUPERNUMBER * spSource, int iNum);

    7.釋放SUPERNUMBER數據的存儲空間:

    void su_fr(struct SUPERNUMBER * spSource);

    應用實例

    當我們計算16的階乘時,常規的方法難于直接得到正確的結果,即使定義長整型(long int)數據,在計算出11的階乘39916800之后,也開始出現數據錯誤。但是利用本文介紹的方法,可精確地計算出從1到16的階乘值。代碼如下:

    FILE * fp;

    struct SUPERNUMBER * spX;

    struct SUPERNUMBER * spY;

    struct SUPERNUMBER * spZ;

    struct SUPERNUMBER * spSum;

    fp=fopen(“abcd.txt”,“a+”);

    if (fp==NULL) MessageBox(hWndMain,“file error”,“”,MB_OK);

    //初始化變量

    spX=su_as(“0”);

    spY=su_as(“30”);

    spSum=su_as(“1”);

    //計算從1到16的階乘值

    lp: spZ=su_si(spX,1);

    su_fr(spX);

    spX=su_co(spZ);

    su_fr(spZ); spZ=su_mu(spSum,spX);

    su_fr(spSum);

    spSum=su_co(spZ);

    su_fr(spZ);

    su_os(spSum);

    su_of(spX,fp);

    su_of(spSum,fp);

    if (!su_ee(spY,spX)) goto lp;

     

    fclose(fp);

    運算結果為:

    1 ! 1 2! 2

    3 ! 6 4! 24



    13 ! 6227020800 14! 87178291200

    15 ! 1307674368000 16! 20922789888000

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>