打印
[国产单片机]

基于8位加法的初等函数计算器设计

[复制链接]
3000|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
因果|  楼主 | 2008-7-20 17:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
基于8位加法的初等函数计算器设计
2004年初,我在一家台资小公司上班,公司老板想在电子行业有一个持久的,产品来维系公司的资金来源,开始着手于计算器的研制。最后把这个任务分派给了我,由我写出初等函数,多项表达式由老板自己写。于是我开始一项痛苦的摸索过来,有两上问题我必须解决:
1.    成本问题(即要达到高精度,也要考虑成本问题,主芯片选用6502,下Mask 2-3元人发币,工程可实现性,计算一个初等函数最多允许1/20秒).
2.    计算方法,在上大学的时候用的是泰勒级数,但是展开式太多了,是不是别他国外的公司也是用这个级数展开了,这是一个问题。
我看了许多的国外的网站,讲到了卡西欧 CASIO的设计,但是也没有说到具体的底层应该怎样构建。我查阅了一些关于数据计算方法的书籍,其中有一个叫密比雪夫多项式的数学方法吸引了我,直觉告诉我,这就是我要找到的。后来计算器的设计,我用的是密比雪夫多项式的系数,而不是用泰勒级数展开得的系数。
整个程序的过程是基于8位的加减法进行的,浮点数是BCD码。我把它做成了Class,用C++编写,其实也同struct 一样的。对于浮点数的乘除法,我采用了建倍数表的方法。
设计的整过程序是基于{AddSub8. ADC8();AddSub8.SBC8()}8位的加减法去模拟6502,
用它搭建浮点数的加减乘除: FPAddSub(),FPMul();FPDiv();其中Cchebft  用于计算多项式的系数.
笔者把这几年收集的关于国人对计算器的研究**”计算器的计算误差与计算精确度的研讨”,”怎样用没有开立方根按键的计算器开立方根和高次方根”等等文件及计算器源程序的工程文件放置网站: http://www.sokutek.com/document.asp,如果您感兴趣,请去下载。如有疑问也可以来电,我们一起讨论:chenshiyangyi@163.com;QQ:3637323.
还有一个问题,就是对数函数,并不是一直都用切比雪夫系数计算,在一定泛围,用了帕德函数计算。具体的方法,可能要做适当的改动.

源程序如下:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <math.h>
#define CHM 7
#define ENTER printf("\n");
#define PI 3.141592653589792384626433832795

//程序有一些问题:可能在运算前先判断末尾连续为零的个数可提高效率

 class AddSub8
{
 public:
         bool  c;//进位、借位标志
         short ADC8(short,short);//8bits相加
         short SBC8(short,short);//8bits相减
         void  CLC(){c=0;};
         void  SEC(){c=1;};
};
 short AddSub8::ADC8(short a1,short a2)
 {
  short result;
  if(c==true)  result=a1+a2+1;
  else result=a1+a2;
  if(result>99)  { c=1;return result-100;}
  else    {c=0;return result;}
 }
 short AddSub8::SBC8(short a1,short a2)
 {
 short result;
 if(c==true)  result=a1-a2;
 else result=a1-a2-1;
 if(result<0) {c=0;return result+100;}
 else {c=1;return result;}
 };


class FP
{
 public:
        bool  Sign;//符号 (1)为负
        short  Exponenet;//以二进制形式表示的指数
        short Mantissa[CHM];//CHM BCD码形式的尾数
        void  Equ(short *data) {for(int i=0;i<CHM;i++) Mantissa=data;}
  //    bool  ExponenetSign()      {if((Exponenet&128)>0) return true;  return false;}
        FP& operator =(FP & fp)
        { 
            Sign=fp.Sign;
            Exponenet=fp.Exponenet;
            for(int i=0;i<CHM;i++) Mantissa=fp.Mantissa;
            return *this;}
        friend FP  operator +(FP,FP);
        friend FP  operator -(FP,FP);
        friend FP  operator *(FP,FP);
        friend FP  operator /(FP,FP);
        
       
};

FP operator +(FP num1,FP num2)
{
FP num3;
void FPAddSub(FP,FP,FP&);
FPAddSub(num1,num2,num3);
return num3; 
}
FP operator -(FP num1,FP num2)
{
FP num3;
void FPAddSub(FP,FP,FP &);
num2.Sign=!num2.Sign;
FPAddSub(num1,num2,num3);
return num3;
}
 FP operator *(FP num1,FP num2)
 {
  FP num3;
  void FPMul(FP,FP,FP&);
  FPMul(num1,num2,num3);
  return num3;
 }
 FP operator /(FP num1,FP num2)
 {
 FP num3;
 bool FPDiv(FP,FP,FP&);
 FPDiv(num1,num2,num3);
 return num3;
 }
