FIX BUILD (with GHC 6.2.x): System.Directory.Internals is no more
[ghc-hetmet.git] / rts / gmp / mpz / get_d.c
1 /* double mpz_get_d (mpz_t src) -- Return the double approximation to SRC.
2
3 Copyright (C) 1996, 1997, 2000 Free Software Foundation, Inc.
4
5 This file is part of the GNU MP Library.
6
7 The GNU MP Library is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or (at your
10 option) any later version.
11
12 The GNU MP Library is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15 License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 MA 02111-1307, USA. */
21
22 #include "gmp.h"
23 #include "gmp-impl.h"
24 #include "longlong.h"
25
26
27 static int
28 #if __STDC__
29 mpn_zero_p (mp_ptr p, mp_size_t n)
30 #else
31 mpn_zero_p (p, n)
32      mp_ptr p;
33      mp_size_t n;
34 #endif
35 {
36   mp_size_t i;
37
38   for (i = 0; i < n; i++)
39     {
40       if (p[i] != 0)
41         return 0;
42     }
43
44   return 1;
45 }
46
47
48 double
49 #if __STDC__
50 mpz_get_d (mpz_srcptr src)
51 #else
52 mpz_get_d (src)
53      mpz_srcptr src;
54 #endif
55 {
56   double res;
57   mp_size_t size;
58   int negative;
59   mp_ptr qp;
60   mp_limb_t hz, lz;
61   int cnt;
62
63   size = SIZ(src);
64   if (size == 0)
65     return 0.0;
66
67   negative = size < 0;
68   size = ABS (size);
69   qp = PTR(src);
70
71   if (size == 1)
72     {
73       res = qp[size - 1];
74     }
75   else if (size == 2)
76     {
77       res = MP_BASE_AS_DOUBLE * qp[size - 1] + qp[size - 2];
78     }
79   else
80     {
81       count_leading_zeros (cnt, qp[size - 1]);
82
83 #if BITS_PER_MP_LIMB == 32
84       if (cnt == 0)
85         {
86           hz = qp[size - 1];
87           lz = qp[size - 2];
88         }
89       else
90         {
91           hz = (qp[size - 1] << cnt) | (qp[size - 2] >> BITS_PER_MP_LIMB - cnt);
92           lz = (qp[size - 2] << cnt) | (qp[size - 3] >> BITS_PER_MP_LIMB - cnt);
93         }
94 #if _GMP_IEEE_FLOATS
95       /* Take bits from less significant limbs, but only if they may affect
96          the result.  */
97       if ((lz & 0x7ff) == 0x400)
98         {
99           if (cnt != 0)
100             lz += ((qp[size - 3] << cnt) != 0 || ! mpn_zero_p (qp, size - 3));
101           else
102             lz += (! mpn_zero_p (qp, size - 2));
103         }
104 #endif
105       res = MP_BASE_AS_DOUBLE * hz + lz;
106       res = __gmp_scale2 (res, (size - 2) * BITS_PER_MP_LIMB - cnt);
107 #endif
108 #if BITS_PER_MP_LIMB == 64
109       if (cnt == 0)
110         hz = qp[size - 1];
111       else
112         hz = (qp[size - 1] << cnt) | (qp[size - 2] >> BITS_PER_MP_LIMB - cnt);
113 #if _GMP_IEEE_FLOATS
114       if ((hz & 0x7ff) == 0x400)
115         {
116           if (cnt != 0)
117             hz += ((qp[size - 2] << cnt) != 0 || ! mpn_zero_p (qp, size - 2));
118           else
119             hz += (! mpn_zero_p (qp, size - 1));
120         }
121 #endif
122       res = hz;
123       res = __gmp_scale2 (res, (size - 1) * BITS_PER_MP_LIMB - cnt);
124 #endif
125     }
126
127   return negative ? -res : res;
128 }