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