class Vector
{
public:
      void PrintfShort(short *data,int n,bool flag=true)        
      {if(flag==true) printf("\n");
        for(int i=0;i<n;i++)     
        {    if(data==0) {printf("00");continue;}
            if(data<10) printf("0");
            printf("%d",data);
        }
      }
    void BCDLeftShift(short *,short *,int);
    void BCDLeftShift(short *,int);
    void PrintfFp(FP);
    void Equ(short *data1,short *data2,int n){for(int i=0;i<n;i++) data1=data2;}
    void PrintZero(int n){for(int i=0;i<n;i++) printf("0");}
    void ClrFP(FP &data)  {data.Exponenet=0;data.Sign=false;for(int i=0;i<CHM;i++) data.Mantissa=0;}
    void ClrShort(short *data,int n){for(int i=0;i<n;i++) data=0;}
    void BCD8ToBCD4(short *,int,short *);
    void BCDRightShift(short *,int);//左移一位,高BCD移出,末低BCD添零
    double FP2Double(FP);//把FP数据类型转化为double型
    void   Double2FP(double,FP&);
    FP     Double2FP(double);
    void   Norm(FP &);
    void PrintfDouble(double *,int);
 
};
  FP Vector::Double2FP(double a)
  {
  FP num1;
  Double2FP(a,num1);
  return num1;
  }
   void Vector::PrintfDouble(double *data,int num)
   {
   for(int i=0;i<num;i++) printf("%.15e\n",data);
   }
   void Vector::Norm(FP &x)
   {
   for(int i=0;i<2*CHM;i++)
       if(x.Mantissa[0]/10==0) {x.Exponenet--;BCDRightShift(x.Mantissa,CHM);} 
           else 
           break;
   if(i==2*CHM) x.Exponenet=0;
   }
  void Vector::Double2FP(double a,FP &fp)
  {
     if(a>0) fp.Sign=false;
     else
     {
     fp.Sign=true;
     a=fabs(a);
     }
     fp.Exponenet=0;
     
     if(a<1e-110) {ClrFP(fp);return;}
     int exp=0;
     for(int i=0;i<110;i++)
     {
         if(floor(a)==0) {a*=10;fp.Exponenet--;}
         else
         {
         a/=10;fp.Exponenet++;
         }
      if(floor(a)>=1 && floor(a)<=9) break; 
     }
     a=a*10;

          for(i=0;i<CHM;i++)
          {
              fp.Mantissa=(short)floor(a);
              a=(a-floor(a))*100;
          
          }
         
  }
  double Vector::FP2Double(FP num)
  {
    double a=0,b=10;
    for(int i=0;i<CHM;i++)
    {
    a+=num.Mantissa/b;
    b*=100;
    }
    a*=pow(10,num.Exponenet);
    if(num.Sign==false)    return a;
    else
        return a*(-1);
  }
void Vector::BCDRightShift(short *num,int n)//左移一位BCD码
{
    for(int i=0;i<n-1;i++)
        num=(num%10)*10+num[i+1]/10;
    num[n-1]=(num[n-1]%10)*10;
}
void Vector::BCDLeftShift(short *num,int n)
{
    
    for(int i=n-1;i>=1;i--)
        num=num/10+(num[i-1]%10)*10;
    num[0]=num[0]/10;
}

void Vector::BCD8ToBCD4(short *num1,int n,short *num)
{
      for(int i=0;i<n;i++)
      {
      num[2*i]=num1/10;//在汇编程序的实现: &0xF0
      num[2*i+1]=num1%10;//&0x0F
      }

}
void Vector::BCDLeftShift(short *num1,short *num2,int n)
 {
  short a=0,b=0;
    for(int i=0;i<n;i++)
    {
    a=num1/10;
    num2=b*10+a;
    b=num1%10;
    }
    num2[n]=b*10;
 };
void Vector::PrintfFp(FP data)
{
if(data.Sign==true) printf("-");
printf("%d.%d",data.Mantissa[0]/10,data.Mantissa[0]%10);
 for(int i=1;i<CHM;i++) 
 {
     if(data.Mantissa<=9) printf("0%d",data.Mantissa);
     else
     printf("%d",data.Mantissa);
 
 }   
printf("E%d",data.Exponenet);
}
 class FileFP
 {
 public:
       void SaveDouble(double);
       void SaveFP(FP);
       void SaveCoAsm(FP);
       FP   ReadFP();
       FileFP(char *,bool);
       ~FileFP(){fclose(fp);}

 private:
       FILE *fp;

 };
 FileFP::FileFP(char *str,bool flag=true)
 {
     if(flag==true)  fp=fopen(str,"w");
     else
         fp=fopen(str,"r");
     if(fp==NULL) exit(0);
 }
 FP FileFP::ReadFP()
 {
 char c1,c2;
 short n=0,n1,n2=0;
 FP x;
 Vector vect;  vect.ClrFP(x);
 c1=getc(fp);
 while(c1<'0' || c1>'9')
 {
     if(c1=='-') x.Sign=true;
     c1=getc(fp);
 }
 c2=getc(fp);//小数点

 while(c1!='e' && c1!='E')
 {
 c2=getc(fp);
 x.Mantissa[n]=(c1-'0')*10+c2-'0';
 n++;
 c1=getc(fp);
 }

 fscanf(fp,"%d",&n1);
 x.Exponenet=n1;
 return x;
 }

 void FileFP::SaveDouble(double x)
 {
 fprintf(fp,"%.13e\n",x);
 }
 void FileFP::SaveFP(FP x)
 {
 if(x.Sign==true) fprintf(fp,"-");
 fprintf(fp,"%d.%d",x.Mantissa[0]/10,x.Mantissa[0]%10);
 for(int i=1;i<CHM;i++) 
 {
     if(x.Mantissa<=9) fprintf(fp,"0%d",x.Mantissa);
     else
     fprintf(fp,"%d",x.Mantissa);
 }   
fprintf(fp,"e%d\n",x.Exponenet);
 }
         
 void FileFP::SaveCoAsm(FP x)
 {
 fprintf(fp,"\n                   .DB %d",x.Exponenet);
 if(x.Sign==true) fprintf(fp,",1");
 else
     fprintf(fp,",0");
 for(int i=0;i<CHM;i++)
     if(x.Mantissa<=9) fprintf(fp,",$0%d",x.Mantissa);
     else
         fprintf(fp,",$%d",x.Mantissa);
 
 }


