Home | History | Annotate | Download | only in mpreal
      1 /*
      2 	Multi-precision real number class. C++ interface fo MPFR library.
      3 	Project homepage: http://www.holoborodko.com/pavel/
      4 	Contact e-mail:   pavel (at) holoborodko.com
      5 
      6 	Copyright (c) 2008-2011 Pavel Holoborodko
      7 
      8 	Core Developers:
      9 	Pavel Holoborodko, Dmitriy Gubanov, Konstantin Holoborodko.
     10 
     11 	Contributors:
     12 	Brian Gladman, Helmut Jarausch, Fokko Beekhof, Ulrich Mutze,
     13 	Heinz van Saanen, Pere Constans, Peter van Hoof, Gael Guennebaud,
     14 	Tsai Chia Cheng, Alexei Zubanov.
     15 
     16 	****************************************************************************
     17 	This library is free software; you can redistribute it and/or
     18 	modify it under the terms of the GNU Lesser General Public
     19 	License as published by the Free Software Foundation; either
     20 	version 2.1 of the License, or (at your option) any later version.
     21 
     22 	This library is distributed in the hope that it will be useful,
     23 	but WITHOUT ANY WARRANTY; without even the implied warranty of
     24 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     25 	Lesser General Public License for more details.
     26 
     27 	You should have received a copy of the GNU Lesser General Public
     28 	License along with this library; if not, write to the Free Software
     29 	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     30 
     31 	****************************************************************************
     32 	****************************************************************************
     33 	Redistribution and use in source and binary forms, with or without
     34 	modification, are permitted provided that the following conditions
     35 	are met:
     36 
     37 	1. Redistributions of source code must retain the above copyright
     38 	notice, this list of conditions and the following disclaimer.
     39 
     40 	2. Redistributions in binary form must reproduce the above copyright
     41 	notice, this list of conditions and the following disclaimer in the
     42 	documentation and/or other materials provided with the distribution.
     43 
     44 	3. The name of the author may be used to endorse or promote products
     45 	derived from this software without specific prior written permission.
     46 
     47 	THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     48 	ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     49 	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     50 	ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     51 	FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     52 	DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     53 	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     54 	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     55 	LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     56 	OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     57 	SUCH DAMAGE.
     58 */
     59 #include <cstring>
     60 #include "mpreal.h"
     61 
     62 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
     63 #include "dlmalloc.h"
     64 #endif
     65 
     66 using std::ws;
     67 using std::cerr;
     68 using std::endl;
     69 using std::string;
     70 using std::ostream;
     71 using std::istream;
     72 
     73 namespace mpfr{
     74 
     75 mp_rnd_t   mpreal::default_rnd  = MPFR_RNDN;	//(mpfr_get_default_rounding_mode)();
     76 mp_prec_t  mpreal::default_prec = 64;			//(mpfr_get_default_prec)();
     77 int		   mpreal::default_base = 10;
     78 int        mpreal::double_bits = -1;
     79 
     80 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
     81 bool       mpreal::is_custom_malloc = false;
     82 #endif
     83 
     84 // Default constructor: creates mp number and initializes it to 0.
     85 mpreal::mpreal()
     86 {
     87 
     88 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
     89 	set_custom_malloc();
     90 #endif
     91 
     92 	mpfr_init2(mp,default_prec);
     93 	mpfr_set_ui(mp,0,default_rnd);
     94 
     95 	MPREAL_MSVC_DEBUGVIEW_CODE;
     96 }
     97 
     98 mpreal::mpreal(const mpreal& u)
     99 {
    100 
    101 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
    102 	set_custom_malloc();
    103 #endif
    104 
    105 	mpfr_init2(mp,mpfr_get_prec(u.mp));
    106 	mpfr_set(mp,u.mp,default_rnd);
    107 
    108 	MPREAL_MSVC_DEBUGVIEW_CODE;
    109 }
    110 
    111 mpreal::mpreal(const mpfr_t u)
    112 {
    113 
    114 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
    115 	set_custom_malloc();
    116 #endif
    117 
    118 	mpfr_init2(mp,mpfr_get_prec(u));
    119 	mpfr_set(mp,u,default_rnd);
    120 
    121 	MPREAL_MSVC_DEBUGVIEW_CODE;
    122 }
    123 
    124 mpreal::mpreal(const mpf_t u)
    125 {
    126 
    127 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
    128 	set_custom_malloc();
    129 #endif
    130 
    131 	mpfr_init2(mp,(mp_prec_t) mpf_get_prec(u)); // (gmp: mp_bitcnt_t) unsigned long -> long (mpfr: mp_prec_t)
    132 	mpfr_set_f(mp,u,default_rnd);
    133 
    134 	MPREAL_MSVC_DEBUGVIEW_CODE;
    135 }
    136 
    137 mpreal::mpreal(const mpz_t u, mp_prec_t prec, mp_rnd_t mode)
    138 {
    139 
    140 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
    141 	set_custom_malloc();
    142 #endif
    143 
    144 	mpfr_init2(mp,prec);
    145 	mpfr_set_z(mp,u,mode);
    146 
    147 	MPREAL_MSVC_DEBUGVIEW_CODE;
    148 }
    149 
    150 mpreal::mpreal(const mpq_t u, mp_prec_t prec, mp_rnd_t mode)
    151 {
    152 
    153 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
    154 	set_custom_malloc();
    155 #endif
    156 
    157 	mpfr_init2(mp,prec);
    158 	mpfr_set_q(mp,u,mode);
    159 
    160 	MPREAL_MSVC_DEBUGVIEW_CODE;
    161 }
    162 
    163 mpreal::mpreal(const double u, mp_prec_t prec, mp_rnd_t mode)
    164 {
    165 
    166 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
    167 	set_custom_malloc();
    168 #endif
    169 
    170     if(double_bits == -1 || fits_in_bits(u, double_bits))
    171     {
    172     	mpfr_init2(mp,prec);
    173 	    mpfr_set_d(mp,u,mode);
    174 
    175 		MPREAL_MSVC_DEBUGVIEW_CODE;
    176     }
    177     else
    178         throw conversion_overflow();
    179 }
    180 
    181 mpreal::mpreal(const long double u, mp_prec_t prec, mp_rnd_t mode)
    182 {
    183 
    184 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
    185 	set_custom_malloc();
    186 #endif
    187 
    188     mpfr_init2(mp,prec);
    189 	mpfr_set_ld(mp,u,mode);
    190 
    191 	MPREAL_MSVC_DEBUGVIEW_CODE;
    192 }
    193 
    194 mpreal::mpreal(const unsigned long int u, mp_prec_t prec, mp_rnd_t mode)
    195 {
    196 
    197 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
    198 	set_custom_malloc();
    199 #endif
    200 
    201 	mpfr_init2(mp,prec);
    202 	mpfr_set_ui(mp,u,mode);
    203 
    204 	MPREAL_MSVC_DEBUGVIEW_CODE;
    205 }
    206 
    207 mpreal::mpreal(const unsigned int u, mp_prec_t prec, mp_rnd_t mode)
    208 {
    209 
    210 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
    211 	set_custom_malloc();
    212 #endif
    213 
    214 	mpfr_init2(mp,prec);
    215 	mpfr_set_ui(mp,u,mode);
    216 
    217 	MPREAL_MSVC_DEBUGVIEW_CODE;
    218 }
    219 
    220 mpreal::mpreal(const long int u, mp_prec_t prec, mp_rnd_t mode)
    221 {
    222 
    223 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
    224 	set_custom_malloc();
    225 #endif
    226 
    227 	mpfr_init2(mp,prec);
    228 	mpfr_set_si(mp,u,mode);
    229 
    230 	MPREAL_MSVC_DEBUGVIEW_CODE;
    231 }
    232 
    233 mpreal::mpreal(const int u, mp_prec_t prec, mp_rnd_t mode)
    234 {
    235 
    236 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
    237 	set_custom_malloc();
    238 #endif
    239 
    240 	mpfr_init2(mp,prec);
    241 	mpfr_set_si(mp,u,mode);
    242 
    243 	MPREAL_MSVC_DEBUGVIEW_CODE;
    244 }
    245 
    246 #if defined (MPREAL_HAVE_INT64_SUPPORT)
    247 mpreal::mpreal(const uint64_t u, mp_prec_t prec, mp_rnd_t mode)
    248 {
    249 
    250 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
    251 	set_custom_malloc();
    252 #endif
    253 
    254 	mpfr_init2(mp,prec);
    255 	mpfr_set_uj(mp, u, mode);
    256 
    257 	MPREAL_MSVC_DEBUGVIEW_CODE;
    258 }
    259 
    260 mpreal::mpreal(const int64_t u, mp_prec_t prec, mp_rnd_t mode)
    261 {
    262 
    263 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
    264 	set_custom_malloc();
    265 #endif
    266 
    267 	mpfr_init2(mp,prec);
    268 	mpfr_set_sj(mp, u, mode);
    269 
    270 	MPREAL_MSVC_DEBUGVIEW_CODE;
    271 }
    272 #endif
    273 
    274 mpreal::mpreal(const char* s, mp_prec_t prec, int base, mp_rnd_t mode)
    275 {
    276 
    277 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
    278 	set_custom_malloc();
    279 #endif
    280 
    281 	mpfr_init2(mp,prec);
    282 	mpfr_set_str(mp, s, base, mode);
    283 
    284 	MPREAL_MSVC_DEBUGVIEW_CODE;
    285 }
    286 
    287 mpreal::mpreal(const std::string& s, mp_prec_t prec, int base, mp_rnd_t mode)
    288 {
    289 
    290 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
    291 	set_custom_malloc();
    292 #endif
    293 
    294 	mpfr_init2(mp,prec);
    295 	mpfr_set_str(mp, s.c_str(), base, mode);
    296 
    297 	MPREAL_MSVC_DEBUGVIEW_CODE;
    298 }
    299 
    300 mpreal::~mpreal()
    301 {
    302 	mpfr_clear(mp);
    303 }
    304 
    305 // Operators - Assignment
    306 mpreal& mpreal::operator=(const char* s)
    307 {
    308 	mpfr_t t;
    309 
    310 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
    311 	set_custom_malloc();
    312 #endif
    313 
    314 	if(0==mpfr_init_set_str(t,s,default_base,default_rnd))
    315 	{
    316 		// We will rewrite mp anyway, so flash it and resize
    317 		mpfr_set_prec(mp,mpfr_get_prec(t));
    318 		mpfr_set(mp,t,mpreal::default_rnd);
    319 		mpfr_clear(t);
    320 
    321 		MPREAL_MSVC_DEBUGVIEW_CODE;
    322 
    323 	}else{
    324 		mpfr_clear(t);
    325 	}
    326 
    327 	return *this;
    328 }
    329 
    330 const mpreal fma (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode)
    331 {
    332 	mpreal a;
    333 	mp_prec_t p1, p2, p3;
    334 
    335 	p1 = v1.get_prec();
    336 	p2 = v2.get_prec();
    337 	p3 = v3.get_prec();
    338 
    339 	a.set_prec(p3>p2?(p3>p1?p3:p1):(p2>p1?p2:p1));
    340 
    341 	mpfr_fma(a.mp,v1.mp,v2.mp,v3.mp,rnd_mode);
    342 	return a;
    343 }
    344 
    345 const mpreal fms (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode)
    346 {
    347 	mpreal a;
    348 	mp_prec_t p1, p2, p3;
    349 
    350 	p1 = v1.get_prec();
    351 	p2 = v2.get_prec();
    352 	p3 = v3.get_prec();
    353 
    354 	a.set_prec(p3>p2?(p3>p1?p3:p1):(p2>p1?p2:p1));
    355 
    356 	mpfr_fms(a.mp,v1.mp,v2.mp,v3.mp,rnd_mode);
    357 	return a;
    358 }
    359 
    360 const mpreal agm (const mpreal& v1, const mpreal& v2, mp_rnd_t rnd_mode)
    361 {
    362 	mpreal a;
    363 	mp_prec_t p1, p2;
    364 
    365 	p1 = v1.get_prec();
    366 	p2 = v2.get_prec();
    367 
    368 	a.set_prec(p1>p2?p1:p2);
    369 
    370 	mpfr_agm(a.mp, v1.mp, v2.mp, rnd_mode);
    371 
    372 	return a;
    373 }
    374 
    375 const mpreal sum (const mpreal tab[], unsigned long int n, mp_rnd_t rnd_mode)
    376 {
    377 	mpreal x;
    378 	mpfr_ptr* t;
    379 	unsigned long int i;
    380 
    381 	t = new mpfr_ptr[n];
    382 	for (i=0;i<n;i++) t[i] = (mpfr_ptr)tab[i].mp;
    383 	mpfr_sum(x.mp,t,n,rnd_mode);
    384 	delete[] t;
    385 	return x;
    386 }
    387 
    388 const mpreal remquo (long* q, const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode)
    389 {
    390 	mpreal a;
    391 	mp_prec_t yp, xp;
    392 
    393 	yp = y.get_prec();
    394 	xp = x.get_prec();
    395 
    396 	a.set_prec(yp>xp?yp:xp);
    397 
    398 	mpfr_remquo(a.mp,q, x.mp, y.mp, rnd_mode);
    399 
    400 	return a;
    401 }
    402 
    403 template <class T>
    404 std::string toString(T t, std::ios_base & (*f)(std::ios_base&))
    405 {
    406 	std::ostringstream oss;
    407 	oss << f << t;
    408 	return oss.str();
    409 }
    410 
    411 #if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0))
    412 
    413 std::string mpreal::toString(const std::string& format) const
    414 {
    415 	char *s = NULL;
    416 	string out;
    417 
    418 	if( !format.empty() )
    419 	{
    420 		if(!(mpfr_asprintf(&s,format.c_str(),mp) < 0))
    421 		{
    422 			out = std::string(s);
    423 
    424 			mpfr_free_str(s);
    425 		}
    426 	}
    427 
    428 	return out;
    429 }
    430 
    431 #endif
    432 
    433 std::string mpreal::toString(int n, int b, mp_rnd_t mode) const
    434 {
    435   (void)b;
    436   (void)mode;
    437 #if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0))
    438 
    439 	// Use MPFR native function for output
    440 	char format[128];
    441 	int digits;
    442 
    443 	digits = n > 0 ? n : bits2digits(mpfr_get_prec(mp));
    444 
    445 	sprintf(format,"%%.%dRNg",digits);		// Default format
    446 
    447 	return toString(std::string(format));
    448 
    449 #else
    450 
    451 	char *s, *ns = NULL;
    452 	size_t slen, nslen;
    453 	mp_exp_t exp;
    454 	string out;
    455 
    456 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
    457 	set_custom_malloc();
    458 #endif
    459 
    460 	if(mpfr_inf_p(mp))
    461 	{
    462 		if(mpfr_sgn(mp)>0) return "+Inf";
    463 		else			   return "-Inf";
    464 	}
    465 
    466 	if(mpfr_zero_p(mp)) return "0";
    467 	if(mpfr_nan_p(mp))  return "NaN";
    468 
    469 	s  = mpfr_get_str(NULL,&exp,b,0,mp,mode);
    470 	ns = mpfr_get_str(NULL,&exp,b,n,mp,mode);
    471 
    472 	if(s!=NULL && ns!=NULL)
    473 	{
    474 		slen  = strlen(s);
    475 		nslen = strlen(ns);
    476 		if(nslen<=slen)
    477 		{
    478 			mpfr_free_str(s);
    479 			s = ns;
    480 			slen = nslen;
    481 		}
    482 		else {
    483 			mpfr_free_str(ns);
    484 		}
    485 
    486 		// Make human eye-friendly formatting if possible
    487 		if (exp>0 && static_cast<size_t>(exp)<slen)
    488 		{
    489 			if(s[0]=='-')
    490 			{
    491 				// Remove zeros starting from right end
    492 				char* ptr = s+slen-1;
    493 				while (*ptr=='0' && ptr>s+exp) ptr--;
    494 
    495 				if(ptr==s+exp) out = string(s,exp+1);
    496 				else		   out = string(s,exp+1)+'.'+string(s+exp+1,ptr-(s+exp+1)+1);
    497 
    498 				//out = string(s,exp+1)+'.'+string(s+exp+1);
    499 			}
    500 			else
    501 			{
    502 				// Remove zeros starting from right end
    503 				char* ptr = s+slen-1;
    504 				while (*ptr=='0' && ptr>s+exp-1) ptr--;
    505 
    506 				if(ptr==s+exp-1) out = string(s,exp);
    507 				else		     out = string(s,exp)+'.'+string(s+exp,ptr-(s+exp)+1);
    508 
    509 				//out = string(s,exp)+'.'+string(s+exp);
    510 			}
    511 
    512 		}else{ // exp<0 || exp>slen
    513 			if(s[0]=='-')
    514 			{
    515 				// Remove zeros starting from right end
    516 				char* ptr = s+slen-1;
    517 				while (*ptr=='0' && ptr>s+1) ptr--;
    518 
    519 				if(ptr==s+1) out = string(s,2);
    520 				else		 out = string(s,2)+'.'+string(s+2,ptr-(s+2)+1);
    521 
    522 				//out = string(s,2)+'.'+string(s+2);
    523 			}
    524 			else
    525 			{
    526 				// Remove zeros starting from right end
    527 				char* ptr = s+slen-1;
    528 				while (*ptr=='0' && ptr>s) ptr--;
    529 
    530 				if(ptr==s) out = string(s,1);
    531 				else	   out = string(s,1)+'.'+string(s+1,ptr-(s+1)+1);
    532 
    533 				//out = string(s,1)+'.'+string(s+1);
    534 			}
    535 
    536 			// Make final string
    537 			if(--exp)
    538 			{
    539 				if(exp>0) out += "e+"+mpfr::toString<mp_exp_t>(exp,std::dec);
    540 				else 	  out += "e"+mpfr::toString<mp_exp_t>(exp,std::dec);
    541 			}
    542 		}
    543 
    544 		mpfr_free_str(s);
    545 		return out;
    546 	}else{
    547 		return "conversion error!";
    548 	}
    549 #endif
    550 }
    551 
    552 
    553 //////////////////////////////////////////////////////////////////////////
    554 // I/O
    555 ostream& operator<<(ostream& os, const mpreal& v)
    556 {
    557 	return os<<v.toString(static_cast<int>(os.precision()));
    558 }
    559 
    560 istream& operator>>(istream &is, mpreal& v)
    561 {
    562 	string tmp;
    563 	is >> tmp;
    564 	mpfr_set_str(v.mp, tmp.c_str(),mpreal::default_base,mpreal::default_rnd);
    565 	return is;
    566 }
    567 
    568 
    569 #if defined (MPREAL_HAVE_CUSTOM_MPFR_MALLOC)
    570 	// Optimized dynamic memory allocation/(re-)deallocation.
    571 	void * mpreal::mpreal_allocate(size_t alloc_size)
    572 	{
    573 		return(dlmalloc(alloc_size));
    574 	}
    575 
    576 	void * mpreal::mpreal_reallocate(void *ptr, size_t old_size, size_t new_size)
    577 	{
    578 		return(dlrealloc(ptr,new_size));
    579 	}
    580 
    581 	void mpreal::mpreal_free(void *ptr, size_t size)
    582 	{
    583 		dlfree(ptr);
    584 	}
    585 
    586 	inline void mpreal::set_custom_malloc(void)
    587 	{
    588 		if(!is_custom_malloc)
    589 		{
    590 			mp_set_memory_functions(mpreal_allocate,mpreal_reallocate,mpreal_free);
    591 			is_custom_malloc = true;
    592 		}
    593 	}
    594 #endif
    595 
    596 }
    597 
    598