1/* mpz_set_d(integer, val) -- Assign INTEGER with a double value VAL.
2
3Copyright 1995, 1996, 2000, 2001, 2002, 2003, 2006 Free Software Foundation,
4Inc.
5
6This file is part of the GNU MP Library.
7
8The GNU MP Library is free software; you can redistribute it and/or modify
9it under the terms of the GNU Lesser General Public License as published by
10the Free Software Foundation; either version 3 of the License, or (at your
11option) any later version.
12
13The GNU MP Library is distributed in the hope that it will be useful, but
14WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16License for more details.
17
18You should have received a copy of the GNU Lesser General Public License
19along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
20
21#include "config.h"
22
23#if HAVE_FLOAT_H
24#include <float.h>  /* for DBL_MAX */
25#endif
26
27#include "gmp.h"
28#include "gmp-impl.h"
29
30
31/* We used to have a special case for d < MP_BASE_AS_DOUBLE, just casting
32   double -> limb.  Unfortunately gcc 3.3 on powerpc970-apple-darwin6.8.5
33   got this wrong.  (It assumed __fixunsdfdi returned its result in a single
34   64-bit register, where instead that function followed the calling
35   conventions and gave the result in two parts r3 and r4.)  Hence the use
36   of __gmp_extract_double in all cases.  */
37
38void
39mpz_set_d (mpz_ptr r, double d)
40{
41  int negative;
42  mp_limb_t tp[LIMBS_PER_DOUBLE];
43  mp_ptr rp;
44  mp_size_t rn;
45
46  DOUBLE_NAN_INF_ACTION (d,
47                         __gmp_invalid_operation (),
48                         __gmp_invalid_operation ());
49
50  negative = d < 0;
51  d = ABS (d);
52
53  rn = __gmp_extract_double (tp, d);
54
55  if (ALLOC(r) < rn)
56    _mpz_realloc (r, rn);
57
58  if (rn <= 0)
59    rn = 0;
60
61  rp = PTR (r);
62
63  switch (rn)
64    {
65    default:
66      MPN_ZERO (rp, rn - LIMBS_PER_DOUBLE);
67      rp += rn - LIMBS_PER_DOUBLE;
68      /* fall through */
69#if LIMBS_PER_DOUBLE == 2
70    case 2:
71      rp[1] = tp[1], rp[0] = tp[0];
72      break;
73    case 1:
74      rp[0] = tp[1];
75      break;
76#endif
77#if LIMBS_PER_DOUBLE == 3
78    case 3:
79      rp[2] = tp[2], rp[1] = tp[1], rp[0] = tp[0];
80      break;
81    case 2:
82      rp[1] = tp[2], rp[0] = tp[1];
83      break;
84    case 1:
85      rp[0] = tp[2];
86      break;
87#endif
88#if LIMBS_PER_DOUBLE == 4
89    case 4:
90      rp[3] = tp[3], rp[2] = tp[2], rp[1] = tp[1], rp[0] = tp[0];
91      break;
92    case 3:
93      rp[2] = tp[3], rp[1] = tp[2], rp[0] = tp[1];
94      break;
95    case 2:
96      rp[1] = tp[3], rp[0] = tp[2];
97      break;
98    case 1:
99      rp[0] = tp[3];
100      break;
101#endif
102    case 0:
103      break;
104    }
105
106  SIZ(r) = negative ? -rn : rn;
107}
108