void FPAddSub(FP num1,FP num2,FP & num3)
{
 short shift=0,i;
 bool  flag=false;//false 表示num1为主运算区,num2进行移位操作 ,c表示有无进位
 short num[CHM+2];//进行移位对齐时应该注意任零两加数都不应该为零
 if(num1.Mantissa[0]==0) {num3=num2;return;}
 if(num2.Mantissa[0]==0) {num3=num1;return;}//不是很规范;判零
 num[CHM]=0;
    if(num1.Exponenet==num2.Exponenet) //指数相等,比较尾数
    {
     for(i=0;i<CHM;i++)
     {    if(num1.Mantissa==num2.Mantissa)  continue;
        if(num1.Mantissa>num2.Mantissa)   flag=false;
        else
            flag=true;
        break;
    }
    }
    else//指数不相等,比较指数
    {
        shift=num1.Exponenet-num2.Exponenet;
        if(shift>0) flag=false;
        else
        {
            flag=true;shift=shift*(-1);
        }
    }
//确定主运算区(num3),加数(num)
Vector vect;

  if(flag==false) 
  {num3=num1;
  if(shift%2==0)   vect.Equ(num,num2.Mantissa,CHM);
  else 
         vect.BCDLeftShift(num2.Mantissa,num,CHM);//BCD右移一位
  }
    else
    {num3=num2;
    if(shift%2==0)
    vect.Equ(num,num1.Mantissa,CHM);
    else
      vect.BCDLeftShift(num1.Mantissa,num,CHM);//BCD码右移一位
    }
AddSub8 add;


shift=shift/2; 
if(shift>CHM+1) return;
short   *result;
result=new short[4*CHM];//可能太浪费空间
vect.ClrShort(result,3*CHM);
        if((num1.Sign^num2.Sign)==false)  //加法
        {
        add.CLC();
        for(i=shift+CHM;i>=0;i--) 
           if(i>=CHM) result[i+1]=add.ADC8(0,num[i-shift]); //有几步是多余的    
           else if(i<shift) result[i+1]=add.ADC8(num3.Mantissa,0);
           else
            result[i+1]=add.ADC8(num3.Mantissa,num[i-shift]);
 
           result[0]=add.ADC8(0,0);//以上完成了数值的加法
           if(result[0]==0) 
               vect.Equ(num3.Mantissa,result+1,CHM);//没有进位
           else//否则右移一位
           {
           num3.Exponenet++;
           //vect.BCDLeftShift(result+1,num3.Mantissa,CHM-1);//一次左移更干净
           //num3.Mantissa[0]+=10*result[0];//???
           
           vect.BCDRightShift(result,CHM+1);
           vect.Equ(num3.Mantissa,result,CHM);

           }
     
           delete []result;
           return;
        }           
        else//减法
        {
        add.SEC();
        for(i=shift+CHM;i>=0;i--) 
           if(i>=CHM) result=add.SBC8(0,num[i-shift]);     //有几步是多余的:
                                                           //至少不应该保存起来(没有多余,有可能前面几位为零)
                                                          //即使这种情况没有,但可以为后续的开发利用
           else if(i<shift) result=add.SBC8(num3.Mantissa,0);
           else
               result=add.SBC8(num3.Mantissa,num[i-shift]);
           
           for(i=0;i<2*CHM;i++)//因为有可能被减数与减数的前几位是相等的
                 if(result==0) {num3.Exponenet-=2;continue;}
                else
                break;
 
         if(i>2*CHM-1) {vect.ClrFP(num3);return;}//如果结果等于零,返回(这一步可以在函数开始处进行判断)
          
         if(result>9) vect.Equ(num3.Mantissa,result+i,CHM);
         else
          {
        //  vect.BCDLeftShift(result+i+1,num3.Mantissa,CHM-1);//???????????
         // num3.Mantissa[0]+=result*10;
          num3.Exponenet--;
              
            vect.BCDRightShift(result+i,CHM+1);
            vect.Equ(num3.Mantissa,result+i,CHM);
          } 
        }
        delete []result;
};

 void FPMul(FP num1,FP num2,FP& num3)
 {
     //首先应文盲判断是否为零
 num3.Exponenet=num1.Exponenet+num2.Exponenet;//指数相加
 num3.Sign=num1.Sign^num2.Sign;//符号异或
 //尾数移位相加
 int i,j;
 short Rnum1[10][CHM+1];//一张乘法表:Rnum1[0]:进位标志
 for(i=1;i<10;i++) Rnum1[0]=0;
 for(i=0;i<=CHM;i++) Rnum1[0]=0;
 AddSub8 add;//8位的BCD加法器
 Vector vect;
     for(i=1;i<=9;i++)//计算被乘数的1-9倍,以便于查表计算结果
     {
     add.CLC();
     for(j=CHM-1;j>=0;j--)
         Rnum1[j+1]=add.ADC8(num1.Mantissa[j],Rnum1[i-1][j+1]);
        
     Rnum1[0]=add.ADC8(0,Rnum1[i-1][0]);
 
     }

//为了减少移位,我们分为二个结果,只需移一次即可:移8位运算(0,2,4,6,8;1,3,5,7,9)

short Result1[2*CHM],Result2[2*CHM];//这里定义的数过于大
short Address[2*CHM];
vect.BCD8ToBCD4(num2.Mantissa,CHM,Address);//为了便于查表(可能在机器上实现起来更节约时间):
vect.ClrShort(Result1,2*CHM);
vect.ClrShort(Result2,2*CHM);

    for(i=CHM-1;i>=0;i--)
    {
     add.CLC();
     if(Address[i*2]!=0)
     for(j=CHM;j>=0;j--)
     {
     Result1[j+i]=add.ADC8(Result1[j+i],Rnum1[Address][i*2]][j]);      
     }
     
       add.CLC();
     if(Address[i*2+1]!=0)
     for(j=CHM;j>=0;j--)
     {
     Result2[j+i]=add.ADC8(Result2[j+i],Rnum1[Address][i*2+1]][j]);      
     }
      
    }
