- 论坛徽章:
- 0
|
回复 10楼 hqxyn 的帖子
decimal.cpp
/***************************************************************************
decimal.cpp - description
-------------------
begin : Wed Jan 9 2002
copyright : (C) 2002 by Xian Yining
email : hqxyn@yahoo.com.cn
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <iostream>
#include <string>
#undef __DEBUG__
//#define __DEBUG__
#include "decimal.h"
unsigned int midDigits(const decimal& ,const decimal& ) ;
/***********
* 构造函数 *
***********/
decimal::decimal(const std::string &s,const unsigned int p,const unsigned int d) {
decimal x(s.c_str(),p,d);
sn=x.sn;
val=x.val;
exp=x.exp;
st=x.st;
pre=x.pre;
dec=x.dec;
this->decReg();
if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
decimal::decimal(const char* ci,const unsigned int p,const unsigned int d) {
char c[strlen(ci)+1];
unsigned j=0;
int i;
strcpy(c,ci);
#ifdef __DEBUG__
std::cout<<"char*:c="<<c<<"\n";
#endif
//消前后空格
for ( i=strlen(c)-1;i>=0;--i ) {
if ( c!=' ' ) break;
c='\0';
}
for ( j=0;j<strlen(c); ) {
if (c[j]!=' ') break;
++j;
}
//判符号
if ( c[j]=='+' ) {sn=PLUS;++j;}
else {
if ( c[j]=='-' ) {sn=MINUS;++j;}
else sn=PLUS;
}
//去前导‘0’
while (j<strlen(c+j)) {if (c[j]!='0') break;++j;}
#ifdef __DEBUG__
std::cout<<"char*:j="<<c+j<<"\n";
#endif
char *fp=c+j; //尾数数组指针
#ifdef __DEBUG__
std::cout<<"char*:fp="<<fp<<"\n";
#endif
char *ep=NULL; //指数数组指针
char *dp=NULL; //小数数组指针
st=OK;
for ( j=0;j<strlen(fp) && fp[j]!='\0'; ) { //取尾数整数部分
switch(fp[j]) {
case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':++j;break;
case '.':dp=fp+j+1;fp[j]='\0';break;
case 'E':case 'e':ep=fp+j+1;fp[j]='\0';break;
default:st=NOINIT;fp[j]='\0';
}
}
#ifdef __DEBUG__
std::cout<<"char*:fp2="<<fp<<"\n";
#endif
if ( dp!=NULL ) { //取尾数小数部分
for (j=0;j<strlen(dp) && dp[j]!='\0'{
switch(dp[j]) {
case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':++j;break;
case 'E':case 'e':ep=dp+j+1;dp[j]='\0';break;
default:st=NOINIT;dp[j]='\0';
}
}
}
#ifdef __DEBUG__
std::cout<<"char*:fp3="<<ep<<"\n";
#endif
if ( ep!=NULL ) {
switch(ep[0]) { //检查指数首字符
case '+':case '-':
case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':break;
default:st=NOINIT;
}
}
#ifdef __DEBUG__
std::cout<<"char*:fp4="<<fp<<"\n";
#endif
if ( ep!=NULL ) { //取指数部分
for (j=1;j<strlen(ep){
switch(ep[j]) {
case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':++j;break;
default:st=NOINIT;
}
#ifdef __DEBUG__
std::cout<<"char*:fp5c="<<fp[j]<<"\n";
#endif
}
}
#ifdef __DEBUG__
std::cout<<"char*:fp5="<<fp<<"\n";
#endif
if (fp!=NULL ) {
val=fp;
}
exp=0;
if (dp!=NULL) {
val.append(dp);
exp-=strlen(dp);
}
if (ep!=NULL) {
#ifdef __DEBUG__
std::cout<<"char*:*ep="<<atoi(ep)<<"\n";
#endif
exp+=atoi(ep);
}
dec=d;
pre=p;
this->decReg();
if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
decimal::decimal(const int v,const unsigned int p,const unsigned int d) {
char c[std::numeric_limits<int>::digits10+2];
sprintf(c,"%i",v);
#ifdef __DEBUG__
std::cout<<"int:c="<<c<<"\n";
#endif
if (c[0]=='-') {sn=MINUS;val=c+1;}
else {sn=PLUS;val=c;}
pre=p;
dec=d;
exp=0;
st=OK;
this->decReg();
if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
decimal::decimal(const unsigned int v,const unsigned int p,const unsigned int d) {
char c[std::numeric_limits<unsigned int>::digits10+2];
sprintf(c,"%u",v);
#ifdef __DEBUG__
std::cout<<"Uint:c="<<c<<"\n";
#endif
sn=PLUS;
val=c;
pre=p;
dec=d;
exp=0;
st=OK;
this->decReg();
if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
decimal::decimal(const long v,const unsigned int p,const unsigned int d) {
char c[std::numeric_limits<long>::digits10+2];
sprintf(c,"%li",v);
#ifdef __DEBUG__
std::cout<<"long:c="<<c<<"\n";
#endif
if (c[0]=='-') {sn=MINUS;val=c+1;}
else {sn=PLUS;val=c;}
pre=p;
dec=d;
exp=0;
st=OK;
this->decReg();
if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
decimal::decimal(const long long v,const unsigned int p,const unsigned int d) {
char c[std::numeric_limits<long long>::digits10+2];
sprintf(c,"%lli",v);
#ifdef __DEBUG__
std::cout<<"long long:c="<<c<<"\n";
#endif
if (c[0]=='-') {sn=MINUS;val=c+1;}
else {sn=PLUS;val=c;}
pre=p;
dec=d;
exp=0;
st=OK;
this->decReg();
if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
decimal::decimal(const unsigned long v,const unsigned int p,const unsigned int d) {
char c[std::numeric_limits<unsigned int>::digits10+2];
sprintf(c,"%lu",v);
#ifdef __DEBUG__
std::cout<<"Ulong:c="<<c<<"\n";
#endif
val=c;
sn=PLUS;
pre=p;
dec=d;
exp=0;
st=OK;
this->decReg();
if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
decimal::decimal(const unsigned long long v,const unsigned int p,const unsigned int d) {
char c[std::numeric_limits<unsigned long long>::digits10+2];
sprintf(c,"%llu",v);
#ifdef __DEBUG__
std::cout<<"UUlong:c="<<c<<"\n";
#endif
val=c;
sn=PLUS;
pre=p;
dec=d;
exp=0;
st=OK;
this->decReg();
if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
decimal::decimal(const double v,const unsigned int p,const unsigned int d) {
char c[std::numeric_limits<double>::digits10+std::numeric_limits<int>::digits10+1];
char t[10],s[15]="%.";
sprintf(t,"%u",std::numeric_limits<double>::digits10);
strcat(s,t);
strcat(s,"E"
sprintf(c,s,v);
#ifdef __DEBUG__
std::cout<<"double:c="<<c<<"\n";
#endif
char *tE=strchr(c,'E');
if ( tE!=NULL ) { //取指数
exp=atoi(tE+1);
*tE='\0';
}
else exp=0;
// for (unsigned u=strlen(c)-1;u>0 && c=='0';c='\0',u--) {}
char *tD=strchr(c,'.');
if ( tD!=NULL ) { //将尾数变为整数,并相应调整指数
char *px=tD;
for (;*(px+1)!='\0';*px = *(px+1),--exp,++px) {}
*px='\0';
}
if (c[0]=='-') {sn=MINUS;val=c+1;}
else {sn=PLUS;val=c;}
pre=p;
dec=d;
st=OK;
this->decReg();
if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
decimal::decimal(const long double v,const unsigned int p,const unsigned int d) {
char c[std::numeric_limits<long double>::digits10+std::numeric_limits<int>::digits10+1];
char t[10],s[15]="%.";
sprintf(t,"%u",std::numeric_limits<long double>::digits10);
strcat(s,t);
strcat(s,"LE"
sprintf(c,s,v);
#ifdef __DEBUG__
std::cout<<"long double:c="<<c<<"\n";
#endif
char *tE=strchr(c,'E');
if ( tE!=NULL ) { //取指数
exp=atoi(tE+1);
*tE='\0';
}
else exp=0;
// for (unsigned u=strlen(c)-1;u>0 && c=='0';c='\0',u--) {}
char *tD=strchr(c,'.');
if ( tD!=NULL ) { //将尾数变为整数,并相应调整指数
char *px=tD;
for (;*(px+1)!='\0';*px = *(px+1),--exp,++px) {}
*px='\0';
}
if (c[0]=='-') {sn=MINUS;val=c+1;}
else {sn=PLUS;val=c;}
pre=p;
dec=d;
st=OK;
this->decReg();
if (val.size()>p) {st=OVERDIGITS;/*throw*/ ;}
}
/************
* 赋值操作符 *
************/
decimal& decimal:perator=(const decimal& d) {
//精度定义(pre)和保留小数位数(dec)在变量定义时确定,?新值时不变。
#ifdef __DEBUG__
std::cout<<"in decimal[=]:"<<*this<<";;"<<d<<"\n";
#endif
sn=d.sn;
val=d.val;
exp=d.exp;
if (val.size()>pre) {st=OVERDIGITS;/*throw*/ ;}
else st=d.st;
return *this;
}
/**************
* 算术运算符 *
**************/
decimal& decimal:perator +=(const decimal& d2) {
if (sn==d2.sn) {
valAdd(val,exp,d2.val,d2.exp);
}
else {
if (valCmp(val,exp,d2.val,d2.exp)<0) {
std::string t=d2.val;
int et=d2.exp;
valSub(t,et,val,exp);val=t;exp=et;sn=d2.sn;
}
else valSub(val,exp,d2.val,d2.exp);
}
return this->decReg();
}
decimal& decimal:perator -=(const decimal& d2) {
if (sn==d2.sn) {
if (valCmp(val,exp,d2.val,d2.exp)<0) {
std::string t=d2.val;
int et=d2.exp;
valSub(t,et,val,exp);val=t;exp=et;
sn=(d2.sn==PLUS)?MINUSLUS;
}
else valSub(val,exp,d2.val,d2.exp);
}
else {
valAdd(val,exp,d2.val,d2.exp);
}
return this->decReg();
}
decimal& decimal:perator *=(const decimal& d2) {
sn=(sn==d2.sn)?PLUS:MINUS;
exp+=d2.exp;
valMult(val,d2.val);
return this->decReg();
}
decimal& decimal:perator /=(const decimal& d2) {
if (d2.zero()) {st=UPFLOW;return *this;}
sn=(sn==d2.sn)?PLUS:MINUS;
int te1,te2;
te1=exp+val.size();te2=d2.exp+d2.val.size();
te1-=te2;
valDiv(val,d2.val,pre+1);
exp=-val.size()+1+te1;
return this->decReg();
}
decimal operator +(const decimal& d1,const decimal& d2) {
decimal d(0,midDigits(d1,d2),(d1.getDec()>=d2.getDec())?d1.getDec():d2.getDec());
d=d1;
#ifdef __DEBUG__
std::cout<<"[+]:d="<<d<<"d.pre="<<d.getPre()<<"\n";
#endif
return d+=d2;
}
decimal operator -(const decimal& d1,const decimal& d2) {
decimal d(0,midDigits(d1,d2),(d1.getDec()>=d2.getDec())?d1.getDec():d2.getDec());
d=d1;
#ifdef __DEBUG__
std::cout<<"[-]:d="<<d<<"d.pre="<<d.getPre()<<"\n";
#endif
return d-=d2;
}
decimal operator *(const decimal& d1,const decimal& d2) {
decimal d(0,d1.getPre()+d2.getPre(),d1.getDec()+d2.getDec());
d=d1;
#ifdef __DEBUG__
std::cout<<":d="<<d<<"d.pre="<<d.getPre()<<"\n";
#endif
return d*=d2;
}
decimal operator /(const decimal& d1,const decimal& d2) {
decimal d(0,d1.getPre()+d2.getPre(),d1.getDec()+d2.getDec());
d=d1;
#ifdef __DEBUG__
std::cout<<"[/]:d="<<d<<"d.pre="<<d.getPre()<<"\n";
#endif
return d/=d2;
}
/**********************
* 比较运算符 *
*********************/
bool decimal::le(const decimal& d2) const {
if (sn==decimal:LUS && d2.sn==decimal::MINUS) return false;
if (sn==decimal::MINUS && d2.sn==decimal:LUS) return true;
int r=decimal::valCmp(val,exp,d2.val,d2.exp);
if (sn==decimal:LUS && r<0) return true;
if (sn==decimal::MINUS && r>0) return true;
return false;
}
bool decimal::eq(const decimal& d2) const {
if ((sn==decimal::MINUS && d2.sn==decimal:LUS) || (sn==decimal:LUS && d2.sn==decimal::MINUS)) return false;
int r=decimal::valCmp(val,exp,d2.val,d2.exp);
if (r==0) return true;
return false;
}
bool decimal::gt(const decimal& d2) const {
if (this->sn==decimal::MINUS && d2.sn==decimal:LUS) return false;
if (this->sn==decimal:LUS && d2.sn==decimal::MINUS) return true;
int r=decimal::valCmp(val,exp,d2.val,d2.exp);
if (this->sn==decimal:LUS && r>0) return true;
if (this->sn==decimal::MINUS && r<0) return true;
return false;
}
bool operator <(const decimal& d1,const decimal& d2) {
return d1.le(d2);
}
bool operator ==(const decimal& d1,const decimal& d2) {
return d1.eq(d2);
}
bool operator >(const decimal& d1,const decimal& d2) {
return d1.gt(d2);
}
bool operator <=(const decimal& d1,const decimal& d2) {
return !(d1>d2);
}
bool operator >=(const decimal& d1,const decimal& d2) {
return !(d1<d2);
}
bool operator !=(const decimal& d1,const decimal& d2) {
return !(d1==d2);
}
/*****************
* 输入输出流 *
****************/
std:stream &operator <<(std:stream &os,const decimal& d) {
#ifdef __DEBUG__
os<<"ok="<<d.ok();
os<<",sign="<<((d.getSn()==decimal:LUS)?'+'d.getSn()==decimal::MINUS)?'-':'?'));
os<<",val="<<d.getVal();
os<<",exp="<<d.getExp();
os<<",pre="<<d.getPre();
os<<",dec="<<d.getDec();
os<<"\n";
#endif
os<<d.toString(0,d.getDec());
return os;
}
/*
std::istream& operator >>(std::istream& is,decimal& d) {
std::string s;
std::cin>>s;
decimal dx(s.c_str());
d=dx;
return is;
}
*/
/**************
* 杂函数 *
**************/
std::string decimal::toEString(const unsigned len) const {
std::string s="";
s.append((sn==decimal::MINUS)?"-"sn==decimal::PLUS)?" ":"?");
s.append(val);
s.append("E"
char c[50];
sprintf(c,"%i",exp);
s.append(c);
if (len != 0 && len<s.size()) s.assign(len,'*');
return s;
}
std::string decimal::toShortStr() const{
std::string s=toString();
if (s.find('.')==std::string::npos) return s;
int c=0;
for (uint u=s.length()-1;u>0;--u){
if (s=='0') ++c;
else break;
}
if (s[s.length()-1-c]=='.') ++c;
s=s.substr(0,s.length()-c);
return s;
}
std::string decimal::toString() const{
return toString(0,getDec());
}
std::string decimal::toString(const unsigned int len,const int de) const {
std::string s="";
if ( ! this->ok() ) return s.append((len==0)?1:len,'*'); //数字无效
s.append((sn==decimal::MINUS)?"-"sn==decimal::PLUS)?" ":"?");
if (exp>=0) { //整数
s.append(val).append(exp,'0').append(1,'.').append(de,'0');
}
else {
if (-exp>=val.size()) { //纯小数
s.append("0.".append(-exp-val.size(),'0').append(val);
}
else {
s.append(val.substr(0,val.size()+exp));
s.append(1,'.');
std::string x=val.substr(val.size()+exp);
s.append(x); //带小数
s.append((de>x.size())?de-x.size():0,'0');
}
}
if (len != 0 && len<s.size()) s.assign(len,'*');
return s;
}
decimal& decimal::round() {
return round(dec);
}
decimal& decimal::round(int r) {
if (r<-exp) { //末位属于舍入位
std::string x="5";
int e=-(r+1);
valAdd(val,exp,x,e);
int i=-exp-r;
if ((val.size()-i)<=0) val="0";
else val=val.substr(0,val.size()-i);
exp+=i;
}
return this->decReg();
}
decimal round(const decimal& d,const int dec) {
decimal dx(0,d.getPre(),dec);
dx=d;
dx.round(dec);
return dx;
}
/****************
* 内部子程序 *
****************/
void decimal::valDiv(std::string& s1,const std::string& s2,const unsigned len) {
std::string s(len,'0'); //商
int ed=s2.size()-s1.size(); //商的小数位数
std::string t1=s1,t2=s2;
int et1; //被除数对位指数,把两数首位对齐
et1=ed;
unsigned int i; //商数循环
int c; //借位
for (i=0;i<len;++i,++et1) {
int j=1;
for (j=1;j<=10;++j) {
if (valCmp(t1,et1,s2,0)<0) {
--j;
break;
}
c=valSub(t1,et1,s2,0) ;
}
s=char(j+4;
}
s1=s;
}
char decimal::valMult(std::string& s1,const std::string& s2) {
std::string s="0";
int es=0;
for (unsigned int i=0;i<s2.size();++i) { //乘数从末尾向前循环
char c1,c2=s2[s2.size()-1-i],m='0';
int j;
std::string pn(s1.size()+1,'0');
for (j=s1.size()-1;j>=0;--j) { //被乘数乘以当前乘数位
c1=s1[j];
m=digitMult(c1,c2,m);
pn[j+1]=c1;
}
es=-i;
pn[0]=m;
valAdd(s,es,pn,0);
}
if (s[0]!='0') s1=s;
else s1=s.substr(1);
return '0';
}
int decimal::valSub(std::string& s1,int &e1,const std::string& s2,const int e2) {
//计算差的位数
//std::cout<<"s1="<<s1<<",e1="<<e1<<",s2"<<s2<<",e2="<<e2<<"\n";
int li1,ld1,li2,ld2,li,ld;
li1= s1.size()+e1;
if ( e1>=0 ) {
li1=s1.size()+e1;
ld1=0;
}
else {
if (li1<0) li1=0;
ld1=-e1;
}
li2=s2.size()+e2;
if ( e2>=0 ) {
ld2=0;
}
else {
if (li2<0) li2=0;
ld2=-e2;
}
li=(li1>=li2)?li1:li2; //整数位数
ld=(ld1>=ld2)?ld1:ld2; //小数位数
std::string s(li+ld,'0');
int qb1, //第一串首位权数
qe1, //第一串末位权数
qb2, //第二串首位权数
qe2; //第二串末位权数
qe1=li-e1-1;qb1=qe1-s1.size()+1;
qe2=li-e2-1;qb2=qe2-s2.size()+1;
char c1,c2;
int m=0,j;
for (j=li+ld-1;j>=0;--j) {
c1=(j>=qb1 && j<=qe1)?s1[j-qb1]:'0';
c2=(j>=qb2 && j<=qe2)?s2[j-qb2]:'0';
m=digitSub(c1,c2,m);
s[j]=c1;
}
s[0]=c1;
s1=s;e1=-ld;
return m;
}
void decimal::valAdd(std::string& s1,int &e1,const std::string& s2,const int e2) {
//计算和的位数
int li1,ld1,li2,ld2,li,ld;
li1= s1.size()+e1;
if ( e1>=0 ) {
li1=s1.size()+e1;
ld1=0;
}
else {
if (li1<0) li1=0;
ld1=-e1;
}
li2=s2.size()+e2;
if ( e2>=0 ) {
ld2=0;
}
else {
if (li2<0) li2=0;
ld2=-e2;
}
li=(li1>=li2)?li1:li2; //整数位数
ld=(ld1>=ld2)?ld1:ld2; //小数位数
std::string s(li+ld+1,'0');
int qb1, //第一串首位权数
qe1, //第一串末位权数
qb2, //第二串首位权数
qe2; //第二串末位权数
qe1=li-e1;qb1=qe1-s1.size()+1;
qe2=li-e2;qb2=qe2-s2.size()+1;
char c1,c2;
int m=0,j;
for (j=li+ld;j>0;--j) {
c1=(j>=qb1 && j<=qe1)?s1[j-qb1]:'0';
c2=(j>=qb2 && j<=qe2)?s2[j-qb2]:'0';
m=digitAdd(c1,c2,m);
s[j]=c1;
}
if (m>0) {s[0]='1';s1=s;}
else s1=s.substr(1);
e1=-ld;
}
int decimal::digitAdd(char& c1,const char c2,const int car) {
int i=c1+c2-48+car;
int c=0;
if (i>57) {i-=10;c=1;}
c1=char(i);return c;
}
int decimal::digitSub(char& c1,const char c2,const int b) {
int c=(c1>=c2+b)?0:1;
int i=c1+(c*10)-c2+48-b;
c1=char(i);
return c;
}
char decimal::digitMult(char& c1,const char c2,const char m) {
int i=(c1-4*(c2-4+(m-4;
c1=i%10+48;
return char(i/10+4;
}
int decimal::valCmp(const std::string& s1,const int e1,const std::string& s2,const int e2) const {
unsigned int h1,h2; //第一有效位的位置
//去掉前导0
for (h1=0;h1<s1.size() && (s1[h1]=='0');++h1) {}
for (h2=0;h2<s2.size() && (s2[h2]=='0');++h2) {}
if ( (h1<s1.size()) && ((s1.size()-h1+e1)>(s2.size()-h2+e2)) ) return 1;
if ( ((s1.size()-h1+e1)<(s2.size()-h2+e2)) && (h1<s1.size()) ) return -1;
int i,j;
for (i=s1.size()-h1,j=s2.size()-h2;i>0 && j>0;--i,--j,++h1,++h2) {
if (s1[h1]<s2[h2]) return -1;
if (s1[h1]>s2[h2]) return 1;
}
if (i>j) {
for (;i>0 && s1[h1]=='0';--i,++h1) {}
return (i==0)?0:1;
}
if (i<j) {
for (;j>0 && s2[h2]=='0';--j,++h2) {}
return (j==0)?0:-1;
}
return 0;
}
decimal& decimal::decReg() {
//消去前0和尾0,调整指数exp
unsigned int b,e;
for (b=0;b<val.size()-1 && val=='0';++b){}
for (e=val.size()-1;e>b && val[e]=='0';--e,++exp){}
if (b!=0 || e!=val.size()-1) val=val.substr(b,e-b+1);
if (val.size()==1 && val[0]=='0') {exp=0;sn=PLUS;} //值为“零”,指数应为0,符号认定为正
return *this;
}
unsigned int midDigits(const decimal& d1,const decimal& d2) {
//计算和或差中间变量的位数
int li1,ld1,li2,ld2,li,ld;
li1= d1.getVal().size()+d1.getExp();
if ( d1.getExp()>=0 ) {
li1=d1.getVal().size()+d1.getExp();
ld1=0;
}
else {
if (li1<0) li1=0;
ld1=-d1.getExp();
}
li2=d2.getVal().size()+d2.getExp();
if ( d2.getExp()>=0 ) {
ld2=0;
}
else {
if (li2<0) li2=0;
ld2=-d2.getExp();
}
li=(li1>=li2)?li1:li2; //整数位数
ld=(ld1>=ld2)?ld1:ld2; //小数位数
return li+ld+1;
}
[ 本帖最后由 hqxyn 于 2006-8-22 19:55 编辑 ] |
|