基于8位加法的初等函数计算器设计
基于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 用于计算多项式的系数.
笔者把这几年收集的关于国人对计算器的研究文章”计算器的计算误差与计算精确度的研讨”,”怎样用没有开立方根按键的计算器开立方根和高次方根”等等文件及计算器源程序的工程文件放置网站: ,如果您感兴趣,请去下载。如有疑问也可以来电,我们一起讨论: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[i]=data[i];}
// 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[i]=fp.Mantissa[i];
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[i]==0) {printf("00");continue;}
if(data[i] <10) printf("0");
printf("%d",data[i]);
}
}
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[i]=data2[i];}
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[i]=0;}
void ClrShort(short *data,int n){for(int i=0;i <n;i++) data[i]=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[i]);
}
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[i]=(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[i]/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[i]=(num[i]%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[i]=num[i]/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[i]/10;//在汇编程序的实现: &0xF0
num[2*i+1]=num1[i]%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[i]/10;
num2[i]=b*10+a;
b=num1[i]%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[i] <=9) printf("0%d",data.Mantissa[i]);
else
printf("%d",data.Mantissa[i]);
}
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[i] <=9) fprintf(fp,"0%d",x.Mantissa[i]);
else
fprintf(fp,"%d",x.Mantissa[i]);
}
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[i] <=9) fprintf(fp,",$0%d",x.Mantissa[i]);
else
fprintf(fp,",$%d",x.Mantissa[i]);
}
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[i]==num2.Mantissa[i]) continue;
if(num1.Mantissa[i]> num2.Mantissa[i]) 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[i],0);
else
result[i+1]=add.ADC8(num3.Mantissa[i],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[i]=add.SBC8(0,num[i-shift]); //有几步是多余的:
//至少不应该保存起来(没有多余,有可能前面几位为零)
//即使这种情况没有,但可以为后续的开发利用
else if(i <shift) result[i]=add.SBC8(num3.Mantissa[i],0);
else
result[i]=add.SBC8(num3.Mantissa[i],num[i-shift]);
for(i=0;i <2*CHM;i++)//因为有可能被减数与减数的前几位是相等的
if(result[i]==0) {num3.Exponenet-=2;continue;}
else
break;
if(i> 2*CHM-1) {vect.ClrFP(num3);return;}//如果结果等于零,返回(这一步可以在函数开始处进行判断)
if(result[i]> 9) vect.Equ(num3.Mantissa,result+i,CHM);
else
{
// vect.BCDLeftShift(result+i+1,num3.Mantissa,CHM-1);//???????????
// num3.Mantissa[0]+=result[i]*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[i][0]:进位标志
for(i=1;i <10;i++) Rnum1[i][0]=0;
for(i=0;i <=CHM;i++) Rnum1[0][i]=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[i][j+1]=add.ADC8(num1.Mantissa[j],Rnum1[i-1][j+1]);
Rnum1[i][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[i]=add.ADC8(Result1[i],Result3[i]);
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[i]==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[i]=new short[L+1];
Vector vect;
for(i=0;i <L+1;i++) Divisor[0][i]=0;
AddSub8 add;//8位的BCD加法器
for(i=1;i <=9;i++)//计算除数的1-9倍,以便于查表计算结果
{
add.CLC();
for(j=L-1;j> =0;j--)
Divisor[i][j+1]=add.ADC8(num2.Mantissa[j],Divisor[i-1][j+1]);
Divisor[i][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[i]=j*10;//保存结果
else
Result[i]+=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[i];
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[i]);
}
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[i],fp[i]);
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[i],fp[i]);}
//for(i=N-1;i> =0;i--) s1.SaveCoAsm(fp[i]);
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));
}
}
发表时间:2008年7月20日16:55:38