//将Result2右移一位,然后两数相加
short Result3[2*CHM+1];
vect.ClrShort(Result3,2*CHM+1);
vect.BCDLeftShift(Result2,Result3,2*CHM);
 
  add.CLC();
  for(i=2*CHM-1;i>=0;i--)
    Result2=add.ADC8(Result1,Result3);
 

    if(Result2[0]==0) vect.Equ(num3.Mantissa,Result2+1,CHM);//进行归一化时可以编一个子程序
    else
    {
        //  vect.BCDLeftShift(Result2+1,num3.Mantissa,CHM-1);//???????????:倒不如一次左移来得干净
         // num3.Mantissa[0]+=Result2[0]*10;
          num3.Exponenet++;

          vect.BCDRightShift(Result2,CHM+1);
          vect.Equ(num3.Mantissa,Result2,CHM);
    }
 }

 bool FPDiv(FP num1,FP num2,FP & num3)
 {
 /* 除法运算:符号异或,阶数相减:尾数
     (1.先检查除数的所谓的有效长度;
      2.两数相减,判断进位标志
      3.保存商
     )采取的运算法则是基于人工的算法,精度可以任意长,我们作了一张除数的倍数表*/
 
 num3.Exponenet=num1.Exponenet-num2.Exponenet;
 num3.Sign=num1.Sign^num2.Sign;

 short L=CHM;//表示除数的长度:
 int i,j,k;
 for(i=CHM-1;i>=0;i--)
     if(num2.Mantissa==0) {L--;continue;}
     else
     break;
     if(L==0) {num3.Exponenet=120;return false;}//除数为零

short *Dividend,*Divisor[10];//被除数,除数
Dividend=new short[L+1];
for(i=0;i<10;i++) Divisor=new short[L+1];
Vector vect;
for(i=0;i<L+1;i++) Divisor[0]=0;
AddSub8 add;//8位的BCD加法器

     for(i=1;i<=9;i++)//计算除数的1-9倍,以便于查表计算结果
     {
     add.CLC();
     for(j=L-1;j>=0;j--)
         Divisor[j+1]=add.ADC8(num2.Mantissa[j],Divisor[i-1][j+1]);
        
     Divisor[0]=add.ADC8(0,Divisor[i-1][0]);
     }
//被除数初始化
 
            Dividend[0]=0;
            vect.Equ(Dividend+1,num1.Mantissa,L);
 

short Result[CHM+1],m;
 
         for(i=0;i<CHM+1;i++) //修改i的上限值可以动态调节精度
         {
             for(m=0;m<2;m++)//BCD的高低字节
             {
                for(j=9;j>0;j--)
                {
                 add.SEC();//进位标志置1
                 for(k=L;k>=0;k--)
                   add.SBC8(Dividend[k],Divisor[j][k]);
                 if(add.c==true)  break;
                }
            if(j!=0)
                  for(k=L;k>=0;k--)
                     Dividend[k]=add.SBC8(Dividend[k],Divisor[j][k]);//更新被除数
              if(m==0)   Result=j*10;//保存结果
              else
                  Result+=j;
               vect.BCDRightShift(Dividend,L+1);//被除数左移一位
              if(L+i<CHM)
              {
              if(m==0) Dividend[L]+=num1.Mantissa[L+i]/10;
              else
              Dividend[L]+=num1.Mantissa[L+i]%10;              
              }
             }
         }
  
  if(Result[0]>9) vect.Equ(num3.Mantissa,Result,CHM);
  else
  {
  num3.Exponenet--;
 // vect.BCDLeftShift(Result+1,num3.Mantissa,CHM);//左移一次可以节约时间:有一个问题:Mantissa溢出
 // num3.Mantissa[0]+=Result[0]*10;

  vect.BCDRightShift(Result,CHM+1);
  vect.Equ(num3.Mantissa,Result,CHM);
  }

delete []Dividend;
for(i=0;i<10;i++) delete []Divisor;
return true;
 }
