github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/mpf/set_q.c (about) 1 /* mpf_set_q (mpf_t rop, mpq_t op) -- Convert the rational op to the float rop. 2 3 Copyright 1996, 1999, 2001, 2002, 2004, 2005 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 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 14 or 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 20 or both in parallel, as here. 21 22 The GNU MP Library is distributed in the hope that it will be useful, but 23 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 24 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25 for more details. 26 27 You should have received copies of the GNU General Public License and the 28 GNU Lesser General Public License along with the GNU MP Library. If not, 29 see https://www.gnu.org/licenses/. */ 30 31 #include <stdio.h> /* for NULL */ 32 #include "gmp.h" 33 #include "gmp-impl.h" 34 #include "longlong.h" 35 36 37 /* As usual the aim is to produce PREC(r) limbs, with the high non-zero. 38 The basic mpn_tdiv_qr produces a quotient of nsize-dsize+1 limbs, with 39 either the high or second highest limb non-zero. We arrange for 40 nsize-dsize+1 to equal prec+1, hence giving either prec or prec+1 result 41 limbs at PTR(r). 42 43 nsize-dsize+1 == prec+1 is achieved by adjusting num(q), either dropping 44 low limbs if it's too big, or padding with low zeros if it's too small. 45 The full given den(q) is always used. 46 47 We cannot truncate den(q), because even when it's much bigger than prec 48 the last limbs can still influence the final quotient. Often they don't, 49 but we leave optimization of that to a prospective quotient-only mpn 50 division. 51 52 Not done: 53 54 If den(q) is a power of 2 then we may end up with low zero limbs on the 55 result. But nothing is done about this, since it should be unlikely on 56 random data, and can be left to an application to call mpf_div_2exp if it 57 might occur with any frequency. 58 59 Enhancements: 60 61 The high quotient limb is non-zero when high{np,dsize} >= {dp,dsize}. We 62 could make that comparison and use qsize==prec instead of qsize==prec+1, 63 to save one limb in the division. 64 65 Future: 66 67 If/when mpn_tdiv_qr supports its qxn parameter we can use that instead of 68 padding n with zeros in temporary space. 69 70 If/when a quotient-only division exists it can be used here immediately. 71 remp is only to satisfy mpn_tdiv_qr, the remainder is not used. */ 72 73 void 74 mpf_set_q (mpf_t r, mpq_srcptr q) 75 { 76 mp_srcptr np, dp; 77 mp_size_t prec, nsize, dsize, qsize, prospective_qsize, tsize, zeros; 78 mp_size_t sign_quotient, high_zero; 79 mp_ptr qp, tp, remp; 80 mp_exp_t exp; 81 TMP_DECL; 82 83 ASSERT (SIZ(&q->_mp_den) > 0); /* canonical q */ 84 85 nsize = SIZ (&q->_mp_num); 86 dsize = SIZ (&q->_mp_den); 87 88 if (UNLIKELY (nsize == 0)) 89 { 90 SIZ (r) = 0; 91 EXP (r) = 0; 92 return; 93 } 94 95 TMP_MARK; 96 97 prec = PREC (r); 98 qp = PTR (r); 99 100 sign_quotient = nsize; 101 nsize = ABS (nsize); 102 np = PTR (&q->_mp_num); 103 dp = PTR (&q->_mp_den); 104 105 prospective_qsize = nsize - dsize + 1; /* q from using given n,d sizes */ 106 exp = prospective_qsize; /* ie. number of integer limbs */ 107 qsize = prec + 1; /* desired q */ 108 109 zeros = qsize - prospective_qsize; /* n zeros to get desired qsize */ 110 tsize = nsize + zeros; /* possible copy of n */ 111 112 if (WANT_TMP_DEBUG) 113 { 114 /* separate alloc blocks, for malloc debugging */ 115 remp = TMP_ALLOC_LIMBS (dsize); 116 tp = NULL; 117 if (zeros > 0) 118 tp = TMP_ALLOC_LIMBS (tsize); 119 } 120 else 121 { 122 /* one alloc with a conditionalized size, for efficiency */ 123 mp_size_t size = dsize + (zeros > 0 ? tsize : 0); 124 remp = TMP_ALLOC_LIMBS (size); 125 tp = remp + dsize; 126 } 127 128 if (zeros > 0) 129 { 130 /* pad n with zeros into temporary space */ 131 MPN_ZERO (tp, zeros); 132 MPN_COPY (tp+zeros, np, nsize); 133 np = tp; 134 nsize = tsize; 135 } 136 else 137 { 138 /* shorten n to get desired qsize */ 139 nsize += zeros; 140 np -= zeros; 141 } 142 143 ASSERT (nsize-dsize+1 == qsize); 144 mpn_tdiv_qr (qp, remp, (mp_size_t) 0, np, nsize, dp, dsize); 145 146 /* strip possible zero high limb */ 147 high_zero = (qp[qsize-1] == 0); 148 qsize -= high_zero; 149 exp -= high_zero; 150 151 EXP (r) = exp; 152 SIZ (r) = sign_quotient >= 0 ? qsize : -qsize; 153 154 TMP_FREE; 155 }