diff options
Diffstat (limited to 'Build/source/libs/mpfr/mpfr-src/src/cache.c')
-rw-r--r-- | Build/source/libs/mpfr/mpfr-src/src/cache.c | 75 |
1 files changed, 60 insertions, 15 deletions
diff --git a/Build/source/libs/mpfr/mpfr-src/src/cache.c b/Build/source/libs/mpfr/mpfr-src/src/cache.c index 9c5b73f8dfb..a48de9967ba 100644 --- a/Build/source/libs/mpfr/mpfr-src/src/cache.c +++ b/Build/source/libs/mpfr/mpfr-src/src/cache.c @@ -37,37 +37,76 @@ mpfr_init_cache (mpfr_cache_t cache, int (*func)(mpfr_ptr, mpfr_rnd_t)) void mpfr_clear_cache (mpfr_cache_t cache) { - if (MPFR_PREC (cache->x) != 0) - mpfr_clear (cache->x); - MPFR_PREC (cache->x) = 0; + if (MPFR_UNLIKELY (MPFR_PREC (cache->x) != 0)) + { + /* Get the cache in read-write mode */ + MPFR_LOCK_WRITE(cache->lock); + + if (MPFR_LIKELY (MPFR_PREC (cache->x) != 0)) + { + mpfr_clear (cache->x); + MPFR_PREC (cache->x) = 0; + } + + /* Free the cache in read-write mode */ + MPFR_UNLOCK_WRITE(cache->lock); + } } int mpfr_cache (mpfr_ptr dest, mpfr_cache_t cache, mpfr_rnd_t rnd) { mpfr_prec_t prec = MPFR_PREC (dest); - mpfr_prec_t pold = MPFR_PREC (cache->x); + mpfr_prec_t pold; int inexact, sign; MPFR_SAVE_EXPO_DECL (expo); + /* Call the initialisation function of the cache if it's needed */ + MPFR_DEFERRED_INIT_CALL(cache); + MPFR_SAVE_EXPO_MARK (expo); + /* Get the cache in read-only mode */ + MPFR_LOCK_READ(cache->lock); + /* Read the precision within the cache */ + pold = MPFR_PREC (cache->x); if (MPFR_UNLIKELY (prec > pold)) { - /* No previous result in the cache or the precision of the - previous result is not sufficient. */ - - if (MPFR_UNLIKELY (pold == 0)) /* No previous result. */ - mpfr_init2 (cache->x, prec); + /* Free the cache in read-only mode */ + /* And get the cache in read-write mode */ + MPFR_LOCK_READ2WRITE(cache->lock); + + /* Retest the precision once we get the lock. + If there is no lock, there is no harm in this code */ + pold = MPFR_PREC (cache->x); + if (MPFR_LIKELY (prec > pold)) + { + /* No previous result in the cache or the precision of the previous + result is not sufficient. We increase the cache size by at least + 10% to avoid invalidating the cache many times if one performs + several computations with small increase of precision. */ + if (MPFR_UNLIKELY (pold == 0)) /* No previous result. */ + mpfr_init2 (cache->x, prec); /* as pold = prec below */ + else + pold += pold / 10; + + /* Update the cache. */ + if (pold < prec) + pold = prec; + + /* no need to keep the previous value */ + mpfr_set_prec (cache->x, pold); + cache->inexact = (*cache->func) (cache->x, MPFR_RNDN); + } - /* Update the cache. */ - pold = prec; - /* no need to keep the previous value */ - mpfr_set_prec (cache->x, pold); - cache->inexact = (*cache->func) (cache->x, MPFR_RNDN); + /* Free the cache in read-write mode */ + /* Get the cache in read-only mode */ + MPFR_LOCK_WRITE2READ(cache->lock); } /* now pold >= prec is the precision of cache->x */ + MPFR_ASSERTD (pold >= prec); + MPFR_ASSERTD (MPFR_PREC (cache->x) == pold); /* First, check if the cache has the exact value (unlikely). Else the exact value is between (assuming x=cache->x > 0): @@ -78,7 +117,7 @@ mpfr_cache (mpfr_ptr dest, mpfr_cache_t cache, mpfr_rnd_t rnd) /* we assume all cached constants are positive */ MPFR_ASSERTN (MPFR_IS_POS (cache->x)); /* TODO... */ sign = MPFR_SIGN (cache->x); - MPFR_SET_EXP (dest, MPFR_GET_EXP (cache->x)); + MPFR_EXP (dest) = MPFR_GET_EXP (cache->x); MPFR_SET_SIGN (dest, sign); /* round cache->x from precision pold down to precision prec */ @@ -105,6 +144,8 @@ mpfr_cache (mpfr_ptr dest, mpfr_cache_t cache, mpfr_rnd_t rnd) mpfr_overflow (dest, rnd, sign); ); + /* Rather a likely, this is a 100% succes rate for + all constants of MPFR */ if (MPFR_LIKELY (cache->inexact != 0)) { switch (rnd) @@ -141,5 +182,9 @@ mpfr_cache (mpfr_ptr dest, mpfr_cache_t cache, mpfr_rnd_t rnd) } MPFR_SAVE_EXPO_FREE (expo); + + /* Free the cache in read-only mode */ + MPFR_UNLOCK_READ(cache->lock); + return mpfr_check_range (dest, inexact, rnd); } |