1/* mpf_ui_div -- Divide an unsigned integer with a float.
2
3Copyright 1993, 1994, 1995, 1996, 2000, 2001, 2002, 2004, 2005 Free Software
4Foundation, Inc.
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 <stdio.h>  /* for NULL */
22#include "gmp.h"
23#include "gmp-impl.h"
24#include "longlong.h"
25
26
27void
28mpf_ui_div (mpf_ptr r, unsigned long int u, mpf_srcptr v)
29{
30  mp_srcptr vp;
31  mp_ptr rp, tp, remp, new_vp;
32  mp_size_t vsize;
33  mp_size_t rsize, prospective_rsize, zeros, tsize, high_zero;
34  mp_size_t sign_quotient;
35  mp_size_t prec;
36  mp_exp_t rexp;
37  TMP_DECL;
38
39  vsize = v->_mp_size;
40  sign_quotient = vsize;
41  vsize = ABS (vsize);
42  prec = r->_mp_prec;
43
44  if (UNLIKELY (vsize == 0))
45    DIVIDE_BY_ZERO;
46
47  if (UNLIKELY (u == 0))
48    {
49      r->_mp_size = 0;
50      r->_mp_exp = 0;
51      return;
52    }
53
54  TMP_MARK;
55  rexp = 1 - v->_mp_exp + 1;
56
57  rp = r->_mp_d;
58  vp = v->_mp_d;
59
60  prospective_rsize = 1 - vsize + 1;    /* quot from using given u,v sizes */
61  rsize = prec + 1;                     /* desired quot size */
62
63  zeros = rsize - prospective_rsize;    /* padding u to give rsize */
64  tsize = 1 + zeros;                    /* u with zeros */
65
66  if (WANT_TMP_DEBUG)
67    {
68      /* separate alloc blocks, for malloc debugging */
69      remp = TMP_ALLOC_LIMBS (vsize);
70      tp = TMP_ALLOC_LIMBS (tsize);
71      new_vp = NULL;
72      if (rp == vp)
73        new_vp = TMP_ALLOC_LIMBS (vsize);
74    }
75  else
76    {
77      /* one alloc with calculated size, for efficiency */
78      mp_size_t size = vsize + tsize + (rp == vp ? vsize : 0);
79      remp = TMP_ALLOC_LIMBS (size);
80      tp = remp + vsize;
81      new_vp = tp + tsize;
82    }
83
84  /* ensure divisor doesn't overlap quotient */
85  if (rp == vp)
86    {
87      MPN_COPY (new_vp, vp, vsize);
88      vp = new_vp;
89    }
90
91  MPN_ZERO (tp, tsize-1);
92
93  tp[tsize - 1] = u & GMP_NUMB_MASK;
94#if BITS_PER_ULONG > GMP_NUMB_BITS
95  if (u > GMP_NUMB_MAX)
96    {
97      /* tsize-vsize+1 == rsize, so tsize >= rsize.  rsize == prec+1 >= 2,
98         so tsize >= 2, hence there's room for 2-limb u with nails */
99      ASSERT (tsize >= 2);
100      tp[tsize - 1] = u >> GMP_NUMB_BITS;
101      tp[tsize - 2] = u & GMP_NUMB_MASK;
102      rexp++;
103    }
104#endif
105
106  ASSERT (tsize-vsize+1 == rsize);
107  mpn_tdiv_qr (rp, remp, (mp_size_t) 0, tp, tsize, vp, vsize);
108
109  /* strip possible zero high limb */
110  high_zero = (rp[rsize-1] == 0);
111  rsize -= high_zero;
112  rexp -= high_zero;
113
114  r->_mp_size = sign_quotient >= 0 ? rsize : -rsize;
115  r->_mp_exp = rexp;
116  TMP_FREE;
117}
118