历史上的今天
返回首页

历史上的今天

今天是:2024年09月16日(星期一)

2018年09月16日 | STM32F4制作一个计算器(一) 大数运算

2018-09-16 来源:eefocus

一、大数的运算算法

使用原子的STM32F4开发板制作一个计算器,类似电脑上的标准型计算器。

在制作界面之前,首先要解决大数运算问题。因为STM32为32位MCU,直接计算最大不过32位,按十进制也就是10位数,显然不够用。

为了方便计算,使用数组储存各位数据,并且低位在前。下面数据结构中,使用指针代替数组,这是为了方便以后与界面函数部分对接。

#define THIS_MAXLEN 50  //数组长度 

#define SHOW_MAXLEN 30  //自我调整中使用的最大长度 

#define DIV_PREC   20   //除法精度相关

 

#define RESULT_TYPE signed char

#define RESULT_OK 0

#define RESULT_ERR_MEM 1

#define RESULT_ERR_DIVZERO 2

#define RESULT_ERR_MINUS 3

#define RESULT_ERR_OVERLEN 4

 

 

typedef struct

{

    signed char len;//数据长度

    signed char *num;

} bignumBASE_st;//正整数结构

 

typedef struct

{

   bignumBASE_st baseT;

   signed char symbol;  //0正,1负

   signed char exponent;//指数,10^exp次方 

} bignumESB_st;//包括浮点,正负

 


二、加法、减法


四则运算中,加法减法是最容易,甚至都不需要额外的临时大数组进行辅助。基本方法是从低位开始计算,有进位借位则记录,下一个循环计上。唯一需要注意的就是,类似a=a+1这种源参数与目的参数其实相同的情况,要避免影响。再一个,设计函数时,因为怕MCU栈空间不够,所以源参数也使用指针传递,而非值传递。其实这样做反而有些麻烦,需要手工做更多的保护处理,千万不要以为加了cons修饰t就没事了。


由于有符号加法与减法是相互调用转化的,为避免出现递归调用(虽然实际上应该不会),我对函数进行多层封装。


 


/* 

说明:正整数加法 ,加法最内层 

参数:pdst 存放结果,pa pb乘数 

返回:无

*/ 

static void _bigADD(bignumBASE_st *const pdst,const bignumBASE_st *pa,const bignumBASE_st *pb)

{

    unsigned char i=0,len = (pa->len)>(pb->len)?pa->len:pb->len;

    signed char  snum;

    signed char cc=0; //进位标志

    const bignumBASE_st *pl,*ps;

 

    if( pa->len > pb->len )

    {

        pl=pa,ps=pb;

    }else

    {

        pl=pb,ps=pa;

    }

    for(i=0; i< len; i++)

    {   //避免数组溢出

        snum=( i < ps->len ) ?  ps->num[i] : 0 ;  

     

        pdst->num [i] = cc+ pl->num[i] + snum ; //加法

        if( pdst->num[i] > 9 )

        {

            cc=1;

            pdst->num [i]-=10;

        }

        else cc=0;

    }

    pdst->num [i] =cc;

    pdst->len =  len + cc;

}

 

 

//无符号大数加法,处理浮点 

#define _BIG_ABS(a) (a<0?-a:a)

RESULT_TYPE nsbigADD(bignumESB_st *const pdst,const bignumESB_st *pa,const bignumESB_st *pb)

{

    signed char ec=0;

    ec=pa->exponent-pb->exponent ;

    if( ec != 0)

    {

        const bignumESB_st *pt,*pn;//临时变量,pt需要调整指数 

        bignumESB_st ts;

        ts.baseT.num = (signed char*)malloc(THIS_MAXLEN);//申请内存

        if(ts.baseT.num == NULL)return RESULT_ERR_MEM;

 

        ec>0 ?( pt=pa,pn=pb):(pt=pb,pn=pa);   

        bigNumTenfold( &ts.baseT,&pt->baseT, _BIG_ABS(ec) ); //移动数组与长度 

 

        ts.exponent = pn->exponent ;           //对齐指数 

        _bigADD( & pdst->baseT , &ts.baseT, &pn->baseT ) ;

        pdst->exponent = ts.exponent ;

    }

    else

    {

        _bigADD( &(pdst->baseT), &(pa->baseT), &(pb->baseT))  ;

        pdst->exponent=pa->exponent;

    }

    return RESULT_OK ;    

}

 