//虽然底层的程序都做好了,但是有一点:我做了两个模块:
 //左移、右移;其实如果我考虑得周密一点的话,左移右移是一回事

 
void Cchebft(double a,double b,double *c,int N,int math)
{
int k,j;
double  fac,bpa,bma,*f,y,sum;
f=new double[N];
for(j=0;j<N;j++) f[j]=0;
bma=0.5*(b-a);
bpa=0.5*(b+a);

  for(k=0;k<N;k++)
  {
  y=cos(PI*(k+0.5)/N);
  switch(math)
  {
  case 1:
      f[k]=pow(10,y*bma+bpa); break;
  case 2:
      f[k]=atan(y*bma+bpa)/(y*bma+bpa);break;
  case 3:
       f[k]=sin(y*bma+bpa)/(y*bma+bpa);break;
  case 4:
       f[k]=log10(y*bma+bpa+1);break;
  case 5:
       f[k]=acos(y*bma+bpa) ;break;       
  case 6:
       f[k]=log(y*bma+bpa);break;
  case 7:
       f[k]=log10(y*bma+bpa)/(y*bma+bpa-1);break;
  case 8:
       f[k]=asin(y*bma+bpa)/(y*bma+bpa);break;       
  case 9:
       f[k]=acos(y*bma+bpa);break;    

  }
  }
  fac=2.0/N;
  for(j=0;j<N;j++) 
  {
    sum=0;
  for(k=0;k<N;k++)
  sum+=f[k]*cos(PI*j*(k+0.5)/N);
  c[j]=fac*sum;
  }
}

 void Cchebpc(double *c,double *q,int N)
 {
  int k,j;
  double  sv,*Q1;
  Q1=new double [N];
  for(j=0;j<N;j++)
  {q[j]=0;Q1[j]=0;}
   
  q[0]=c[N-1];
  
 for(j=N-2;j>=1;j--)
 {
  for(k=N-j;k>=1;k--)
  {
  sv=q[k];
  q[k]=2.0*q[k-1]-Q1[k];
  Q1[k]=sv;
  }
  sv=q[0];
  q[0]=-Q1[0]+c[j];
  Q1[0]=sv;
 }
 for(j=N-1;j>=1;j--) q[j]=q[j-1]-Q1[j];
 q[0]=-Q1[0]+0.5*c[0];
 delete []Q1;
 }

void Cpcshift(double a,double b,double *coeff,int N)
{
int k,j;
double  fac,cnst;
cnst=2.0/(b-a);
fac=cnst;
//for(j=0;j<N;j++) coeff[j]=1;

for(j=1;j<N;j++)
 {
 coeff[j]*=fac;
 fac *=cnst;
 }
cnst=0.5*(a+b);
for(j=0;j<=N-2;j++)
  for(k=N-2;k>=j;k--)
  coeff[k]-=cnst*coeff[k+1];
}

void PrintfVect(double *c,int n)
{
for(int i=0;i<n;i++) printf("\n%.12e",c);
}
 double cddpoly(double x,double *c,int n)
 {
 double p=0;
 p=c[n-1];
 for(int j=n-2;j>=0;j--)
 p=p*x+c[j]; 
 return p;
 }
FP  poly(FP x,FP *c,int n)
 {
 FP p;
 Vector vect;
 vect.ClrFP(p);
 p=c[n-1];
 for(int j=n-2;j>=0;j--)
 { p=p*x+c[j];
 }
// printf("\n%.11e\n",0.11111111111111111111);
 return p;
}
 
