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

数学计算

开发平台:

Unix_Linux

  1. /* double mpq_get_d (mpq_t src) -- mpq to double, rounding towards zero.
  2. Copyright 1995, 1996, 2001, 2002, 2003, 2004, 2005 Free Software Foundation,
  3. Inc.
  4. This file is part of the GNU MP Library.
  5. The GNU MP Library is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU Lesser General Public License as published by
  7. the Free Software Foundation; either version 3 of the License, or (at your
  8. option) any later version.
  9. The GNU MP Library is distributed in the hope that it will be useful, but
  10. WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  11. or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
  12. License for more details.
  13. You should have received a copy of the GNU Lesser General Public License
  14. along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
  15. #include <stdio.h>  /* for NULL */
  16. #include "gmp.h"
  17. #include "gmp-impl.h"
  18. #include "longlong.h"
  19. /* All that's needed is to get the high 53 bits of the quotient num/den,
  20.    rounded towards zero.  More than 53 bits is fine, any excess is ignored
  21.    by mpn_get_d.
  22.    N_QLIMBS is how many quotient limbs we need to satisfy the mantissa of a
  23.    double, assuming the highest of those limbs is non-zero.  The target
  24.    qsize for mpn_tdiv_qr is then 1 more than this, since that function may
  25.    give a zero in the high limb (and non-zero in the second highest).
  26.    The use of 8*sizeof(double) in N_QLIMBS is an overestimate of the
  27.    mantissa bits, but it gets the same result as the true value (53 or 48 or
  28.    whatever) when rounded up to a multiple of GMP_NUMB_BITS, for non-nails.
  29.    Enhancements:
  30.    Use the true mantissa size in the N_QLIMBS formula, to save a divide step
  31.    in nails.
  32.    Examine the high limbs of num and den to see if the highest 1 bit of the
  33.    quotient will fall high enough that just N_QLIMBS-1 limbs is enough to
  34.    get the necessary bits, thereby saving a division step.
  35.    Bit shift either num or den to arrange for the above condition on the
  36.    high 1 bit of the quotient, to save a division step always.  A shift to
  37.    save a division step is definitely worthwhile with mpn_tdiv_qr, though we
  38.    may want to reassess this on big num/den when a quotient-only division
  39.    exists.
  40.    Maybe we could estimate the final exponent using nsize-dsize (and
  41.    possibly the high limbs of num and den), so as to detect overflow and
  42.    return infinity or zero quickly.  Overflow is never very helpful to an
  43.    application, and can therefore probably be regarded as abnormal, but we
  44.    may still like to optimize it if the conditions are easy.  (This would
  45.    only be for float formats we know, unknown formats are not important and
  46.    can be left to mpn_get_d.)
  47.    Future:
  48.    If/when mpn_tdiv_qr supports its qxn parameter we can use that instead of
  49.    padding n with zeros in temporary space.
  50.    If/when a quotient-only division exists it can be used here immediately.
  51.    remp is only to satisfy mpn_tdiv_qr, the remainder is not used.
  52.    Alternatives:
  53.    An alternative algorithm, that may be faster:
  54.    0. Let n be somewhat larger than the number of significant bits in a double.
  55.    1. Extract the most significant n bits of the denominator, and an equal
  56.       number of bits from the numerator.
  57.    2. Interpret the extracted numbers as integers, call them a and b
  58.       respectively, and develop n bits of the fractions ((a + 1) / b) and
  59.       (a / (b + 1)) using mpn_divrem.
  60.    3. If the computed values are identical UP TO THE POSITION WE CARE ABOUT,
  61.       we are done.  If they are different, repeat the algorithm from step 1,
  62.       but first let n = n * 2.
  63.    4. If we end up using all bits from the numerator and denominator, fall
  64.       back to a plain division.
  65.    5. Just to make life harder, The computation of a + 1 and b + 1 above
  66.       might give carry-out...  Needs special handling.  It might work to
  67.       subtract 1 in both cases instead.
  68.    Not certain if this approach would be faster than a quotient-only
  69.    division.  Presumably such optimizations are the sort of thing we would
  70.    like to have helping everywhere that uses a quotient-only division. */
  71. double
  72. mpq_get_d (const MP_RAT *src)
  73. {
  74.   double res;
  75.   mp_srcptr np, dp;
  76.   mp_ptr remp, tp;
  77.   mp_size_t nsize = src->_mp_num._mp_size;
  78.   mp_size_t dsize = src->_mp_den._mp_size;
  79.   mp_size_t qsize, prospective_qsize, zeros, chop, tsize;
  80.   mp_size_t sign_quotient = nsize;
  81.   long exp;
  82. #define N_QLIMBS (1 + (sizeof (double) + BYTES_PER_MP_LIMB-1) / BYTES_PER_MP_LIMB)
  83.   mp_limb_t qarr[N_QLIMBS + 1];
  84.   mp_ptr qp = qarr;
  85.   TMP_DECL;
  86.   ASSERT (dsize > 0);    /* canonical src */
  87.   /* mpn_get_d below requires a non-zero operand */
  88.   if (UNLIKELY (nsize == 0))
  89.     return 0.0;
  90.   TMP_MARK;
  91.   nsize = ABS (nsize);
  92.   dsize = ABS (dsize);
  93.   np = src->_mp_num._mp_d;
  94.   dp = src->_mp_den._mp_d;
  95.   prospective_qsize = nsize - dsize + 1;   /* from using given n,d */
  96.   qsize = N_QLIMBS + 1;                    /* desired qsize */
  97.   zeros = qsize - prospective_qsize;       /* padding n to get qsize */
  98.   exp = (long) -zeros * GMP_NUMB_BITS;     /* relative to low of qp */
  99.   chop = MAX (-zeros, 0);                  /* negative zeros means shorten n */
  100.   np += chop;
  101.   nsize -= chop;
  102.   zeros += chop;                           /* now zeros >= 0 */
  103.   tsize = nsize + zeros;                   /* size for possible copy of n */
  104.   if (WANT_TMP_DEBUG)
  105.     {
  106.       /* separate blocks, for malloc debugging */
  107.       remp = TMP_ALLOC_LIMBS (dsize);
  108.       tp = (zeros > 0 ? TMP_ALLOC_LIMBS (tsize) : NULL);
  109.     }
  110.   else
  111.     {
  112.       /* one block with conditionalized size, for efficiency */
  113.       remp = TMP_ALLOC_LIMBS (dsize + (zeros > 0 ? tsize : 0));
  114.       tp = remp + dsize;
  115.     }
  116.   /* zero extend n into temporary space, if necessary */
  117.   if (zeros > 0)
  118.     {
  119.       MPN_ZERO (tp, zeros);
  120.       MPN_COPY (tp+zeros, np, nsize);
  121.       np = tp;
  122.       nsize = tsize;
  123.     }
  124.   ASSERT (qsize == nsize - dsize + 1);
  125.   mpn_tdiv_qr (qp, remp, (mp_size_t) 0, np, nsize, dp, dsize);
  126.   /* strip possible zero high limb */
  127.   qsize -= (qp[qsize-1] == 0);
  128.   res = mpn_get_d (qp, qsize, sign_quotient, exp);
  129.   TMP_FREE;
  130.   return res;
  131. }