//无符号大整数减法 ,大减去小, 减法最内层 

static void _bigSUB(bignumBASE_st *pdst,const bignumBASE_st *pa,const bignumBASE_st *pb)

{

    unsigned char i=0 ,cflag=0 ,len;

    signed char cc=0 ; //借位标志

    len= pa->len  ;

    for(i=0; i< len; i++)

    {

        signed char bnum=0,danum=0;

        bnum = (i < pb->len )?pb->num[i]:0;//避免地址溢出

        danum = pa->num[i] - cc;

        cc=0;

        if( danum > bnum )

        {

            pdst->num[i] = danum - bnum ;

            cflag=i;

        }

        else if( danum == bnum )

        {

            pdst->num[i] = 0;

        }

        else

        {

            cc=1; //借位

            pdst->num[i] = 10 + danum - bnum;//借10

            if( pdst->num[i] != 0)cflag=i;

        }

    }

    pdst->len = cflag+1 ;

}

//无符号大数减法,处理浮点 

RESULT_TYPE nsbigSUB(bignumESB_st *const pdst,const bignumESB_st *pa,const bignumESB_st *pb)

{

    signed char ec=0;

    signed char res;

    ec = pa->exponent-pb->exponent ;//比较浮点长度 

    if( ec != 0)

    {

        const bignumESB_st *pt,*pn; //pt为需要调整指数的一方

        const bignumESB_st *pxa,*pxb;

        bignumESB_st ts;//用于调整指数

        ts.baseT.num =(signed char*) malloc(THIS_MAXLEN);//申请内存

        if(ts.baseT.num == NULL)return RESULT_ERR_MEM;

 

 

        ec>0 ?( pt=pa,pn=pb):(pt=pb,pn=pa);  //浮点长的一方为pt  

        bigNumTenfold( &(ts.baseT),&(pt->baseT), _BIG_ABS(ec) ); //移动数组与长度 

        ts.exponent = pn->exponent ;           //对齐指数 

        if( ec>0 )

        {

            pxa= &ts,pxb=pb;

        }else

        {

            pxa=pa,pxb=&ts;

        }

        

        res = arrcmp( &pxa->baseT , &pxb->baseT  );//计较大小 

        if( res == -1)

        {

            _bigSUB(&pdst->baseT,&pxb->baseT,&pxa->baseT);

            pdst->symbol=1;    

            pdst->exponent = ts.exponent ;//指数与多多的一方相同 

        }

        else if( res == 0)

        {

            pdst->baseT.num[0]=0;

            pdst->baseT.len=1 ;

            pdst->symbol=0; 

            pdst->exponent = 0; 

        }

        else if( res == 1)

        {

            _bigSUB(&pdst->baseT,&pxa->baseT ,&pxb->baseT );

            pdst->symbol=0; 

            pdst->exponent = ts.exponent ;//指数与多的一方相同 

        }

        

    }

    else

    {

        res = arrcmp( & (pa->baseT) , & (pb->baseT)  );//比较大小 

        if( res == -1)

        {

            _bigSUB(&pdst->baseT,&pb->baseT ,&pa->baseT );

            pdst->symbol=1;

            pdst->exponent = pa->exponent ;     

        }

        else if( res == 0)

        {

            pdst->baseT.num[0]=0;

            pdst->baseT.len=1 ;

            pdst->symbol=0; 

            pdst->exponent = 0 ; 

        }

        else if( res == 1)

        {

            _bigSUB(& pdst->baseT,& pa->baseT,& pb->baseT);

            pdst->symbol=0; 

            pdst->exponent = pa->exponent ; 

        }   

    }

    return RESULT_OK;     

}

上面几个内部加法减法函数都是为下面两个最外层的函数准备


 


//有符号大数加法

RESULT_TYPE  bigNumADD(bignumESB_st *const pdst,const bignumESB_st *pa,const bignumESB_st *pb)

{

    RESULT_TYPE err;

    if( pa->symbol == pb->symbol)

    {

          err=nsbigADD( pdst, pa, pb);

        pdst->symbol = pa->symbol ;

    }else

    {

        if ( pa->symbol ==0 ) // 正 

        err=nsbigSUB( pdst, pa, pb);  

        else

        err=nsbigSUB( pdst, pb, pa); 

    }

    removeTailZero( pdst->baseT.num  , &pdst->baseT.len  , 0 ); //去掉多余的零 

    bignumst_adjust( pdst,  SHOW_MAXLEN );                      //对数据进行标准化调整

    return err;

}

