set_q.c
上传用户:qaz666999
上传日期:2022-08-06
资源大小:2570k
文件大小:4k
源码类别:

数学计算

开发平台:

Unix_Linux

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