Home | History | Annotate | Line # | Download | only in mpf
div.c revision 1.1.1.3
      1      1.1  mrg /* mpf_div -- Divide two floats.
      2      1.1  mrg 
      3  1.1.1.3  mrg Copyright 1993, 1994, 1996, 2000-2002, 2004, 2005, 2010, 2012 Free Software
      4  1.1.1.3  mrg Foundation, Inc.
      5      1.1  mrg 
      6      1.1  mrg This file is part of the GNU MP Library.
      7      1.1  mrg 
      8      1.1  mrg The GNU MP Library is free software; you can redistribute it and/or modify
      9  1.1.1.3  mrg it under the terms of either:
     10  1.1.1.3  mrg 
     11  1.1.1.3  mrg   * the GNU Lesser General Public License as published by the Free
     12  1.1.1.3  mrg     Software Foundation; either version 3 of the License, or (at your
     13  1.1.1.3  mrg     option) any later version.
     14  1.1.1.3  mrg 
     15  1.1.1.3  mrg or
     16  1.1.1.3  mrg 
     17  1.1.1.3  mrg   * the GNU General Public License as published by the Free Software
     18  1.1.1.3  mrg     Foundation; either version 2 of the License, or (at your option) any
     19  1.1.1.3  mrg     later version.
     20  1.1.1.3  mrg 
     21  1.1.1.3  mrg or both in parallel, as here.
     22      1.1  mrg 
     23      1.1  mrg The GNU MP Library is distributed in the hope that it will be useful, but
     24      1.1  mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     25  1.1.1.3  mrg or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     26  1.1.1.3  mrg for more details.
     27      1.1  mrg 
     28  1.1.1.3  mrg You should have received copies of the GNU General Public License and the
     29  1.1.1.3  mrg GNU Lesser General Public License along with the GNU MP Library.  If not,
     30  1.1.1.3  mrg see https://www.gnu.org/licenses/.  */
     31      1.1  mrg 
     32      1.1  mrg #include "gmp.h"
     33      1.1  mrg #include "gmp-impl.h"
     34      1.1  mrg 
     35      1.1  mrg 
     36      1.1  mrg /* Not done:
     37      1.1  mrg 
     38      1.1  mrg    No attempt is made to identify an overlap u==v.  The result will be
     39      1.1  mrg    correct (1.0), but a full actual division is done whereas of course
     40      1.1  mrg    x/x==1 needs no work.  Such a call is not a sensible thing to make, and
     41      1.1  mrg    it's left to an application to notice and optimize if it might arise
     42      1.1  mrg    somehow through pointer aliasing or whatever.
     43      1.1  mrg 
     44      1.1  mrg    Enhancements:
     45      1.1  mrg 
     46      1.1  mrg    The high quotient limb is non-zero when high{up,vsize} >= {vp,vsize}.  We
     47      1.1  mrg    could make that comparison and use qsize==prec instead of qsize==prec+1,
     48      1.1  mrg    to save one limb in the division.
     49      1.1  mrg 
     50      1.1  mrg    If r==u but the size is enough bigger than prec that there won't be an
     51  1.1.1.2  mrg    overlap between quotient and dividend in mpn_div_q, then we can avoid
     52      1.1  mrg    copying up,usize.  This would only arise from a prec reduced with
     53      1.1  mrg    mpf_set_prec_raw and will be pretty unusual, but might be worthwhile if
     54      1.1  mrg    it could be worked into the copy_u decision cleanly.  */
     55      1.1  mrg 
     56      1.1  mrg void
     57      1.1  mrg mpf_div (mpf_ptr r, mpf_srcptr u, mpf_srcptr v)
     58      1.1  mrg {
     59      1.1  mrg   mp_srcptr up, vp;
     60      1.1  mrg   mp_ptr rp, tp, new_vp;
     61      1.1  mrg   mp_size_t usize, vsize, rsize, prospective_rsize, tsize, zeros;
     62      1.1  mrg   mp_size_t sign_quotient, prec, high_zero, chop;
     63      1.1  mrg   mp_exp_t rexp;
     64      1.1  mrg   int copy_u;
     65      1.1  mrg   TMP_DECL;
     66      1.1  mrg 
     67      1.1  mrg   usize = SIZ(u);
     68      1.1  mrg   vsize = SIZ(v);
     69      1.1  mrg 
     70  1.1.1.2  mrg   if (UNLIKELY (vsize == 0))
     71      1.1  mrg     DIVIDE_BY_ZERO;
     72      1.1  mrg 
     73      1.1  mrg   if (usize == 0)
     74      1.1  mrg     {
     75      1.1  mrg       SIZ(r) = 0;
     76      1.1  mrg       EXP(r) = 0;
     77      1.1  mrg       return;
     78      1.1  mrg     }
     79      1.1  mrg 
     80  1.1.1.2  mrg   sign_quotient = usize ^ vsize;
     81  1.1.1.2  mrg   usize = ABS (usize);
     82  1.1.1.2  mrg   vsize = ABS (vsize);
     83  1.1.1.2  mrg   prec = PREC(r);
     84  1.1.1.2  mrg 
     85      1.1  mrg   TMP_MARK;
     86      1.1  mrg   rexp = EXP(u) - EXP(v) + 1;
     87      1.1  mrg 
     88      1.1  mrg   rp = PTR(r);
     89      1.1  mrg   up = PTR(u);
     90      1.1  mrg   vp = PTR(v);
     91      1.1  mrg 
     92      1.1  mrg   prospective_rsize = usize - vsize + 1; /* quot from using given u,v sizes */
     93      1.1  mrg   rsize = prec + 1;			 /* desired quot */
     94      1.1  mrg 
     95      1.1  mrg   zeros = rsize - prospective_rsize;	 /* padding u to give rsize */
     96      1.1  mrg   copy_u = (zeros > 0 || rp == up);	 /* copy u if overlap or padding */
     97      1.1  mrg 
     98      1.1  mrg   chop = MAX (-zeros, 0);		 /* negative zeros means shorten u */
     99      1.1  mrg   up += chop;
    100      1.1  mrg   usize -= chop;
    101      1.1  mrg   zeros += chop;			 /* now zeros >= 0 */
    102      1.1  mrg 
    103      1.1  mrg   tsize = usize + zeros;		 /* size for possible copy of u */
    104      1.1  mrg 
    105      1.1  mrg   /* copy and possibly extend u if necessary */
    106      1.1  mrg   if (copy_u)
    107      1.1  mrg     {
    108      1.1  mrg       tp = TMP_ALLOC_LIMBS (tsize + 1);	/* +1 for mpn_div_q's scratch needs */
    109      1.1  mrg       MPN_ZERO (tp, zeros);
    110      1.1  mrg       MPN_COPY (tp+zeros, up, usize);
    111      1.1  mrg       up = tp;
    112      1.1  mrg       usize = tsize;
    113      1.1  mrg     }
    114      1.1  mrg   else
    115      1.1  mrg     {
    116      1.1  mrg       tp = TMP_ALLOC_LIMBS (usize + 1);
    117      1.1  mrg     }
    118      1.1  mrg 
    119      1.1  mrg   /* ensure divisor doesn't overlap quotient */
    120      1.1  mrg   if (rp == vp)
    121      1.1  mrg     {
    122      1.1  mrg       new_vp = TMP_ALLOC_LIMBS (vsize);
    123      1.1  mrg       MPN_COPY (new_vp, vp, vsize);
    124      1.1  mrg       vp = new_vp;
    125      1.1  mrg     }
    126      1.1  mrg 
    127      1.1  mrg   ASSERT (usize-vsize+1 == rsize);
    128      1.1  mrg   mpn_div_q (rp, up, usize, vp, vsize, tp);
    129      1.1  mrg 
    130      1.1  mrg   /* strip possible zero high limb */
    131      1.1  mrg   high_zero = (rp[rsize-1] == 0);
    132      1.1  mrg   rsize -= high_zero;
    133      1.1  mrg   rexp -= high_zero;
    134      1.1  mrg 
    135      1.1  mrg   SIZ(r) = sign_quotient >= 0 ? rsize : -rsize;
    136      1.1  mrg   EXP(r) = rexp;
    137      1.1  mrg   TMP_FREE;
    138      1.1  mrg }
    139