FP chebyshev(double a,double b,int N,int n,FP x)
{
 double c[40],q[40];
 Cchebft(a,b,c,N,n);
 Cchebpc(c,q,N);
 Cpcshift(a,b,q,N);
 Vector vect;
 FP fp[40];
 for(int i=0;i<N;i++)
     vect.Double2FP(q,fp);
 return poly(x,fp,N);
}

 FP pow10(FP x)
 {
  FP p; 
  Vector vect;
  vect.ClrFP(p);
  short k=0;
  //判断是否溢出:1,0,<0(指数存在的情况)
  if(x.Exponenet>1 && x.Sign==false) {p.Mantissa[0]=10;p.Exponenet=100;return p;}
  if(x.Exponenet>1 && x.Sign==true)  {p.Mantissa[0]=10;p.Exponenet=-100;return p;}
           
         if(x.Exponenet==1) 
          {
              k=x.Mantissa[0];
              x.Mantissa[0]=0;
          }
          if(x.Exponenet==0)
          {
              k=x.Mantissa[0]/10;
              x.Mantissa[0]=x.Mantissa[0]%10;
          }
  vect.Norm(x);//进行归一化处理
    if(x.Exponenet==0) //是否是整数
    {
     p.Mantissa[0]=10;
     if(x.Sign==true)       p.Exponenet=k*(-1);
     else
         p.Exponenet=k;
     return p;
    }
  if(x.Sign==true) { p.Mantissa[0]=10;x=p+x;k=k*(-1)-1;}
  double a,b;
  int N=12;
   if(x.Mantissa[0]/10>5 && x.Exponenet==-1)     {a=0.5;b=1;}  else     {a=0;b=0.5;} 
  // a=0;
  // if(x.Exponenet==-1) a=x.Mantissa[0]/10;
  // a=a*0.1;
  // b=a+0.1;
   p=chebyshev(a,b,N,1,x);
   p.Exponenet=k;
  return p;
 }

 FP  arctan(FP x)
 {
 if(x.Mantissa[0]==0) return x;
 FP p,pi,one;
 bool flag1=false,flag2=false,flag3=false;;
 Vector vect;
 vect.ClrFP(one);
 one.Mantissa[0]=10;//置一
 vect.Double2FP(PI*0.5,pi);

 if(x.Exponenet>=0) {x=one/x;flag2=true;}
 if(x.Sign==true) {x.Sign=false;flag1=true;}
 
 double a,b;
 int N=12,u;
 if(x.Exponenet<-1)  u=0;
 else
 u=x.Mantissa[0]/25;//不对
 if(x.Exponenet==0) u=3;//x=1:可以直接赋值退出子程序
 a=0.25*u;
 b=a+0.25;
 
   p=chebyshev(a,b,N,2,x);//x.exponenet<-2进行修正
    
  if(x.Exponenet<-2) 
      flag3=true;
  p=p*x;

  if(flag2==true && flag1==true) p=p-pi;
  else 
      if(flag2==true && flag1==false) p=pi-p;
  else if(flag1==true) p.Sign=true;
 FP w;
 if(flag3==true)//进行修正:对末位有效数字修正
 {
 vect.ClrFP(w);
 w.Mantissa[0]=10;
 w.Sign=p.Sign;
 w.Exponenet=p.Exponenet-CHM*2+1;
 p=p+w;
 }
  return p;
 }

  FP Sin(FP x)//-pi/2----pi/2
 {
 FP p,pi4;
 bool flag=false;
 if(x.Sign==true) {x.Sign=false;flag=true;}//绝对值
 double a,b;
 int N=12;
 a=0;b=PI/4;
 Vector vect;
 vect.Double2FP(PI/4.00,pi4);
 pi4=x-pi4;
 if(pi4.Sign==false) {a=PI/4;b=PI/2;}

 p=chebyshev(a,b,N,3,x);
 if(flag==true) p.Sign=true;
 return p*x;
 }

 FP Cos(FP x)//0---pi
 {
 FP pi2;
 Vector vect;
 vect.Double2FP(PI/2,pi2);
 x=pi2-x;
 return Sin(x);
 }

 FP Tan(FP x)
 {
  return Sin(x)/Cos(x);//Cos!=0   
 }

 FP Sqrt(FP x)
 {
 FP p,p1;
 double k=0.5;
 Vector vect;
 vect.Double2FP(k,p1);
 vect.ClrFP(p);
 if(x.Mantissa[0]==0) return p;
 p.Mantissa[0]=10;p.Exponenet=x.Exponenet/2;
 for(int i=0;i<15;i++)//迭代法:这里应该不断判断两次的结果是否已经收敛
 {
   p=p+x/p;
   p=p*p1;
 }
 return p;
 }

   FP arcsin(FP x)
   {
    FP p,p1;
    Vector vect;
    bool flag=false,flag1=false;
    if(x.Sign==true) {flag1=true;x.Sign=false;}
    p=x;
    if(x.Exponenet>=0) {vect.ClrFP(p);p.Exponenet=110;return p;}
       if(x.Exponenet==-1 && x.Mantissa[0]>50) 
       {flag=true;
        vect.ClrFP(p1);
        vect.Double2FP(0.5,p1);
        x=Sqrt((p1-p1*x));
       }
 
 double a=0,b=0.25;
 int N=12;
 if(x.Exponenet==-1 && x.Mantissa[0]>25) {a=0.25;a=0.5;}
   p=chebyshev(a,b,N,8,x)*x;
     if(flag==true)
     {
     vect.ClrFP(p1);p1.Mantissa[0]=20;
     p=p*p1;//p=p*2
     vect.Double2FP(PI/2,p1);
     p=p1-p;
     }

     if(flag1==true) p.Sign=true;
   return p;
     }
   
   FP arccos(FP x)
   {
    FP p,p1;
    Vector vect;
    bool flag=false,flag1=false;
    if(x.Sign==true) {x.Sign=false;flag1=true;}

    p=x;
    if(x.Exponenet>=0 && x.Mantissa[0]!=0) {vect.ClrFP(p);p.Exponenet=110;return p;}//这里判断不是很准确:x=1;x=-1;x>1;x<1
       if(x.Exponenet==-1 && x.Mantissa[0]>50)
       {flag=true;
        vect.ClrFP(p1);
        vect.Double2FP(0.5,p1);
        x=Sqrt((p1-p1*x));
       }
 double  a=0,b=0.25;
 int N=12;
  if(x.Exponenet==-1 && x.Mantissa[0]>25) {a=0.25;a=0.5;}
    p=chebyshev(a,b,N,5,x);
     if(flag==true)
     {
     vect.ClrFP(p1);p1.Mantissa[0]=20;
     p=p*p1;//p=p*2
     vect.Double2FP(PI,p1);
     p=p1-p;
     }
     if(flag1==true) 
     {vect.Double2FP(PI,p1);p=p1-p;}
   return p;
   }
 FP exp(FP x)
 {
  FP p;
 double log10E=0.4342944819032518;//x=0.5有点问题
 FP q;
 Vector vect;
 vect.Double2FP(log10E,q);
 x=x*q;
 p=pow10(x);
 return p;
 }
 FP Log10(FP x)//x必须为正:此程序没有判断
 {
     //log10(a*10^b)=log10(a)+b=log10(a*c)-log10(c)
Vector vect;
FP  One,x1;
vect.ClrFP(One);One.Mantissa[0]=10;
x1=x-One;
 //x1趋于零时,C语言计算的结果不一定是准确的
if(x1.Exponenet<-5)     
      return x1*(vect.Double2FP(6)+x1)/(vect.Double2FP(6.0)+vect.Double2FP(4.0)*x1)*vect.Double2FP(0.4342944819032518);
if(x1.Exponenet<-2) 
      return (((x1+vect.Double2FP(21))*x1+vect.Double2FP(30))*x1)/((vect.Double2FP(9)*x1+vect.Double2FP(36))*x1+vect.Double2FP(30))*vect.Double2FP(0.4342944819032518);
if(x.Exponenet==0 && x.Mantissa[0]<15) //1<=x<=1.5
                              return chebyshev(1.0,1.50,12,7,x)*(x-One);
if(x.Exponenet==-1 && x.Mantissa[0]>=80)//  0.8<=x<1
                              return chebyshev(0.8,1,12,7,x)*(x-One);

 FP p,p1;
 double c;
 //vect.PrintfFp(x);
 if(x.Mantissa[0]/10>=5) c=1.0;
 else
    // c=6.0-x.Mantissa[0]/10;
 switch(x.Mantissa[0]/10)
 {
     case 1:c=5.0;break;
     case 2:c=3.0;break;
     case 3:c=2.0;break;
     case 4: c=2.0;break;//???????
 }
 
 vect.Double2FP((double)x.Exponenet,p1);
 vect.Double2FP(log10(c),p); 
 
 p=p1-p;
 vect.Double2FP(c,p1);
 x.Exponenet=0;
 x=x*p1;
  double a,b;
  int N=8;
//  if(x.Mantissa[0]/10==5) N=10;

   //if(x.Mantissa[0]>75)        {a=7.5;b=10;}  else       {a=5;b=7.5;} 
//    a=x.Mantissa[0]/10;b=a+1;
a=x.Mantissa[0]/10+((x.Mantissa[0]%10*10+x.Mantissa[1]/10)/25)*0.25;
b=a+0.25;
N=7;
   p=chebyshev(a,b,N,4,x)+p;
  return p;
 }

