1/* mpfr_cache -- cache interface for multiple-precision constants in MPFR. 2 3Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. 4Contributed by the AriC and Caramel projects, INRIA. 5 6This file is part of the GNU MPFR Library. 7 8The GNU MPFR Library is free software; you can redistribute it and/or modify 9it under the terms of the GNU Lesser General Public License as published by 10the Free Software Foundation; either version 3 of the License, or (at your 11option) any later version. 12 13The GNU MPFR Library is distributed in the hope that it will be useful, but 14WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 16License for more details. 17 18You should have received a copy of the GNU Lesser General Public License 19along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see 20http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., 2151 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ 22 23#include "mpfr-impl.h" 24 25#if 0 /* this function is not used/documented/tested so far, it could be 26 useful if some user wants to add a new constant to mpfr, and 27 implement a cache mechanism for that constant */ 28void 29mpfr_init_cache (mpfr_cache_t cache, int (*func)(mpfr_ptr, mpfr_rnd_t)) 30{ 31 MPFR_PREC (cache->x) = 0; /* Invalid prec to detect that the cache is not 32 valid. Maybe add a flag? */ 33 cache->func = func; 34} 35#endif 36 37void 38mpfr_clear_cache (mpfr_cache_t cache) 39{ 40 if (MPFR_PREC (cache->x) != 0) 41 mpfr_clear (cache->x); 42 MPFR_PREC (cache->x) = 0; 43} 44 45int 46mpfr_cache (mpfr_ptr dest, mpfr_cache_t cache, mpfr_rnd_t rnd) 47{ 48 mpfr_prec_t prec = MPFR_PREC (dest); 49 mpfr_prec_t pold = MPFR_PREC (cache->x); 50 int inexact, sign; 51 MPFR_SAVE_EXPO_DECL (expo); 52 53 MPFR_SAVE_EXPO_MARK (expo); 54 55 if (MPFR_UNLIKELY (prec > pold)) 56 { 57 /* No previous result in the cache or the precision of the 58 previous result is not sufficient. */ 59 60 if (MPFR_UNLIKELY (pold == 0)) /* No previous result. */ 61 mpfr_init2 (cache->x, prec); 62 63 /* Update the cache. */ 64 pold = prec; 65 /* no need to keep the previous value */ 66 mpfr_set_prec (cache->x, pold); 67 cache->inexact = (*cache->func) (cache->x, MPFR_RNDN); 68 } 69 70 /* now pold >= prec is the precision of cache->x */ 71 72 /* First, check if the cache has the exact value (unlikely). 73 Else the exact value is between (assuming x=cache->x > 0): 74 x and x+ulp(x) if cache->inexact < 0, 75 x-ulp(x) and x if cache->inexact > 0, 76 and abs(x-exact) <= ulp(x)/2. */ 77 78 /* we assume all cached constants are positive */ 79 MPFR_ASSERTN (MPFR_IS_POS (cache->x)); /* TODO... */ 80 sign = MPFR_SIGN (cache->x); 81 MPFR_SET_EXP (dest, MPFR_GET_EXP (cache->x)); 82 MPFR_SET_SIGN (dest, sign); 83 84 /* round cache->x from precision pold down to precision prec */ 85 MPFR_RNDRAW_GEN (inexact, dest, 86 MPFR_MANT (cache->x), pold, rnd, sign, 87 if (MPFR_UNLIKELY (cache->inexact == 0)) 88 { 89 if ((_sp[0] & _ulp) == 0) 90 { 91 inexact = -sign; 92 goto trunc_doit; 93 } 94 else 95 goto addoneulp; 96 } 97 else if (cache->inexact < 0) 98 goto addoneulp; 99 else /* cache->inexact > 0 */ 100 { 101 inexact = -sign; 102 goto trunc_doit; 103 }, 104 if (MPFR_UNLIKELY (++MPFR_EXP (dest) > __gmpfr_emax)) 105 mpfr_overflow (dest, rnd, sign); 106 ); 107 108 if (MPFR_LIKELY (cache->inexact != 0)) 109 { 110 switch (rnd) 111 { 112 case MPFR_RNDZ: 113 case MPFR_RNDD: 114 if (MPFR_UNLIKELY (inexact == 0)) 115 { 116 inexact = cache->inexact; 117 if (inexact > 0) 118 { 119 mpfr_nextbelow (dest); 120 inexact = -inexact; 121 } 122 } 123 break; 124 case MPFR_RNDU: 125 case MPFR_RNDA: 126 if (MPFR_UNLIKELY (inexact == 0)) 127 { 128 inexact = cache->inexact; 129 if (inexact < 0) 130 { 131 mpfr_nextabove (dest); 132 inexact = -inexact; 133 } 134 } 135 break; 136 default: /* MPFR_RNDN */ 137 if (MPFR_UNLIKELY(inexact == 0)) 138 inexact = cache->inexact; 139 break; 140 } 141 } 142 143 MPFR_SAVE_EXPO_FREE (expo); 144 return mpfr_check_range (dest, inexact, rnd); 145} 146