blob: b0b7fe309fb9ce9068a1d9ca010ea2b4ec460bae [file] [log] [blame]
Austin Schuhdace2a62020-08-18 10:56:48 -07001/* mpf_set_q (mpf_t rop, mpq_t op) -- Convert the rational op to the float rop.
2
3Copyright 1996, 1999, 2001, 2002, 2004, 2005, 2016 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library.
6
7The GNU MP Library is free software; you can redistribute it and/or modify
8it under the terms of either:
9
10 * the GNU Lesser General Public License as published by the Free
11 Software Foundation; either version 3 of the License, or (at your
12 option) any later version.
13
14or
15
16 * the GNU General Public License as published by the Free Software
17 Foundation; either version 2 of the License, or (at your option) any
18 later version.
19
20or both in parallel, as here.
21
22The GNU MP Library is distributed in the hope that it will be useful, but
23WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25for more details.
26
27You should have received copies of the GNU General Public License and the
28GNU Lesser General Public License along with the GNU MP Library. If not,
29see https://www.gnu.org/licenses/. */
30
31#include "gmp-impl.h"
32
33
34/* As usual the aim is to produce PREC(r) limbs, with the high non-zero. The
35 basic mpn_div_q produces a quotient of nsize-dsize+1 limbs, with either the
36 high or second highest limb non-zero. We arrange for nsize-dsize+1 to equal
37 prec+1, hence giving either prec or prec+1 result limbs at PTR(r).
38
39 nsize-dsize+1 == prec+1 is achieved by adjusting num(q), either dropping low
40 limbs if it's too big, or padding with low zeros if it's too small. The
41 full given den(q) is always used.
42
43 We cannot truncate den(q), because even when it's much bigger than prec the
44 last limbs can still influence the final quotient. Often they don't, but we
45 leave optimization of that to mpn_div_q.
46
47 Enhancements:
48
49 The high quotient limb is non-zero when high{np,dsize} > {dp,dsize}. We
50 could make that comparison and use qsize==prec instead of qsize==prec+1,
51 to save one limb in the division. */
52
53void
54mpf_set_q (mpf_t r, mpq_srcptr q)
55{
56 mp_srcptr np, dp;
57 mp_size_t prec, nsize, dsize, qsize, prospective_qsize, tsize, zeros;
58 mp_size_t sign_quotient, high_zero;
59 mp_ptr qp, tp;
60 mp_exp_t exp;
61 TMP_DECL;
62
63 ASSERT (SIZ(&q->_mp_den) > 0); /* canonical q */
64
65 nsize = SIZ (&q->_mp_num);
66 dsize = SIZ (&q->_mp_den);
67
68 if (UNLIKELY (nsize == 0))
69 {
70 SIZ (r) = 0;
71 EXP (r) = 0;
72 return;
73 }
74
75 TMP_MARK;
76
77 prec = PREC (r);
78 qp = PTR (r);
79
80 sign_quotient = nsize;
81 nsize = ABS (nsize);
82 np = PTR (&q->_mp_num);
83 dp = PTR (&q->_mp_den);
84
85 prospective_qsize = nsize - dsize + 1; /* q from using given n,d sizes */
86 exp = prospective_qsize; /* ie. number of integer limbs */
87 qsize = prec + 1; /* desired q */
88
89 zeros = qsize - prospective_qsize; /* n zeros to get desired qsize */
90 tsize = nsize + zeros; /* size of intermediate numerator */
91 tp = TMP_ALLOC_LIMBS (tsize + 1); /* +1 for mpn_div_q's scratch */
92
93 if (zeros > 0)
94 {
95 /* pad n with zeros into temporary space */
96 MPN_ZERO (tp, zeros);
97 MPN_COPY (tp+zeros, np, nsize);
98 np = tp; /* mpn_div_q allows this overlap */
99 }
100 else
101 {
102 /* shorten n to get desired qsize */
103 np -= zeros;
104 }
105
106 ASSERT (tsize-dsize+1 == qsize);
107 mpn_div_q (qp, np, tsize, dp, dsize, tp);
108
109 /* strip possible zero high limb */
110 high_zero = (qp[qsize-1] == 0);
111 qsize -= high_zero;
112 exp -= high_zero;
113
114 EXP (r) = exp;
115 SIZ (r) = sign_quotient >= 0 ? qsize : -qsize;
116
117 TMP_FREE;
118}