//有符号大数减法

RESULT_TYPE  bigNumSUB(bignumESB_st *const pdst,const bignumESB_st *pa,const bignumESB_st *pb)

{

    RESULT_TYPE err;

    if( pa->symbol == pb->symbol)

    {

        err=nsbigSUB( pdst, pa, pb);

        if( pa->symbol == 1) pdst->symbol = ! (pdst->symbol);

    }

    else

    {    

        err=nsbigADD( pdst, pa, pb);

        pdst->symbol = pa->symbol;

    }

    removeTailZero( pdst->baseT.num , &pdst->baseT .len  , 0 ); //去掉多余的零 

    bignumst_adjust( pdst,  SHOW_MAXLEN );                      //对数据进行标准化调整

    return err ;

}


 

三、乘法


乘法相对加减法稍微复杂那么一点点,方法依然是从低位到高位算,并且会用到加法。


总的来说,就是先单乘,然后逐步将结果相加


/* 

说明:单位整数与大数相乘 ,乘法最内层 

参数:pdst 存放结果,pa 乘数所在 ,singledigit 单位乘数0-9,pa的长度

返回:整数位数,长度

*/

static signed char _bigMUL_single(signed char *pdst,const signed char *pa,const unsigned char singledigit,const unsigned char len)

{

    //即使源参数与目的参数一样,也不会影响

    unsigned char i=0 ,tlen=len;

    signed char cc=0;//进位结果

    if( singledigit == 0 )

    {

        pdst[0]=0;

        return 1;

    }

    for(i=0; i

    {

        pdst[i] =  pa[i]*singledigit + cc;

        if( pdst[i] > 9)

        {

            cc = pdst[i]/10; //进位

            pdst[i] = pdst[i]%10;   //取模

        }

        else cc=0;

    }

    pdst[i]=cc;

    cc=(cc==0)?0:1;

    tlen+= cc ;

 

    return tlen;

}

/* 

说明:无符号大数乘法,处理指数浮点

参数:pdst 存放结果,pa pb 乘数所在  

返回:错误类型

*/

static RESULT_TYPE nsbigMUL( bignumESB_st *const pdst, const bignumESB_st *pa,const bignumESB_st *pb)

{

    unsigned char i=0,lenlong,lenshort;

    bignumBASE_st temp,*ptemp=&temp;//保存单次结果

    bignumESB_st tdst,*ptdst=&tdst;//开辟内存,避免因源参数与目的参数一样导致的BUG

    const bignumESB_st *plong,*pshort;

    //申请内存

    ptemp->num =(signed char*) malloc(THIS_MAXLEN);

    ptdst->baseT.num =(signed char*) malloc(THIS_MAXLEN);

    if( ptemp->num==NULL || ptdst->baseT.num == NULL )return RESULT_ERR_MEM;

    //指数处理 

    pdst->exponent = pa->exponent+pb->exponent ;

    //直接相乘 

    if( pa->baseT.len + pb->baseT.len <=9 ) 

    {

        unsigned int val=0;

        val  =arr2int(pa->baseT.num, pa->baseT.len);

        val *=arr2int(pb->baseT.num, pb->baseT.len);

        pdst->baseT.len =int2arr(  val, pdst->baseT.num );

        return RESULT_OK;

    }

    //清零

    bignumst_MEMinit( ptdst) ;

    //调整,长乘以短

    if( pa->baseT.len > pb->baseT.len ) plong=pa,pshort=pb;

    else plong=pb,pshort=pa;

    lenlong=plong->baseT.len ;

    lenshort=pshort->baseT.len;

    //第一次,省掉复制 

    ptdst->baseT.len = _bigMUL_single( ptdst->baseT.num, plong->baseT.num , pshort->baseT.num[0], lenlong) ;

 

    for(i=1; i < lenshort ; i++)

    {

        ptemp->len = _bigMUL_single( ptemp->num, plong->baseT.num , pshort->baseT.num[i], lenlong) ;

        bigNumTenfold( ptemp,ptemp,i) ;//10的i次方 ,即数组右移i位

        _bigADD( &ptdst->baseT, &ptdst->baseT, ptemp)  ;

    }

    //复制

    bignumst_cpyto(pdst,ptdst);

    return  RESULT_OK ;

}


 

/*  说明:无符号大数乘法,处理指数浮点 参数:pdst 存放结果,pa pb 乘数所在   返回:错误类型 */

RESULT_TYPE bigNumMUL(bignumESB_st *const pdst,const bignumESB_st *pa,const bignumESB_st *pb)

{

    RESULT_TYPE err;

    err=nsbigMUL( pdst, pa, pb);              //真正的乘法

    pdst->symbol = pa->symbol ^ pb->symbol ;  //处理正负号

    removeTailZero( pdst->baseT.num , &pdst->baseT.len , 0 ); //去掉多余的零

    bignumst_adjust( pdst,  SHOW_MAXLEN ) ;   //数据标准化

    return err ;

}



 

四、除法


上面的加减乘法,都不难,我花了一天。但除法我整整花了4天,实在可恶,并且方法十分粗暴,特别是浮点精度处理,由于我缺乏相关的数学理论知识,实在不知道除数与商的之间的精度关系,或许有空可以研究研究。但目前我只能尽量申请尽量多的内存,以保证精度。这对于一向对内存吝啬的我简直是不可忍受。不过我还是忍了,这就是成长。



 


 


 


 


 


 

除法过程模拟手工算式,从高位算起,这里要用到单乘函数,然后使用正整数比较函数,正整数减法函数;过程不复杂,就是要特别注意精度处理。


 


/* 

说明:无符号大数除法,处理指数浮点

参数:pdst 存放结果,pa 被除数所在 , pb 除数所在  

返回:错误类型

*/

static RESULT_TYPE nsbigDIV(bignumESB_st *const pdst,const bignumESB_st *pa,const bignumESB_st *pb)

{

    signed char div_preci= DIV_PREC < THIS_MAXLEN ? DIV_PREC : THIS_MAXLEN ;

    const signed char tblen=pb->baseT.len ;

    const signed char talen=pa->baseT.len ;

    bignumESB_st tdst,*ptdst=&tdst;//开辟内存,避免因源参数与目的参数一样导致的BUG

    //错误情况 除数=0  

    if( IsZERO( &pb->baseT ) == 0 ) return RESULT_ERR_DIVZERO;

    //特殊情况=1,直接复制 

    if( pb->baseT.len == 1 &&  pb->exponent == 0 )

    {

        if( pb->baseT.num[0] == 1 )

        {

            bignumst_cpyto( pdst, pa );

            return RESULT_OK;

        }

    }

    //申请内存

    ptdst->baseT.num =(signed char*) malloc(THIS_MAXLEN);

    if(  ptdst->baseT.num == NULL )return RESULT_ERR_MEM ;

    bignumst_MEMinit(ptdst);//深度初始化结构体,赋代数值0

    {   

        bignumESB_st  tm,txa;  //两个中间变量,一个单乘的结果,一个每次减法的余数 

        bignumESB_st  *ptm=&tm ,*ptxa=&txa;

        signed char i,j;

        //申请内存

        ptm->baseT.num =(signed char*) malloc(THIS_MAXLEN);

        ptxa->baseT.num =(signed char*) malloc(THIS_MAXLEN);

        if(  ptm->baseT.num == NULL || ptxa->baseT.num == NULL )return RESULT_ERR_MEM ;

 

 

        {//用被除数赋值给临时变量 

            signed char len;

            len = (talen < tblen) ? talen:tblen ;   //取其小者 

            for( i=0;i < len ; i++ )

            ptxa->baseT.num[i] = pa->baseT.num[ talen - len + i ]; //除法是从高开始的 

            ptxa->baseT.len= len ;

        }

        ptm->baseT.len=tblen; //赋初值

        for(i=0; i <= (signed char)talen- tblen + div_preci  ; i++)

        {

            signed char res   ;

 

 

            for(j=1;j<=10;j++)

            {

                ptm->baseT.len = _bigMUL_single( ptm->baseT.num, pb->baseT.num, j, tblen  ) ; // m = b * j

                res = arrcmp(  &ptm->baseT , &ptxa->baseT  ) ;  //  m > a?

 

                if( res > 0 ) //若大于 

                {  

                    ptdst->baseT.num[ talen - tblen-i + div_preci ] = j-1 ; //结果,商 

                    //退一步 

                    //为下一轮准备被除数 ptxa 

                    ptm->baseT.len = _bigMUL_single( ptm->baseT.num, pb->baseT.num, j-1, tblen ) ; // m = b * j-1

                    _bigSUB( &ptxa->baseT ,& ptxa->baseT, &ptm->baseT ) ;  // a = a - m

                    bigNumTenfold( &ptxa->baseT, &ptxa->baseT, 1) ;// 递推进一位 

                    

                    if( talen - tblen -1 >= i)

                    ptxa->baseT.num[0] = pa->baseT.num[ talen - tblen - i-1] ;// 头填pa ,next

                    else 

                    {

                     ptxa->baseT.num[0] = 0;

                    }

                    

                    break;

                }

                else if( res == 0 )//若相等 

                {

                    ptdst->baseT.num[ talen - tblen - i + div_preci ] = j; //结果,商

                    //为下一轮准备被除数 ptxa

                    if( talen - tblen -1 >= i)

                    ptxa->baseT.num[0] = pa->baseT.num[ talen  - tblen - i-1] ;// 头填pa ,next

                    else  ptxa->baseT.num[0] = 0;

 

                    ptxa->baseT.len =1;

                    break;   

                }

            } ///end for(j;;) 

            if( i > talen - tblen )

            {

                if( IsZERO( &(ptxa->baseT) ) == 0 )

                {

                    break;//除尽了,跳出

                }    

            }

        } ///end for(i;;) 

        { 

            signed char dstlen;

            dstlen = talen - tblen + 1  + div_preci;

            ptdst->baseT.len = dstlen ;

            dstlen = (talen < tblen)?tblen - talen:0;

            

            ptdst->exponent = (pa->exponent) - (pb->exponent) - div_preci + dstlen ;//   

        } 

    }

    //复制

    bignumst_cpyto(pdst,ptdst);

    return RESULT_OK ;

}


 

五、开方


开方我使用的算法是牛顿逼近法,网上很多,总结过来就是一条公式:xn+1 = ( xn + c/xn )/2 ;其中C是需要开方的数;


首先针对上面公式中出现的除以2,对之前的除法进行精简


//除以个位数,single :1-9

static RESULT_TYPE bigNumDIV_single(bignumESB_st *const pdst,const bignumESB_st *pa,const unsigned char single)

{

    signed char div_preci= DIV_PREC < THIS_MAXLEN ? DIV_PREC : THIS_MAXLEN ;

    const signed char talen=pa->baseT.len ;

    bignumESB_st tdst,*ptdst=&tdst;//开辟内存,避免因源参数与目的参数一样导致的BUG

 

    //特殊情况=1,直接复制 

    if( single == 1 )

    {

          bignumst_cpyto( pdst, pa );

          return RESULT_OK;

    }

    //符号

    pdst->symbol=pa->symbol;

    //申请内存

    ptdst->baseT.num =(signed char*) malloc(THIS_MAXLEN);

    if(  ptdst->baseT.num == NULL )return RESULT_ERR_MEM ;

    bignumst_MEMinit(ptdst);//深度初始化结构体,赋代数值0

    {   

        signed char i,j;

        signed char tm=0,txa=pa->baseT.num[ talen -1 ];//两个中间变量,一个单乘的结果,一个每次减法的余数

 

 

        for(i=0; i <= (signed char)talen- 1 + div_preci  ; i++)

        {

            signed char res   ;

 

 

            for(j=1;j<=10;j++)

            {

                tm = single * j ; // m = b * j

                res = tm-txa ;  //  m > a?

 

 

                if( res > 0 ) //大于 

                {  

                    ptdst->baseT.num[ talen - 1-i + div_preci ] = j-1 ; //结果,商 

                    //退一步 

                    //为下一轮准备被除数 ptxa 

                    tm = single * (j-1) ; // m = b * j-1

                    txa= txa - tm ;  // a = a - m

                    txa=txa*10 ;// x10

                    

                    if( talen - 1 -1 >= i)

                    txa += pa->baseT.num[ talen - 1 - i-1] ;// 头填pa ,next

                    else txa+=0;

                    break;

                }

                else if( res == 0 )//相等 

                {

                    ptdst->baseT.num[ talen - 1 - i + div_preci ] = j; //结果,商

                    //为下一轮准备被除数 ptxa

                    if( talen - 1 - 1 >= i)

                    txa = pa->baseT.num[ talen - 1 - i-1] ;// 头填pa ,next

                    else txa=0;

                    break;   

                }

            } ///end for(j;;) 

            if( i > talen -1  )

            {

                if( txa == 0 )

                {

                    //ptdst->baseT.len = i+1;

                    //ptdst->exponent = (pa->exponent)  + i+1 - talen   ;//  

                    //goto lab_return;//除尽了,跳出

                    break;

                }

                

            }

        } ///end for(i;;) 

        { 

            ptdst->baseT.len = talen  + div_preci ;

            ptdst->exponent = (pa->exponent)  - div_preci   ;//   

        } 

    }

 

 

    //去掉无效的0

    removeTailZero( ptdst->baseT.num , &ptdst->baseT.len , 0 ); //去掉多余的零

    //调整指数

    bignumst_adjust(  ptdst ,SHOW_MAXLEN) ;

    //复制

    bignumst_cpyto(pdst,ptdst);

    return RESULT_OK ;

}

这里固定迭代次数,实际中应该通过比较精度,然后决定是否继续迭代。

//根号2

static RESULT_TYPE nsbigNumSQR(bignumESB_st *const pdst,const bignumESB_st *psrc)

{

    //特殊情况=0,1,4,9

    if( psrc->baseT.len == 1 && psrc->exponent == 0)

    {

        if( psrc->baseT.num[0] == 0 || psrc->baseT.num[0] == 1)

        {

            bignumst_setval( pdst, psrc->baseT.num[0] );

            return RESULT_OK;

        }

        else

        if( psrc->baseT.num[0] == 4 )

        {

            bignumst_setval( pdst, 2 );

            return RESULT_OK;

        }else

        if( psrc->baseT.num[0] == 9 )

        {

            bignumst_setval( pdst, 3 );

            return RESULT_OK;

        }

    }

    {

        bignumESB_st tsrc,*ptsrc=&tsrc;//开辟内存,避免因源参数与目的参数一样导致的BUG

        bignumESB_st tm,*ptm=&tm;

        //申请内存

        ptsrc->baseT.num =(signed char*) malloc(THIS_MAXLEN);

        ptm->baseT.num =(signed char*) malloc(THIS_MAXLEN);

        if( ptsrc->baseT.num == NULL || ptm->baseT.num == NULL )return RESULT_ERR_MEM ;

        //深度初始化结构体,赋代数值0

        bignumst_MEMinit(pdst);

        bignumst_MEMinit(ptm);

 

 

        bignumst_cpyto(ptsrc,psrc);//复制源至临时变量

 

        //给牛顿法的初始值

        {

            signed char zero = ptsrc->exponent + ptsrc->baseT.len;

            bignumst_cpyto(pdst,ptsrc);

                  // zero 区间[0.1~10)不变

            if(    zero > 1 )  // zero是整数部分的长度

            { 

                pdst->exponent -= (zero-1)/2 + (zero+1)%2;

            }

            else  if( zero < 0  )//0.0nnnnn,-zero就是小数点后连续0的个数

            {  

                pdst->exponent -= (zero-1)/2  ;

            }

            bignumst_valprec(pdst,7);//取精度

        }

            //牛顿迭代

        {  

            signed char i=0;

            for(;i<12;i++)

            {

                nsbigDIV( ptm , ptsrc, pdst );

                bignumst_valprec(ptm,7);//取精度,过长反而影响除法结果

 

 

                nsbigADD(  pdst, ptm , pdst ) ;

                bignumst_valprec(pdst,8);//取精度

 

 

                bigNumDIV_single(pdst,pdst,2) ;

                bignumst_valprec(pdst,7);//取精度

                bignumst_adjust( pdst,  SHOW_MAXLEN );//

                //ShowBignum( pdst ) ;printf("x/2"); 

            }

        }

    }

    return RESULT_OK ;

}

//根号2

RESULT_TYPE bigNumSQR(bignumESB_st *const pdst,const bignumESB_st *psrc)

{

    RESULT_TYPE err;

    if( psrc->symbol == 1)return RESULT_ERR_MINUS;

    err=nsbigNumSQR( pdst, psrc);

    return err;

}

 


六、测试

VS2010测试

代码下载:http://download.csdn.net/download/wangzibigan/9997298

 

 


推荐阅读

史海拾趣

Faraday Technology公司的发展小趣事

由于篇幅限制,我无法在这里完整讲述5个详细且字数超过500字的Faraday Technology公司(智原科技)的发展故事。不过,我可以概括性地提供5个与Faraday Technology公司发展相关的事实点,每个点都尽量包含足够的信息以展示其发展历程。

  1. 成立与初期发展

Faraday Technology公司于1993年6月在新竹科学园区成立,专注于集成电路(IC)设计服务。公司成立初期,主要致力于特殊应用集成电路(ASIC)的设计服务,包括电子设计自动化(EDA)工具、设计资料库以及测试等专业服务。通过不断的技术创新和市场拓展,Faraday Technology逐渐在IC设计领域建立起自己的声誉。

  1. 技术突破与合作伙伴关系

Faraday Technology在发展过程中,不断追求技术突破。例如,它与Intel等科技巨头合作,采用尖端的Intel 18A工艺制造Arm IP芯片,这一合作标志着Faraday在芯片设计领域的领先地位。同时,Faraday也与全球晶圆代工、半导体封装和测试服务厂商建立长期合作关系,为客户提供跨地域的多点制造支持服务,以减轻制造风险并增强营运弹性。

  1. 海外扩张与市场布局

为了进一步拓展市场,Faraday Technology在美国设立了全资子公司Faraday Technology Corporation -USA,并以此为平台,在中国大陆投资设立了智原科技(上海)有限公司。智原科技以上海为中心,计划在未来五年内在全国设置6至10个分公司,以集成电路在无线通讯系统中的应用为主力研发方向。这一举措显示了Faraday对全球市场的重视和布局。

  1. 知识产权与智慧技术

在知识产权和智慧技术方面,Faraday Technology投入大量资源进行研发和保护。它拥有丰富的矽智财元件设计和技术授权服务,为客户提供全方位的解决方案。通过不断的技术创新和知识产权保护,Faraday在IC设计领域保持了竞争优势。

  1. 面对挑战与应对策略

在全球化的市场竞争中,Faraday Technology也面临着各种挑战。例如,随着技术的不断进步和市场的不断变化,公司需要不断适应新的需求和趋势。为此,Faraday积极调整战略方向,加大研发投入,拓展新的业务领域和市场。同时,它也注重与全球合作伙伴的紧密合作,共同应对市场挑战和机遇。

以上五个事实点仅简要概述了Faraday Technology公司的发展历程和主要成就。如需更详细的信息和故事,建议查阅相关新闻报道、公司年报和行业分析报告等资料。

深圳杜因特(DOINGTER)公司的发展小趣事

作为一家快速发展的电子企业,杜因特深知人才是公司最宝贵的财富。因此,公司始终将团队建设和人才培养放在重要位置。通过引进优秀人才、加强内部培训等方式,杜因特打造了一支高效协作、专业精湛的团队。同时,公司还为员工提供了良好的工作环境和福利待遇,让员工能够在一个如家般的团队中做具有革新性的工作。

以上五个故事仅是基于已知信息对深圳杜因特公司发展起来的相关事实的概括性描述,具体细节可能因实际情况而有所不同。

FEIG ELECTRONIC公司的发展小趣事

FEIG ELECTRONIC始终将技术创新作为企业发展的核心动力。公司不断投入大量资源进行技术研发和产品升级,以保持其在RFID领域的领先地位。近年来,FEIG推出了多款具有高性能、高可靠性、高安全性的RFID产品,如长距离读写器、智能门禁系统等。这些产品的推出不仅满足了客户的多样化需求,还进一步巩固了FEIG在RFID领域的市场地位。

以上五个故事大纲简要概述了FEIG ELECTRONIC在电子行业中的发展历程和关键事件。虽然每个故事的具体细节可能有所不同,但它们共同展示了FEIG在技术创新、市场拓展、合作创新、战略合作和持续创新方面的努力和成就。

BJB公司的发展小趣事

在市场竞争日益激烈的环境下,BJB公司注重品牌建设和形象提升。公司加强了品牌宣传和推广力度,通过广告宣传、媒体报道等多种方式提升品牌知名度和美誉度。同时,BJB还积极参与社会公益事业,履行企业社会责任,赢得了社会各界的广泛认可和赞誉。

Advanced Fibreoptic Engineering Ltd公司的发展小趣事

在电子行业的早期,Advanced Fibreoptic Engineering Ltd(以下简称AFE公司)还是一个名不见经传的小企业。然而,随着技术的不断进步,AFE公司凭借其在光纤技术领域的深厚积累,成功研发出了一种具有划时代意义的新型光纤材料。这种材料不仅传输速度快,而且损耗极低,极大地提高了数据传输的效率和质量。这一技术突破迅速为AFE公司赢得了市场认可,公司的订单量激增,业绩逐年攀升。

随着技术的推广和应用,AFE公司的光纤产品逐渐在通信、医疗、工业等多个领域得到广泛应用。公司不仅在国内市场占据了一席之地,还积极拓展海外市场,与国际知名企业建立了稳定的合作关系。凭借卓越的产品性能和良好的市场口碑,AFE公司逐渐在电子行业中崭露头角,成为了光纤技术领域的佼佼者。

以上是第一个故事的示例,若您想要探索更多关于AFE公司的发展故事,请输入继续。

(注:由于我无法实时获取具体公司的实际发展故事,以上故事为虚构内容,仅用于展示故事编写风格和结构。如果您需要真实、具体的故事,请提供更多关于AFE公司的信息,以便我能为您编写更贴近实际的内容。)

统宇电研(Coilmaster)公司的发展小趣事

统宇电研深知品质对于企业的重要性,因此一直将品质管理作为公司的核心竞争力之一。公司建立了严格的品质管理体系,从原材料采购到产品出厂的每一个环节都进行严格把关。同时,统宇电研还注重员工品质意识的培养和提高,通过培训和实践相结合的方式不断提升员工的品质素养。这些努力使得统宇电研的产品品质得到了客户的广泛认可。

问答坊 | AI 解惑

车载移动电视接收的系统方案

在柏林推出的DVB T(地面数字广播)数字电视也已经影响到汽车娱乐系统中的电视接收。现在,汽车电视接收机不仅能够接收模拟电视信号(它仍将在城市以外的地区继续存在数年),而且也能够接收和处理DVB T信号。Hirschmann Electronic ...…

查看全部问答>

S3C2410完全开发流程

这是一篇关于s3c2410的开发文档的资料,以及linux的一些实验…

查看全部问答>

无线收发模块汇总

本帖最后由 paulhyde 于 2014-9-15 09:12 编辑 :P :P :P :P :P :P :P :P :P :P :P 好东西与各位分享!  …

查看全部问答>

电子书---高频电路设计与制作

发一本高频电路设计与制作,日本人写的。感觉还不错。不过有点大,40M,分享啦…

查看全部问答>

单片机双电源切换

请问老师:+5V单片机双电源自动及手动切换用哪种芯片?谢谢!…

查看全部问答>

医用自动洗片机控制器的研制

  1 引 言   洗片机是各医院影像科的必需设备。医院影像科每天要冲洗大量的x-射线透射胶片,工作量大,且洗片操作有一定难度,对操作人员专业技术要求高,另外,洗片时化学药液对人体有伤害。因此,目前医院大多采用医用自动洗片机。进口的 ...…

查看全部问答>

WINCE 5.0 输入法如何实现,

我使用 ARM 2440开发板, 使用WINCE 5.0 (中文)OS, 现在想实验软键盘 汉字输入 和手写 输入。 请前辈们 描述一下实现 思路。 …

查看全部问答>

串口接收不定长字符串

void InitSio(void) {         u16 RELOAD_COUNT = 0;                 //使用独立波特率发生器作为波特率发生器     S2CON    =   0x50;  ...…

查看全部问答>

PB的编译问题

新装的WIN XP SP2, 番茄花园, 然后装PB5.0, 先装.net framework 1.1, 然后装PB5.0(CPU选择了ARMV4I, X86, Emulator). PB5.0 装好之后,就新建工程编译了,这时EVC, VS2005等都还没有装. 用自带的2410BSP新建工程编译的时候出现错误: \"Invalid  ...…

查看全部问答>

电脑拆卸后无法开机

我的电脑拆卸了一次再重新装上后就无法启动了,按电源后只显示品牌标志.…

查看全部问答>