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