FP Ln(FP x)
{
FP p;
double p4=0.4342944819032518;
Vector vect;
vect.Double2FP(1/p4,p); 
return Log10(x)*p;
}

FP Pow(FP x,FP y)
{
FP p;
p=Log10(x);
//p.Mantissa[CHM-1]=0;
return pow10(y*p);//x的y次方
}

FP ain(FP in)
{
 FileFP s1("c:\\COEF.txt");
 double a,b,c[100],e=2.71828182845904;
 double q[20]={
    3.979400086720374e-001,
    1.737177927611043e-001,
   -3.474355855214964e-002,
    9.264948969143740e-003,
   -2.779484694009623e-003,
    8.894344021844690e-004,
   -2.964780808962932e-004,
    1.016592169579166e-004,
   -3.558111680579244e-005,
    1.258718493447536e-005,
   -4.530049685422902e-006,
    1.851579095212842e-006,
   -6.806462801319921e-007,0},q1[20]={0};

 int N=13;
  a=0;b=0.3;
  FP nine;
  Vector vect;
  vect.ClrFP(nine);
  nine.Exponenet=0;
  nine.Mantissa[0]=25;
  nine.Mantissa[1]=00;
  
 //Cchebft(a,b,c,N,7);
 //Cchebpc(c,q,N);
 //Cpcshift(a,b,q,N);
 double s=6;
 FP input,fp[20];

 vect.Double2FP(s,input);
 for(int i=0;i<N;i++)    {  vect.Double2FP(q,fp);}
 //for(i=N-1;i>=0;i--) s1.SaveCoAsm(fp);
 s1.SaveCoAsm(vect.Double2FP(log(10)*6));
 s1.SaveCoAsm(vect.Double2FP(log(10)*4));

 exit(0);
//ENTER;
 //vect.PrintfFp(input);
 FP one;vect.ClrFP(one);one.Mantissa[0]=10;
 //ENTER;
 //vect.PrintfFp(poly(in,fp,N));
 //printf("\n\n%.15e  %.15e   %.15e   \n",s,cddpoly(s,q,N),log10(s));
in=in-nine;
return poly(in,fp,N);
}

