/* Multi-precision real number class. C++ wrapper fo MPFR library. Project homepage: http://www.holoborodko.com/pavel/ Contact e-mail: pavel@holoborodko.com Copyright (c) 2008-2010 Pavel Holoborodko This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Contributors: Brian Gladman, Helmut Jarausch, Fokko Beekhof, Ulrich Mutze, Heinz van Saanen, Pere Constans, Dmitriy Gubanov */ #include #include "mpreal.h" using std::ws; using std::cerr; using std::endl; using std::string; using std::ostream; using std::istream; namespace mpfr{ mp_rnd_t mpreal::default_rnd = mpfr_get_default_rounding_mode(); mp_prec_t mpreal::default_prec = mpfr_get_default_prec(); int mpreal::default_base = 10; int mpreal::double_bits = -1; // Default constructor: creates mp number and initializes it to 0. mpreal::mpreal() { mpfr_init2(mp,default_prec); mpfr_set_ui(mp,0,default_rnd); } mpreal::mpreal(const mpreal& u) { mpfr_init2(mp,mpfr_get_prec(u.mp)); mpfr_set(mp,u.mp,default_rnd); } mpreal::mpreal(const mpfr_t u) { mpfr_init2(mp,mpfr_get_prec(u)); mpfr_set(mp,u,default_rnd); } mpreal::mpreal(const mpf_t u) { mpfr_init2(mp,mpf_get_prec(u)); mpfr_set_f(mp,u,default_rnd); } mpreal::mpreal(const mpz_t u, mp_prec_t prec, mp_rnd_t mode) { mpfr_init2(mp,prec); mpfr_set_z(mp,u,mode); } mpreal::mpreal(const mpq_t u, mp_prec_t prec, mp_rnd_t mode) { mpfr_init2(mp,prec); mpfr_set_q(mp,u,mode); } mpreal::mpreal(const double u, mp_prec_t prec, mp_rnd_t mode) { if(double_bits == -1 || fits_in_bits(u, double_bits)) { mpfr_init2(mp,prec); mpfr_set_d(mp,u,mode); } else throw conversion_overflow(); } mpreal::mpreal(const long double u, mp_prec_t prec, mp_rnd_t mode) { mpfr_init2(mp,prec); mpfr_set_ld(mp,u,mode); } mpreal::mpreal(const unsigned long int u, mp_prec_t prec, mp_rnd_t mode) { mpfr_init2(mp,prec); mpfr_set_ui(mp,u,mode); } mpreal::mpreal(const unsigned int u, mp_prec_t prec, mp_rnd_t mode) { mpfr_init2(mp,prec); mpfr_set_ui(mp,u,mode); } mpreal::mpreal(const long int u, mp_prec_t prec, mp_rnd_t mode) { mpfr_init2(mp,prec); mpfr_set_si(mp,u,mode); } mpreal::mpreal(const int u, mp_prec_t prec, mp_rnd_t mode) { mpfr_init2(mp,prec); mpfr_set_si(mp,u,mode); } mpreal::mpreal(const char* s, mp_prec_t prec, int base, mp_rnd_t mode) { mpfr_init2(mp,prec); mpfr_set_str(mp, s, base, mode); } mpreal::~mpreal() { mpfr_clear(mp); } // Operators - Assignment mpreal& mpreal::operator=(const char* s) { mpfr_t t; if(0==mpfr_init_set_str(t,s,default_base,default_rnd)) { mpfr_set(mp,t,mpreal::default_rnd); mpfr_clear(t); }else{ mpfr_clear(t); // cerr<<"fail to convert string"<p2?(p3>p1?p3:p1):(p2>p1?p2:p1)); mpfr_fma(a.mp,v1.mp,v2.mp,v3.mp,rnd_mode); return a; } const mpreal fms (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode) { mpreal a; mp_prec_t p1, p2, p3; p1 = v1.get_prec(); p2 = v2.get_prec(); p3 = v3.get_prec(); a.set_prec(p3>p2?(p3>p1?p3:p1):(p2>p1?p2:p1)); mpfr_fms(a.mp,v1.mp,v2.mp,v3.mp,rnd_mode); return a; } const mpreal agm (const mpreal& v1, const mpreal& v2, mp_rnd_t rnd_mode) { mpreal a; mp_prec_t p1, p2; p1 = v1.get_prec(); p2 = v2.get_prec(); a.set_prec(p1>p2?p1:p2); mpfr_agm(a.mp, v1.mp, v2.mp, rnd_mode); return a; } const mpreal hypot (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode) { mpreal a; mp_prec_t yp, xp; yp = y.get_prec(); xp = x.get_prec(); a.set_prec(yp>xp?yp:xp); mpfr_hypot(a.mp, x.mp, y.mp, rnd_mode); return a; } const mpreal sum (const mpreal tab[], unsigned long int n, mp_rnd_t rnd_mode) { mpreal x; mpfr_ptr* t; unsigned long int i; t = new mpfr_ptr[n]; for (i=0;ixp?yp:xp); mpfr_remainder(a.mp, x.mp, y.mp, rnd_mode); return a; } const mpreal remquo (long* q, const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode) { mpreal a; mp_prec_t yp, xp; yp = y.get_prec(); xp = x.get_prec(); a.set_prec(yp>xp?yp:xp); mpfr_remquo(a.mp,q, x.mp, y.mp, rnd_mode); return a; } template std::string to_string(T t, std::ios_base & (*f)(std::ios_base&)) { std::ostringstream oss; oss << f << t; return oss.str(); } mpreal::operator std::string() const { return to_string(); } string mpreal::to_string(size_t n, int b, mp_rnd_t mode) const { char *s, *ns = NULL; size_t slen, nslen; mp_exp_t exp; string out; if(mpfr_inf_p(mp)) { if(mpfr_sgn(mp)>0) return "+@Inf@"; else return "-@Inf@"; } if(mpfr_zero_p(mp)) return "0"; if(mpfr_nan_p(mp)) return "@NaN@"; s = mpfr_get_str(NULL,&exp,b,0,mp,mode); ns = mpfr_get_str(NULL,&exp,b,n,mp,mode); if(s!=NULL && ns!=NULL) { slen = strlen(s); nslen = strlen(ns); if(nslen<=slen) { mpfr_free_str(s); s = ns; slen = nslen; } else { mpfr_free_str(ns); } // Make human eye-friendly formatting if possible if (exp>0 && static_cast(exp)s+exp) ptr--; if(ptr==s+exp) out = string(s,exp+1); else out = string(s,exp+1)+'.'+string(s+exp+1,ptr-(s+exp+1)+1); //out = string(s,exp+1)+'.'+string(s+exp+1); } else { // Remove zeros starting from right end char* ptr = s+slen-1; while (*ptr=='0' && ptr>s+exp-1) ptr--; if(ptr==s+exp-1) out = string(s,exp); else out = string(s,exp)+'.'+string(s+exp,ptr-(s+exp)+1); //out = string(s,exp)+'.'+string(s+exp); } }else{ // exp<0 || exp>slen if(s[0]=='-') { // Remove zeros starting from right end char* ptr = s+slen-1; while (*ptr=='0' && ptr>s+1) ptr--; if(ptr==s+1) out = string(s,2); else out = string(s,2)+'.'+string(s+2,ptr-(s+2)+1); //out = string(s,2)+'.'+string(s+2); } else { // Remove zeros starting from right end char* ptr = s+slen-1; while (*ptr=='0' && ptr>s) ptr--; if(ptr==s) out = string(s,1); else out = string(s,1)+'.'+string(s+1,ptr-(s+1)+1); //out = string(s,1)+'.'+string(s+1); } // Make final string if(--exp) { if(exp>0) out += "e+"+mpfr::to_string(exp,std::dec); else out += "e"+mpfr::to_string(exp,std::dec); } } mpfr_free_str(s); return out; }else{ return "conversion error!"; } } ////////////////////////////////////////////////////////////////////////// // I/O ostream& operator<<(ostream& os, const mpreal& v) { return os<>(istream &is, mpreal& v) { char c; string s = ""; mpfr_t t; if(is.good()) { is>>ws; while ((c = is.get())!=EOF) { if(c ==' ' || c == '\t' || c == '\n' || c == '\r') { is.putback(c); break; } s += c; } if(s.size() != 0) { // Protect current value from alternation in case of input error // so some error handling(roll back) procedure can be used if(0==mpfr_init_set_str(t,s.c_str(),mpreal::default_base,mpreal::default_rnd)) { mpfr_set(v.mp,t,mpreal::default_rnd); mpfr_clear(t); }else{ mpfr_clear(t); cerr<<"error reading from istream"<