summaryrefslogtreecommitdiff
path: root/get_ld.c
diff options
context:
space:
mode:
authorpelissip <pelissip@280ebfd0-de03-0410-8827-d642c229c3f4>2004-12-17 11:13:53 +0000
committerpelissip <pelissip@280ebfd0-de03-0410-8827-d642c229c3f4>2004-12-17 11:13:53 +0000
commit20b84c32281fdbce91e97ed6977d4140e30e8078 (patch)
tree4322cca1061a07378af9fdc6f28b57455dec305c /get_ld.c
parent633ff961963dc69d40209c2066d39de37ba23fcc (diff)
downloadmpfr-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.c70
1 files changed, 29 insertions, 41 deletions
diff --git a/get_ld.c b/get_ld.c
index 459406e15..fed1d56d6 100644
--- a/get_ld.c
+++ b/get_ld.c
@@ -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;
}
-
}