void CheckDesign()

int i;
double x1,y1,e=2.71828182845904;
FP x2,y2;
Vector vect; 
while(1)
{
system("cls");

 printf("a:sin(x)    b:cos(x)    c:tan(x)    d:log(x)    e:ln(x)\n");
 printf("f:asin(x)   g:acos(x)   h:atan(x)   i:10^x      j:e^x\n");
 printf("k:x^y       l:sqrt(x)   x:Exit\n\n\n\n\n");

 printf("\nChoice:");
 i=getchar();
 if(i=='x') return;

 x1=0;y1=0  ;
 
      printf("x=");scanf("%lf",&x1);vect.Double2FP(x1,x2);

      x1=vect.FP2Double(x2);
      if(i=='k') 
      {
          printf("y=");scanf("%lf",&y1);vect.Double2FP(y1,y2);
          printf("x=%.15e   ",x1);vect.PrintfFp(x2);
          printf("\ny=%.15e   ",y1);vect.PrintfFp(y2);
      }
      else
      {
          printf("x=%.15e   ",x1);vect.PrintfFp(x2);

      }

 switch(i)
        {
        case 'a':printf("\n%.15e\n",sin(x1));vect.PrintfFp(Sin(x2));break;
        case 'b':printf("\n%.15e\n",cos(x1));vect.PrintfFp(Cos(x2));break;
        case 'c':printf("\n%.15e\n",tan(x1));vect.PrintfFp(Tan(x2));break;
        case 'd':printf("\n%.15e\n",log10(x1));vect.PrintfFp(Log10(x2));break;
        case 'e':printf("\n%.15e\n",log(x1));vect.PrintfFp(Ln(x2));break;
        case 'f':printf("\n%.15e\n",asin(x1));vect.PrintfFp(arcsin(x2));break;
        case 'g':printf("\n%.15e\n",acos(x1));vect.PrintfFp(arccos(x2));break;
        case 'h':printf("\n%.15e\n",atan(x1));vect.PrintfFp(arctan(x2));break;
        case 'i':printf("\n%.15e\n",pow(10,x1));vect.PrintfFp(pow10(x2));break;
        case 'j':printf("\n%.15e\n",pow(e,x1));vect.PrintfFp(exp(x2));break;
        case 'k':printf("\n%.15e\n",pow(x1,y1));vect.PrintfFp(Pow(x2,y2));break;
        case 'l':printf("\n%.15e\n",sqrt(x1));vect.PrintfFp(Sqrt(x2));break;
         }
getch();getchar();getchar();getch();
}
}
void main()
{
Vector vect;
CheckDesign();
//return;
int num=9999;
double step=0,begin=2,end=3,x1;
FileFP s1("c:\\d.txt");
FileFP s2("c:\\f.txt");
FileFP s("c:\\input.txt"); 
FP x2;
step=(end-begin)/num; 
   for(int i=0;i<num;i++)
    {
    x1=begin+i*step;     x2=vect.Double2FP(x1); 
    x1=vect.FP2Double(x2);   
    s.SaveFP(x2);
//    s1.SaveDouble(pow(10,x1));
    s1.SaveDouble(log10(x1));
    s2.SaveFP(ain(x2));
    }
}

相关帖子

沙发
McuPlayer| | 2008-7-21 22:32 | 只看该作者

契比雪夫多项式,国内一般是这个翻译

如果你做函数计算器,用它算是对路了。
比泰勒展开式收敛速度快,同样的精度大大节约计算时间

当初我一个同事,现在已经移民了,电子字典的计算器,也是6502的core

使用特权

评论回复
板凳
edgesoft| | 2008-7-26 09:57 | 只看该作者

不错。。。。。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

9

主题

9

帖子

1

粉丝