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