summaryrefslogtreecommitdiff
path: root/Build/source/libs/mpfr/mpfr-src/src/cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/mpfr/mpfr-src/src/cache.c')
-rw-r--r--Build/source/libs/mpfr/mpfr-src/src/cache.c75
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);
}