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