1 /*
2   This file is part of MADNESS.
3 
4   Copyright (C) 2007,2010 Oak Ridge National Laboratory
5 
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10 
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14   GNU General Public License for more details.
15 
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 
20   For more information please contact:
21 
22   Robert J. Harrison
23   Oak Ridge National Laboratory
24   One Bethel Valley Road
25   P.O. Box 2008, MS-6367
26 
27   email: harrisonrj@ornl.gov
28   tel:   865-241-3937
29   fax:   865-572-0680
30 
31   $Id$
32 */
33 /*
34 	Multi-precision real number class. C++ wrapper fo MPFR library.
35 	Project homepage: http://www.holoborodko.com/pavel/
36 	Contact e-mail:   pavel@holoborodko.com
37 
38 	Copyright (c) 2008 Pavel Holoborodko
39 
40 	This library is free software; you can redistribute it and/or
41 	modify it under the terms of the GNU Lesser General Public
42 	License as published by the Free Software Foundation; either
43 	version 2.1 of the License, or (at your option) any later version.
44 
45 	This library is distributed in the hope that it will be useful,
46 	but WITHOUT ANY WARRANTY; without even the implied warranty of
47 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
48 	Lesser General Public License for more details.
49 
50 	You should have received a copy of the GNU Lesser General Public
51 	License along with this library; if not, write to the Free Software
52 	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
53 
54 	Contributors:
55 	Brain Gladman, Helmut Jarausch, Fokko Beekhof, Ulrich Mutze.
56 */
57 
58 #include <cstring>
59 #include <sstream>
60 #include "mpreal.h"
61 
62 using std::ws;
63 using std::cerr;
64 using std::endl;
65 using std::string;
66 using std::ostream;
67 using std::istream;
68 
69 namespace mpfr{
70 
71 mp_rnd_t   mpreal::default_rnd  = mpfr_get_default_rounding_mode();
72 mp_prec_t  mpreal::default_prec = mpfr_get_default_prec();
73 int		   mpreal::default_base = 10;
74 int        mpreal::double_bits = -1;
75 
76 // Default constructor: creates mp number and initializes it to 0.
mpreal()77 mpreal::mpreal()
78 {
79 	mpfr_init2(mp,default_prec);
80 	mpfr_set_ui(mp,0,default_rnd);
81 }
82 
mpreal(const mpreal & u)83 mpreal::mpreal(const mpreal& u)
84 {
85 	mpfr_init2(mp,mpfr_get_prec(u.mp));
86 	mpfr_set(mp,u.mp,default_rnd);
87 }
88 
mpreal(const mpfr_t u)89 mpreal::mpreal(const mpfr_t u)
90 {
91 	mpfr_init2(mp,mpfr_get_prec(u));
92 	mpfr_set(mp,u,default_rnd);
93 }
94 
mpreal(const mpf_t u)95 mpreal::mpreal(const mpf_t u)
96 {
97 	mpfr_init2(mp,mpf_get_prec(u));
98 	mpfr_set_f(mp,u,default_rnd);
99 }
100 
mpreal(const mpz_t u,mp_prec_t prec,mp_rnd_t mode)101 mpreal::mpreal(const mpz_t u, mp_prec_t prec, mp_rnd_t mode)
102 {
103 	mpfr_init2(mp,prec);
104 	mpfr_set_z(mp,u,default_rnd);
105 }
106 
mpreal(const mpq_t u,mp_prec_t prec,mp_rnd_t mode)107 mpreal::mpreal(const mpq_t u, mp_prec_t prec, mp_rnd_t mode)
108 {
109 	mpfr_init2(mp,prec);
110 	mpfr_set_q(mp,u,default_rnd);
111 }
112 
mpreal(const double u,mp_prec_t prec,mp_rnd_t mode)113 mpreal::mpreal(const double u, mp_prec_t prec, mp_rnd_t mode)
114 {
115     if(double_bits == -1 || fits_in_bits(u, double_bits))
116     {
117     	mpfr_init2(mp,prec);
118 	    mpfr_set_d(mp,u,mode);
119     }
120     else
121         throw conversion_overflow();
122 }
123 
mpreal(const long double u,mp_prec_t prec,mp_rnd_t mode)124 mpreal::mpreal(const long double u, mp_prec_t prec, mp_rnd_t mode)
125 {
126     mpfr_init2(mp,prec);
127 	mpfr_set_ld(mp,u,mode);
128 }
129 
mpreal(const unsigned long int u,mp_prec_t prec,mp_rnd_t mode)130 mpreal::mpreal(const unsigned long int u, mp_prec_t prec, mp_rnd_t mode)
131 {
132 	mpfr_init2(mp,prec);
133 	mpfr_set_ui(mp,u,mode);
134 }
135 
mpreal(const unsigned int u,mp_prec_t prec,mp_rnd_t mode)136 mpreal::mpreal(const unsigned int u, mp_prec_t prec, mp_rnd_t mode)
137 {
138 	mpfr_init2(mp,prec);
139 	mpfr_set_ui(mp,u,mode);
140 }
141 
mpreal(const long int u,mp_prec_t prec,mp_rnd_t mode)142 mpreal::mpreal(const long int u, mp_prec_t prec, mp_rnd_t mode)
143 {
144 	mpfr_init2(mp,prec);
145 	mpfr_set_si(mp,u,mode);
146 }
147 
mpreal(const int u,mp_prec_t prec,mp_rnd_t mode)148 mpreal::mpreal(const int u, mp_prec_t prec, mp_rnd_t mode)
149 {
150 	mpfr_init2(mp,prec);
151 	mpfr_set_si(mp,u,mode);
152 }
153 
mpreal(const char * s,mp_prec_t prec,int base,mp_rnd_t mode)154 mpreal::mpreal(const char* s, mp_prec_t prec, int base, mp_rnd_t mode)
155 {
156 	mpfr_init2(mp,prec);
157 	mpfr_set_str(mp, s, base, mode);
158 }
159 
~mpreal()160 mpreal::~mpreal()
161 {
162 	mpfr_clear(mp);
163 }
164 
165 // Operators - Assignment
operator =(const char * s)166 mpreal& mpreal::operator=(const char* s)
167 {
168 	mpfr_t t;
169 	if(0==mpfr_init_set_str(t,s,default_base,default_rnd))
170 	{
171 		mpfr_set(mp,t,mpreal::default_rnd);
172 		mpfr_clear(t);
173 	}else{
174 		mpfr_clear(t);
175 		// cerr<<"fail to convert string"<<endl;
176 	}
177 
178 	return *this;
179 }
180 
fma(const mpreal & v1,const mpreal & v2,const mpreal & v3,mp_rnd_t rnd_mode)181 const mpreal fma (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode)
182 {
183 	mpreal a;
184 	mp_prec_t p1, p2, p3;
185 
186 	p1 = v1.get_prec();
187 	p2 = v2.get_prec();
188 	p3 = v3.get_prec();
189 
190 	a.set_prec(p3>p2?(p3>p1?p3:p1):(p2>p1?p2:p1));
191 
192 	mpfr_fma(a.mp,v1.mp,v2.mp,v3.mp,rnd_mode);
193 	return a;
194 }
195 
fms(const mpreal & v1,const mpreal & v2,const mpreal & v3,mp_rnd_t rnd_mode)196 const mpreal fms (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode)
197 {
198 	mpreal a;
199 	mp_prec_t p1, p2, p3;
200 
201 	p1 = v1.get_prec();
202 	p2 = v2.get_prec();
203 	p3 = v3.get_prec();
204 
205 	a.set_prec(p3>p2?(p3>p1?p3:p1):(p2>p1?p2:p1));
206 
207 	mpfr_fms(a.mp,v1.mp,v2.mp,v3.mp,rnd_mode);
208 	return a;
209 }
210 
agm(const mpreal & v1,const mpreal & v2,mp_rnd_t rnd_mode)211 const mpreal agm (const mpreal& v1, const mpreal& v2, mp_rnd_t rnd_mode)
212 {
213 	mpreal a;
214 	mp_prec_t p1, p2;
215 
216 	p1 = v1.get_prec();
217 	p2 = v2.get_prec();
218 
219 	a.set_prec(p1>p2?p1:p2);
220 
221 	mpfr_agm(a.mp, v1.mp, v2.mp, rnd_mode);
222 
223 	return a;
224 }
225 
hypot(const mpreal & x,const mpreal & y,mp_rnd_t rnd_mode)226 const mpreal hypot (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode)
227 {
228 	mpreal a;
229 	mp_prec_t yp, xp;
230 
231 	yp = y.get_prec();
232 	xp = x.get_prec();
233 
234 	a.set_prec(yp>xp?yp:xp);
235 
236 	mpfr_hypot(a.mp, x.mp, y.mp, rnd_mode);
237 
238 	return a;
239 }
240 
sum(const mpreal tab[],unsigned long int n,mp_rnd_t rnd_mode)241 const mpreal sum (const mpreal tab[], unsigned long int n, mp_rnd_t rnd_mode)
242 {
243 	mpreal x;
244 	mpfr_ptr* t;
245 	unsigned long int i;
246 
247 	t = new mpfr_ptr[n];
248 	for (i=0;i<n;i++) t[i] = (mpfr_ptr)tab[i].mp;
249 	mpfr_sum(x.mp,t,n,rnd_mode);
250 	delete[] t;
251 	return x;
252 }
253 
remainder(const mpreal & x,const mpreal & y,mp_rnd_t rnd_mode)254 const mpreal remainder (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode)
255 {
256 	mpreal a;
257 	mp_prec_t yp, xp;
258 
259 	yp = y.get_prec();
260 	xp = x.get_prec();
261 
262 	a.set_prec(yp>xp?yp:xp);
263 
264 	mpfr_remainder(a.mp, x.mp, y.mp, rnd_mode);
265 
266 	return a;
267 }
268 
remquo(long * q,const mpreal & x,const mpreal & y,mp_rnd_t rnd_mode)269 const mpreal remquo (long* q, const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode)
270 {
271 	mpreal a;
272 	mp_prec_t yp, xp;
273 
274 	yp = y.get_prec();
275 	xp = x.get_prec();
276 
277 	a.set_prec(yp>xp?yp:xp);
278 
279 	mpfr_remquo(a.mp,q, x.mp, y.mp, rnd_mode);
280 
281 	return a;
282 }
283 
284 template <class T>
to_string(T t,std::ios_base & (* f)(std::ios_base &))285 std::string to_string(T t, std::ios_base & (*f)(std::ios_base&))
286 {
287 	std::ostringstream oss;
288 	oss << f << t;
289 	return oss.str();
290 }
291 
to_string(size_t n,int b,mp_rnd_t mode) const292 string mpreal::to_string(size_t n, int b, mp_rnd_t mode) const
293 {
294 	char *s, *ns = nullptr;
295 	size_t slen, nslen;
296 	mp_exp_t exp;
297 	string out;
298 
299 	if(mpfr_inf_p(mp))
300 	{
301 		if(mpfr_sgn(mp)>0) return "+@Inf@";
302 		else			   return "-@Inf@";
303 	}
304 
305 	if(mpfr_zero_p(mp)) return "0";
306 	if(mpfr_nan_p(mp))  return "@NaN@";
307 
308 
309 	s  = mpfr_get_str(nullptr,&exp,b,0,mp,mode);
310 	ns = mpfr_get_str(nullptr,&exp,b,n,mp,mode);
311 
312 	if(s!=nullptr && ns!=nullptr)
313 	{
314 		slen  = strlen(s);
315 		nslen = strlen(ns);
316 		if(nslen<=slen)
317 		{
318 			mpfr_free_str(s);
319 			s = ns;
320 			slen = nslen;
321 		}
322 		else {
323 			mpfr_free_str(ns);
324 		}
325 
326 		// Make human eye-friendly formatting if possible
327 		if (exp>0 && static_cast<size_t>(exp)<slen)
328 		{
329 			if(s[0]=='-')
330 			{
331 				// Remove zeros starting from right end
332 				char* ptr = s+slen-1;
333 				while (*ptr=='0' && ptr>s+exp) ptr--;
334 
335 				if(ptr==s+exp) out = string(s,exp+1);
336 				else		   out = string(s,exp+1)+'.'+string(s+exp+1,ptr-(s+exp+1)+1);
337 
338 				//out = string(s,exp+1)+'.'+string(s+exp+1);
339 			}
340 			else
341 			{
342 				// Remove zeros starting from right end
343 				char* ptr = s+slen-1;
344 				while (*ptr=='0' && ptr>s+exp-1) ptr--;
345 
346 				if(ptr==s+exp-1) out = string(s,exp);
347 				else		     out = string(s,exp)+'.'+string(s+exp,ptr-(s+exp)+1);
348 
349 				//out = string(s,exp)+'.'+string(s+exp);
350 			}
351 
352 		}else{ // exp<0 || exp>slen
353 			if(s[0]=='-')
354 			{
355 				// Remove zeros starting from right end
356 				char* ptr = s+slen-1;
357 				while (*ptr=='0' && ptr>s+1) ptr--;
358 
359 				if(ptr==s+1) out = string(s,2);
360 				else		 out = string(s,2)+'.'+string(s+2,ptr-(s+2)+1);
361 
362 				//out = string(s,2)+'.'+string(s+2);
363 			}
364 			else
365 			{
366 				// Remove zeros starting from right end
367 				char* ptr = s+slen-1;
368 				while (*ptr=='0' && ptr>s) ptr--;
369 
370 				if(ptr==s) out = string(s,1);
371 				else	   out = string(s,1)+'.'+string(s+1,ptr-(s+1)+1);
372 
373 				//out = string(s,1)+'.'+string(s+1);
374 			}
375 
376 			// Make final string
377 			if(--exp)
378 				if(exp>0) out += "e+"+mpfr::to_string<mp_exp_t>(exp,std::dec);
379 				else 	  out += "e"+mpfr::to_string<mp_exp_t>(exp,std::dec);
380 		}
381 
382 		mpfr_free_str(s);
383 		return out;
384 	}else{
385 		return "conversion error!";
386 	}
387 }
388 
389 //////////////////////////////////////////////////////////////////////////
390 // I/O
operator <<(ostream & os,const mpreal & v)391 ostream& operator<<(ostream& os, const mpreal& v)
392 {
393 	return os<<v.to_string(os.precision());
394 }
395 
operator >>(istream & is,mpreal & v)396 istream& operator>>(istream &is, mpreal& v)
397 {
398 	char c;
399 	string s = "";
400 	mpfr_t t;
401 
402 	if(is.good())
403 	{
404 		is>>ws;
405 		while ((c = is.get())!=EOF)
406 		{
407 			if(c ==' ' || c == '\t' || c == '\n' || c == '\r')
408 			{
409 				is.putback(c);
410 				break;
411 			}
412 			s += c;
413 		}
414 
415 		if(s.size() != 0)
416 		{
417 			// Protect current value from alternation in case of input error
418 			// so some error handling(roll back) procedure can be used
419 			if(0==mpfr_init_set_str(t,s.c_str(),mpreal::default_base,mpreal::default_rnd))
420 			{
421 				mpfr_set(v.mp,t,mpreal::default_rnd);
422 				mpfr_clear(t);
423 
424 			}else{
425 				mpfr_clear(t);
426 				cerr<<"error reading from istream"<<endl;
427 				// throw an exception
428 			}
429 		}
430 	}
431 	return is;
432 }
433 }
434