diff options
author | pelissip <pelissip@280ebfd0-de03-0410-8827-d642c229c3f4> | 2004-12-17 11:13:53 +0000 |
---|---|---|
committer | pelissip <pelissip@280ebfd0-de03-0410-8827-d642c229c3f4> | 2004-12-17 11:13:53 +0000 |
commit | 20b84c32281fdbce91e97ed6977d4140e30e8078 (patch) | |
tree | 4322cca1061a07378af9fdc6f28b57455dec305c /get_ld.c | |
parent | 633ff961963dc69d40209c2066d39de37ba23fcc (diff) | |
download | mpfr-20b84c32281fdbce91e97ed6977d4140e30e8078.tar.gz |
Fix problem with long double with ICC (Wrong x86 processor flag).
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@3148 280ebfd0-de03-0410-8827-d642c229c3f4
Diffstat (limited to 'get_ld.c')
-rw-r--r-- | get_ld.c | 70 |
1 files changed, 29 insertions, 41 deletions
@@ -29,59 +29,51 @@ long double mpfr_get_ld (mpfr_srcptr x, mp_rnd_t rnd_mode) { - if (!mpfr_number_p (x)) /* NaN or Inf: check before 0.0 */ - { - return (long double) mpfr_get_d (x, rnd_mode); - } - else if (MPFR_IS_ZERO(x)) - { - return MPFR_SIGN(x) < 0 ? -0.0 : 0.0; - } + if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x))) + return (long double) mpfr_get_d (x, rnd_mode); else /* now x is a normal non-zero number */ { long double r; /* result */ long double m; double s; /* part of result */ - mp_exp_t e; /* exponent of x */ mp_exp_t sh; /* exponent shift, so that x/2^sh is in the double range */ mpfr_t y, z; + int sign; /* first round x to the target long double precision, so that all subsequent operations are exact (this avoids double rounding problems) */ mpfr_init2 (y, MPFR_LDBL_MANT_DIG); + mpfr_init2 (z, IEEE_DBL_MANT_DIG); + mpfr_set (y, x, rnd_mode); - e = MPFR_GET_EXP (y); - if (e > 1023) - { - sh = e - 1023; - MPFR_SET_EXP (y, 1023); - } - else if (e < -1021) - { - sh = e + 1021; - MPFR_SET_EXP (y, -1021); - } - else - { - sh = 0; - } - /* now -1021 <= e - sh = EXP(y) <= 1023 */ + sh = MPFR_GET_EXP (y); + sign = MPFR_SIGN (y); + MPFR_SET_EXP (y, 0); + MPFR_SET_POS (y); + r = 0.0; - mpfr_init2 (z, IEEE_DBL_MANT_DIG); + do { + s = mpfr_get_d (y, GMP_RNDN); /* high part of y */ + r += (long double) s; + mpfr_set_d (z, s, GMP_RNDN); /* exact */ + mpfr_sub (y, y, z, GMP_RNDN); /* exact */ + } while (!MPFR_IS_ZERO (y)); - do - { - s = mpfr_get_d (y, GMP_RNDN); /* high part of y */ - r += (long double) s; - mpfr_set_d (z, s, rnd_mode); /* exact */ - mpfr_sub (y, y, z, rnd_mode); /* exact */ - } - while (MPFR_NOTZERO(y)); + mpfr_clear (z); + mpfr_clear (y); /* we now have to multiply back by 2^sh */ + MPFR_ASSERTD (r > 0); if (sh != 0) { + /* An overflow may occurs (example: 0.5*2^1024) */ + while (r < 1.0) + { + r += r; + sh--; + } + if (sh > 0) m = 2.0; else @@ -89,7 +81,7 @@ mpfr_get_ld (mpfr_srcptr x, mp_rnd_t rnd_mode) m = 0.5; sh = -sh; } - e = 1; /* invariant: m = 2^e */ + for (;;) { if (sh % 2) @@ -98,14 +90,10 @@ mpfr_get_ld (mpfr_srcptr x, mp_rnd_t rnd_mode) if (sh == 0) break; m = m * m; - e = e + e; } } - - mpfr_clear (z); - mpfr_clear (y); - + if (sign < 0) + r = -r; return r; } - } |