📄 wy__numstr_basic.h
字号:
/* Copyright is licensed by GNU LGPL. by I.J.Wang 2005 This file is template or inline functions for include in implementaion for each instantiated type*/#ifndef WY__NUMSTR_BASIC_H__#define WY__NUMSTR_BASIC_H__#define WYLIB_SOURCE#include "wystr.h"#include <cstdlib>#include <cstring>#include <cmath>#include <limits>namespace WyMath { extern double _scif(double x, double& p10);};static const char WY__EToken('e');// [Internal] Break num into radix notation and store into buf//// Note: 1. buf have to have enough space before call// 2. buf can not be 0, radix should be >=2// 3. the stored 'digit' is saved in reversed order// 4. if num is negative, the stored 'digit' is negative// 5. the stored 'digit' is in range [0-radix)// // [Ret] number of digits stored into buf//inline int wy__brknum(char* buf,int num, int radix) WY__TSPC(){ std::div_t dt={num,0}; //dt.quot=num; int n=0; do { dt=std::div(dt.quot,radix); buf[n++]=(char)(dt.rem); } while(dt.quot!=0); return(n);};inline int wy__brknum(char* buf,long num, int radix) WY__TSPC(){ std::ldiv_t dt={num,0}; //dt.quot=num; int n=0; do { dt=std::ldiv(dt.quot,radix); buf[n++]=(char)(dt.rem); } while(dt.quot!=0); return(n);};inline static int wy__brknum(char* buf,long long num, int radix) WY__TSPC(){ std::lldiv_t dt={num,0}; //dt.quot=num; int n=0; do { dt=std::lldiv(dt.quot,radix); buf[n++]=(char)(dt.rem); } while(dt.quot!=0); return(n);};inline int wy__brknum(char* buf,unsigned int num, int radix){ if(num<=(unsigned int)(std::numeric_limits<int>::max())) { return( wy__brknum(buf,(int)num,radix) ); } const unsigned int q=num/radix; if(q>(unsigned int)(std::numeric_limits<int>::max())) { // assertion fail WY_THROW(WyRet(Wym_ERANGE)); } buf[0]= char(num%radix); return( wy__brknum(buf+1,(int)q,radix)+1 );};inline int wy__brknum(char* buf,unsigned long num, int radix){ if(num<=(unsigned long)(std::numeric_limits<long>::max())) { return( wy__brknum(buf,(long)num,radix) ); } const unsigned long q=num/radix; if(q>(unsigned long)(std::numeric_limits<long>::max())) { // assertion fail WY_THROW(WyRet(Wym_ERANGE)); } buf[0]= char(num%radix); return( wy__brknum(buf+1,(long)q,radix)+1 );};inline static int wy__brknum(char* buf,unsigned long long num, int radix){ if(num<=(unsigned long long)(std::numeric_limits<signed long long>::max())) { return( wy__brknum(buf,(long long)num,radix) ); } const unsigned long long q=num/radix; if(q>(unsigned long long)(std::numeric_limits<signed long long>::max())) { // assertion fail WY_THROW(WyRet(Wym_ERANGE)); } buf[0]= char(num%radix); return( wy__brknum(buf+1,(signed long long)q,radix)+1 );};inline int wy__brknum(char*,double, int){ // This function exist for compiling reason. should not be actually called WY_TERMINATE("");};//// [Internal] Convert the broken down representation in buf/blen// to ascii//// Note: buf can not be 0, blen must be >0//inline void wy__cvrrev_pos(char* buf, int blen) WY__TSPC(){ int i,j; for(i=0, j=blen-1; i<=j; ++i,--j) { char ch1=buf[i]; char ch2=buf[j]; ch1= (ch1>9)? (ch1+'7'):(ch1+'0'); ch2= (ch2>9)? (ch2+'7'):(ch2+'0'); buf[i]=ch2; buf[j]=ch1; }};//// [Internal] Convert the broken down representation in buf/blen// to ascii//// Note: buf can not be 0, blen must be >0// Note: buf contaions one more character ('-') after return//inline void wy__cvrrev_neg(char* buf, int blen) WY__TSPC(){ { const char ch0=-buf[0]; buf[blen]=(ch0>9)? (ch0+'7'):(ch0+'0'); buf[0]='-'; } int i,j; for(i=1, j=blen-1; i<=j; ++i,--j) { char ch1=-buf[i]; char ch2=-buf[j]; ch1= (ch1>9)? (ch1+'7'):(ch1+'0'); ch2= (ch2>9)? (ch2+'7'):(ch2+'0'); buf[i]=ch2; buf[j]=ch1; }};// [Interna] Convert number(integer type) to string//// [Ret] Ok// Wym_EINVAL radix invalid// Wym_EFBIG str size exceeds the maximum// Wym_ENOMEM Not enough memory//template <typename NumT>inline WyRet wy__setnum_integer(WyStr &str, NumT num, int radix){ if(std::numeric_limits<NumT>::is_integer==false) { WY_TERMINATE(""); } if((radix<2)||(radix>36)) { WY_RETURN(Wym_EINVAL); } char dbuf[std::numeric_limits<NumT>::digits+2]; // digits*('0'|'1') +'-' + 0 int n=wy__brknum(dbuf,num,radix); if(std::numeric_limits<NumT>::is_signed) { if(num<0) { wy__cvrrev_neg(dbuf,n); ++n; } else { wy__cvrrev_pos(dbuf,n); } } else { wy__cvrrev_pos(dbuf,n); } WY_RETURN( str.reset( WyCSeg(dbuf,(size_t)n) ) );};// [Syn] Convert number num into radix string// representation, reset str with the result. The number of// characters for fraction is specified by frdig.// [-]ddd.ddd//// Note: There may be truncate or round-up error // // Implementation works only for radix equal to 10//// [Ret] Ok Succeed// Wym_EINVAL radix invalid// Wym_EFBIG str size exceeds the maximum// Wym_ENOMEM Not enough memory//inline WyRet wy__setnum_double(WyStr &str,double num,int radix,size_t frdig)try { typedef long long int FI_INT; // int type capable holding (int)double const size_t FI_INT_DIG10( size_t(std::numeric_limits<FI_INT>::digits10) ); if(radix!=10) { WY_RETURN(Wym_EINVAL); } if(frdig>FI_INT_DIG10) { frdig=FI_INT_DIG10; } if(isnan(num)) { str.reset("nan"); return(Ok); } if(isinf(num)) { if(isinf(num)>0) { str.reset("inf"); } else { str.reset("-inf"); } return(Ok); } WyRet r; WyStr stmp; double wnum; // whole num double frac; // fraction if(num<0) { stmp.reset(1,'-'); // always Ok num=-num; } frac=std::modf(num,&wnum); { WyStr tmp; size_t n_dig( static_cast<size_t>(std::log10(wnum)+1.0) ); // dig10 of wnum if(n_dig>=FI_INT_DIG10) { wnum/= std::pow((double)10.0,(double)(n_dig-FI_INT_DIG10+1)); } r=wy__setnum_integer(tmp,static_cast<FI_INT>(wnum),10); if(r!=Ok) { WY_RETURN(r); } if(n_dig>=FI_INT_DIG10) { if((r=tmp.append(n_dig-FI_INT_DIG10+1,'0'))!=Ok) { WY_RETURN(r); } } stmp+=tmp; if(frdig<=0) { if(wnum<=0) { WY_RETURN( str.reset("0") ); } else { WY_RETURN( str.reset(stmp) ); } } stmp+='.'; } std::modf(frac*std::pow(10.0,static_cast<double>(frdig)) +std::numeric_limits<double>::epsilon() // roundup? ,&wnum); { WyStr tmp; r=wy__setnum_integer(tmp,static_cast<FI_INT>(wnum),10); if(r!=Ok) { WY_RETURN(r); } if(frdig<tmp.size()) { WY_THROW(WyRet(Wym_ERANGE)); } if((r=stmp.append(frdig-tmp.size(),'0'))!=Ok) { WY_RETURN(r); } stmp+=tmp; } str.swap(stmp); return(Ok);}catch(const WyStr::Reply& e) { return(e);};template <typename NumT>WyRet wy__setnum(WyStr &str, NumT num, int radix)try { if(std::numeric_limits<NumT>::is_integer) { WY_RETURN( wy__setnum_integer(str,num,radix) ); } else { // float NumT assumed typedef signed long long int FI_INT; // int type capable holding (int)double const int FrRadix=10; // float type always use radix 10 const size_t DftFracDig=6; // number of digits for fraction if(radix==FrRadix) { WY_RETURN(wy__setnum_double(str,num,radix,DftFracDig)); } else if (radix!=0) { WY_RETURN(Wym_EINVAL); } else { // FALL_THROUGH with radix==0 } double fnorm,p10; WyRet r; WyStr tmp1; fnorm=WyMath::_scif(num,p10); if((r=wy__setnum_double(tmp1,fnorm,FrRadix,DftFracDig))!=Ok) { WY_RETURN(r); } { WyStr tmp2; if((r=wy__setnum_integer(tmp2,static_cast<FI_INT>(p10),FrRadix))!=Ok) { WY_RETURN(r); } tmp1+=WY__EToken; if(p10>=0) { tmp1+='+'; } tmp1+=tmp2; } return( str.reset(tmp1) ); }}catch(const WyStr::Reply& e) { WY_RETURN( WyRet(e) );};template <typename NumT>WyRet wy__setnum(WyStr &str, NumT num, int radix, size_t frdig)try { if(std::numeric_limits<NumT>::is_integer) { if(frdig!=0) { WY_RETURN(Wym_EINVAL); } WY_RETURN( wy__setnum_integer(str,num,radix) ); } else { // float NumT assumed typedef signed long long int FI_INT; // int type capable holding (int)double const int FrRadix=10; // float type always use radix 10 if(radix==FrRadix) { WY_RETURN(wy__setnum_double(str,num,radix,frdig)); } else if (radix!=0) { WY_RETURN(Wym_EINVAL); } else { // FALL_THROUGH with radix==0 } if(isnan(num)) { str.reset("nan"); return(Ok); } if(isinf(num)) { if(isinf(num)>0) { str.reset("inf"); } else { str.reset("-inf"); } return(Ok); } double fnorm,p10; WyRet r; WyStr tmp1; fnorm=WyMath::_scif(num,p10); if((r=wy__setnum_double(tmp1,fnorm,FrRadix,frdig))!=Ok) { WY_RETURN(r); } { WyStr tmp2; if((r=wy__setnum_integer(tmp2,static_cast<FI_INT>(p10),FrRadix))!=Ok) { WY_RETURN(r); } tmp1+=WY__EToken; if(p10>=0) { tmp1+='+'; } tmp1+=tmp2; } return( str.reset(tmp1) ); }}catch(const WyStr::Reply& e) { WY_RETURN( WyRet(e) );};template <typename NumT>WyRet wy__apdnum_integer(WyStr &str, NumT num, int radix){ if((radix<2)||(radix>36)) { WY_RETURN(Wym_EINVAL); } char dbuf[std::numeric_limits<NumT>::digits+2]; // digits*('0'|'1') +'-' + 0 int n=wy__brknum(dbuf,num,radix); if(std::numeric_limits<NumT>::is_signed) { if(num<0) { wy__cvrrev_neg(dbuf,n); ++n; } else { wy__cvrrev_pos(dbuf,n); } } else { wy__cvrrev_pos(dbuf,n); } WY_RETURN( str.append( WyCSeg(dbuf,(size_t)n) ) );};// [Syn] Convert number num into radix string// representation, append the result to str. The number of// characters for fraction is specified by frdig.// [-]ddd.ddd//// Note: There may be truncate or round-up error // // Implementation works only for radix equal to 10//// [Ret] Ok Succeed// Wym_EINVAL radix invalid// Wym_EFBIG str size exceeds the maximum// Wym_ENOMEM Not enough memory//inline WyRet wy__apdnum_double(WyStr &str,double num,int radix,size_t frdig)try { typedef long long int FI_INT; // int type capable holding (int)double const size_t FI_INT_DIG10( size_t(std::numeric_limits<FI_INT>::digits10) ); if(radix!=10) { WY_RETURN(Wym_EINVAL); } if(frdig>FI_INT_DIG10) { frdig=FI_INT_DIG10; } if(isnan(num)) { WY_RETURN( str.append("nan") ); } if(isinf(num)) { if(isinf(num)>0) { WY_RETURN( str.append("inf") ); } else { WY_RETURN( str.append("-inf") ); } } WyRet r; WyStr stmp; double wnum; // whole num double frac; // fraction if(num<0) { stmp.reset(1,'-'); // always Ok num=-num; } frac=std::modf(num,&wnum); { WyStr tmp; size_t n_dig( static_cast<size_t>(std::log10(wnum)+1.0) ); // dig10 of wnum if(n_dig>=FI_INT_DIG10) { wnum/= std::pow((double)10.0,(double)(n_dig-FI_INT_DIG10+1)); } r=wy__setnum_integer(tmp,static_cast<FI_INT>(wnum),10); if(r!=Ok) { WY_RETURN(r); } if(n_dig>=FI_INT_DIG10) { if((r=tmp.append(n_dig-FI_INT_DIG10+1,'0'))!=Ok) { WY_RETURN(r); } } stmp+=tmp; if(frdig<=0) { if(wnum<=0) { WY_RETURN( str.append(char('0')) ); } else { WY_RETURN( str.append(stmp) ); } } stmp+='.'; } std::modf(frac*std::pow(10.0,static_cast<double>(frdig)) +std::numeric_limits<double>::epsilon() // roundup? ,&wnum); { WyStr tmp; r=wy__setnum_integer(tmp,static_cast<FI_INT>(wnum),10); if(r!=Ok) { WY_RETURN(r); } if(frdig<tmp.size()) { WY_TERMINATE(""); } if((r=stmp.append(frdig-tmp.size(),'0'))!=Ok) { WY_RETURN(r); } stmp+=tmp; } WY_RETURN( str.append(stmp) );}catch(const WyStr::Reply& e) { return(e);};template <typename NumT>WyRet wy__apdnum(WyStr &str, NumT num, int radix)try { if(std::numeric_limits<NumT>::is_integer) { WY_RETURN( wy__apdnum_integer(str,num,radix) ); } else { // float NumT assumed typedef signed long long int FI_INT; // int type capable holding (int)double const int FrRadix=10; // float types always use radix 10 const size_t DftFracDig=6; // number of digits for fraction if(radix==FrRadix) { WY_RETURN(wy__apdnum_double(str,num,radix,DftFracDig)); } else if (radix!=0) { WY_RETURN(Wym_EINVAL); } else { // FALL_THROUGH with radix==0 } if(isnan(num)) { str.reset("nan"); return(Ok); } if(isinf(num)) { if(isinf(num)>0) { str.reset("inf"); } else { str.reset("-inf"); } return(Ok); } double fnorm,p10; WyRet r; WyStr tmp1; fnorm=WyMath::_scif(num,p10); if((r=wy__setnum_double(tmp1,fnorm,FrRadix,DftFracDig))!=Ok) { WY_RETURN(r); } { WyStr tmp2; if((r=wy__setnum_integer(tmp2,static_cast<FI_INT>(p10),FrRadix))!=Ok) { WY_RETURN(r); } tmp1+=WY__EToken; if(p10>=0) { tmp1+='+'; } tmp1+=tmp2; } return( str.append(tmp1) ); }}catch(const WyStr::Reply& e) { return(e);};template <typename NumT>WyRet wy__apdnum(WyStr &str, NumT num, int radix, size_t frdig)try { if(std::numeric_limits<NumT>::is_integer) { if(frdig!=0) { WY_RETURN(Wym_EINVAL); } WY_RETURN( wy__apdnum_integer(str,num,radix) ); } else { // float NumT assumed typedef signed long long int FI_INT; // int type capable holding (int)double const int FrRadix=10; // float types always use radix 10 if(radix==FrRadix) { WY_RETURN(wy__apdnum_double(str,num,radix,frdig)); } else if (radix!=0) { WY_RETURN(Wym_EINVAL); } else { // FALL_THROUGH with radix==0 } double fnorm,p10; WyRet r; WyStr tmp1; fnorm=WyMath::_scif(num,p10); if((r=wy__setnum_double(tmp1,fnorm,FrRadix,frdig))!=Ok) { WY_RETURN(r); } { WyStr tmp2; if((r=wy__setnum_integer(tmp2,static_cast<FI_INT>(p10),FrRadix))!=Ok) { WY_RETURN(r); } tmp1+=WY__EToken; if(p10>=0) { tmp1+='+'; } tmp1+=tmp2; } return( str.append(tmp1) ); }}catch(const WyStr::Reply& e) { return(e);};#endif // end of WY__NUMSTR_BASIC_H__
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -