xref: /dflybsd-src/contrib/gmp/mpf/div.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /* mpf_div -- Divide two floats.
286d7f5d3SJohn Marino 
386d7f5d3SJohn Marino Copyright 1993, 1994, 1996, 2000, 2001, 2002, 2004, 2005, 2010 Free Software
486d7f5d3SJohn Marino Foundation, Inc.
586d7f5d3SJohn Marino 
686d7f5d3SJohn Marino This file is part of the GNU MP Library.
786d7f5d3SJohn Marino 
886d7f5d3SJohn Marino The GNU MP Library is free software; you can redistribute it and/or modify
986d7f5d3SJohn Marino it under the terms of the GNU Lesser General Public License as published by
1086d7f5d3SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
1186d7f5d3SJohn Marino option) any later version.
1286d7f5d3SJohn Marino 
1386d7f5d3SJohn Marino The GNU MP Library is distributed in the hope that it will be useful, but
1486d7f5d3SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1586d7f5d3SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
1686d7f5d3SJohn Marino License for more details.
1786d7f5d3SJohn Marino 
1886d7f5d3SJohn Marino You should have received a copy of the GNU Lesser General Public License
1986d7f5d3SJohn Marino along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
2086d7f5d3SJohn Marino 
2186d7f5d3SJohn Marino #include "gmp.h"
2286d7f5d3SJohn Marino #include "gmp-impl.h"
2386d7f5d3SJohn Marino 
2486d7f5d3SJohn Marino 
2586d7f5d3SJohn Marino /* Not done:
2686d7f5d3SJohn Marino 
2786d7f5d3SJohn Marino    No attempt is made to identify an overlap u==v.  The result will be
2886d7f5d3SJohn Marino    correct (1.0), but a full actual division is done whereas of course
2986d7f5d3SJohn Marino    x/x==1 needs no work.  Such a call is not a sensible thing to make, and
3086d7f5d3SJohn Marino    it's left to an application to notice and optimize if it might arise
3186d7f5d3SJohn Marino    somehow through pointer aliasing or whatever.
3286d7f5d3SJohn Marino 
3386d7f5d3SJohn Marino    Enhancements:
3486d7f5d3SJohn Marino 
3586d7f5d3SJohn Marino    The high quotient limb is non-zero when high{up,vsize} >= {vp,vsize}.  We
3686d7f5d3SJohn Marino    could make that comparison and use qsize==prec instead of qsize==prec+1,
3786d7f5d3SJohn Marino    to save one limb in the division.
3886d7f5d3SJohn Marino 
3986d7f5d3SJohn Marino    If r==u but the size is enough bigger than prec that there won't be an
4086d7f5d3SJohn Marino    overlap between quotient and dividend in mpn_tdiv_qr, then we can avoid
4186d7f5d3SJohn Marino    copying up,usize.  This would only arise from a prec reduced with
4286d7f5d3SJohn Marino    mpf_set_prec_raw and will be pretty unusual, but might be worthwhile if
4386d7f5d3SJohn Marino    it could be worked into the copy_u decision cleanly.  */
4486d7f5d3SJohn Marino 
4586d7f5d3SJohn Marino void
mpf_div(mpf_ptr r,mpf_srcptr u,mpf_srcptr v)4686d7f5d3SJohn Marino mpf_div (mpf_ptr r, mpf_srcptr u, mpf_srcptr v)
4786d7f5d3SJohn Marino {
4886d7f5d3SJohn Marino   mp_srcptr up, vp;
4986d7f5d3SJohn Marino   mp_ptr rp, tp, new_vp;
5086d7f5d3SJohn Marino   mp_size_t usize, vsize, rsize, prospective_rsize, tsize, zeros;
5186d7f5d3SJohn Marino   mp_size_t sign_quotient, prec, high_zero, chop;
5286d7f5d3SJohn Marino   mp_exp_t rexp;
5386d7f5d3SJohn Marino   int copy_u;
5486d7f5d3SJohn Marino   TMP_DECL;
5586d7f5d3SJohn Marino 
5686d7f5d3SJohn Marino   usize = SIZ(u);
5786d7f5d3SJohn Marino   vsize = SIZ(v);
5886d7f5d3SJohn Marino   sign_quotient = usize ^ vsize;
5986d7f5d3SJohn Marino   usize = ABS (usize);
6086d7f5d3SJohn Marino   vsize = ABS (vsize);
6186d7f5d3SJohn Marino   prec = PREC(r);
6286d7f5d3SJohn Marino 
6386d7f5d3SJohn Marino   if (vsize == 0)
6486d7f5d3SJohn Marino     DIVIDE_BY_ZERO;
6586d7f5d3SJohn Marino 
6686d7f5d3SJohn Marino   if (usize == 0)
6786d7f5d3SJohn Marino     {
6886d7f5d3SJohn Marino       SIZ(r) = 0;
6986d7f5d3SJohn Marino       EXP(r) = 0;
7086d7f5d3SJohn Marino       return;
7186d7f5d3SJohn Marino     }
7286d7f5d3SJohn Marino 
7386d7f5d3SJohn Marino   TMP_MARK;
7486d7f5d3SJohn Marino   rexp = EXP(u) - EXP(v) + 1;
7586d7f5d3SJohn Marino 
7686d7f5d3SJohn Marino   rp = PTR(r);
7786d7f5d3SJohn Marino   up = PTR(u);
7886d7f5d3SJohn Marino   vp = PTR(v);
7986d7f5d3SJohn Marino 
8086d7f5d3SJohn Marino   prospective_rsize = usize - vsize + 1; /* quot from using given u,v sizes */
8186d7f5d3SJohn Marino   rsize = prec + 1;			 /* desired quot */
8286d7f5d3SJohn Marino 
8386d7f5d3SJohn Marino   zeros = rsize - prospective_rsize;	 /* padding u to give rsize */
8486d7f5d3SJohn Marino   copy_u = (zeros > 0 || rp == up);	 /* copy u if overlap or padding */
8586d7f5d3SJohn Marino 
8686d7f5d3SJohn Marino   chop = MAX (-zeros, 0);		 /* negative zeros means shorten u */
8786d7f5d3SJohn Marino   up += chop;
8886d7f5d3SJohn Marino   usize -= chop;
8986d7f5d3SJohn Marino   zeros += chop;			 /* now zeros >= 0 */
9086d7f5d3SJohn Marino 
9186d7f5d3SJohn Marino   tsize = usize + zeros;		 /* size for possible copy of u */
9286d7f5d3SJohn Marino 
9386d7f5d3SJohn Marino   /* copy and possibly extend u if necessary */
9486d7f5d3SJohn Marino   if (copy_u)
9586d7f5d3SJohn Marino     {
9686d7f5d3SJohn Marino       tp = TMP_ALLOC_LIMBS (tsize + 1);	/* +1 for mpn_div_q's scratch needs */
9786d7f5d3SJohn Marino       MPN_ZERO (tp, zeros);
9886d7f5d3SJohn Marino       MPN_COPY (tp+zeros, up, usize);
9986d7f5d3SJohn Marino       up = tp;
10086d7f5d3SJohn Marino       usize = tsize;
10186d7f5d3SJohn Marino     }
10286d7f5d3SJohn Marino   else
10386d7f5d3SJohn Marino     {
10486d7f5d3SJohn Marino       tp = TMP_ALLOC_LIMBS (usize + 1);
10586d7f5d3SJohn Marino     }
10686d7f5d3SJohn Marino 
10786d7f5d3SJohn Marino   /* ensure divisor doesn't overlap quotient */
10886d7f5d3SJohn Marino   if (rp == vp)
10986d7f5d3SJohn Marino     {
11086d7f5d3SJohn Marino       new_vp = TMP_ALLOC_LIMBS (vsize);
11186d7f5d3SJohn Marino       MPN_COPY (new_vp, vp, vsize);
11286d7f5d3SJohn Marino       vp = new_vp;
11386d7f5d3SJohn Marino     }
11486d7f5d3SJohn Marino 
11586d7f5d3SJohn Marino   ASSERT (usize-vsize+1 == rsize);
11686d7f5d3SJohn Marino   mpn_div_q (rp, up, usize, vp, vsize, tp);
11786d7f5d3SJohn Marino 
11886d7f5d3SJohn Marino   /* strip possible zero high limb */
11986d7f5d3SJohn Marino   high_zero = (rp[rsize-1] == 0);
12086d7f5d3SJohn Marino   rsize -= high_zero;
12186d7f5d3SJohn Marino   rexp -= high_zero;
12286d7f5d3SJohn Marino 
12386d7f5d3SJohn Marino   SIZ(r) = sign_quotient >= 0 ? rsize : -rsize;
12486d7f5d3SJohn Marino   EXP(r) = rexp;
12586d7f5d3SJohn Marino   TMP_FREE;
12686d7f5d3SJohn Marino }
127