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  }