1 /*
2     Copyright (C) 2009 William Hart
3 
4     This file is part of FLINT.
5 
6     FLINT is free software: you can redistribute it and/or modify it under
7     the terms of the GNU Lesser General Public License (LGPL) as published
8     by the Free Software Foundation; either version 2.1 of the License, or
9     (at your option) any later version.  See <http://www.gnu.org/licenses/>.
10 */
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <gmp.h>
15 #include "flint.h"
16 #include "ulong_extras.h"
17 #include "fmpz.h"
18 
19 void
fmpz_fdiv_qr(fmpz_t f,fmpz_t s,const fmpz_t g,const fmpz_t h)20 fmpz_fdiv_qr(fmpz_t f, fmpz_t s, const fmpz_t g, const fmpz_t h)
21 {
22     fmpz c1 = *g;
23     fmpz c2 = *h;
24 
25     if (fmpz_is_zero(h))
26     {
27         flint_printf("Exception (fmpz_fdiv_q). Division by zero.\n");
28         flint_abort();
29     }
30 
31     if (!COEFF_IS_MPZ(c1))      /* g is small */
32     {
33         if (!COEFF_IS_MPZ(c2))  /* h is also small */
34         {
35             fmpz q = c1 / c2;   /* compute C quotient */
36             fmpz r = c1 - c2 * q;   /* compute remainder */
37 
38             if ((c2 > WORD(0) && r < WORD(0)) || (c2 < WORD(0) && r > WORD(0)))
39             {
40                 q--;            /* q cannot overflow as remainder implies |c2| != 1 */
41                 r += c2;
42             }
43 
44             fmpz_set_si(f, q);
45             fmpz_set_si(s, r);
46         }
47         else                    /* h is large and g is small */
48         {
49             if (c1 == WORD(0))
50             {
51                 fmpz_set_ui(f, WORD(0)); /* g is zero */
52                 fmpz_set_si(s, c1);
53             }
54             else if ((c1 < WORD(0) && fmpz_sgn(h) < 0) || (c1 > WORD(0) && fmpz_sgn(h) > 0))  /* signs are the same */
55             {
56                 fmpz_zero(f);   /* quotient is positive, round down to zero */
57                 fmpz_set_si(s, c1);
58             }
59             else
60             {
61                 fmpz_add(s, g, h);
62                 fmpz_set_si(f, WORD(-1));    /* quotient is negative, round down to minus one */
63             }
64         }
65     }
66     else                        /* g is large */
67     {
68         __mpz_struct *mpz_ptr, *mpz_ptr2;
69 
70         _fmpz_promote(f); /* must not hang on to ptr whilst promoting s */
71         mpz_ptr2 = _fmpz_promote(s);
72 		mpz_ptr  = COEFF_TO_PTR(*f);
73 
74 		if (!COEFF_IS_MPZ(c2))  /* h is small */
75         {
76             if (c2 > 0)         /* h > 0 */
77             {
78                 flint_mpz_fdiv_qr_ui(mpz_ptr, mpz_ptr2, COEFF_TO_PTR(c1), c2);
79             }
80             else
81             {
82                 flint_mpz_cdiv_qr_ui(mpz_ptr, mpz_ptr2, COEFF_TO_PTR(c1), -c2);
83                 mpz_neg(mpz_ptr, mpz_ptr);
84             }
85         }
86         else                    /* both are large */
87         {
88             mpz_fdiv_qr(mpz_ptr, mpz_ptr2, COEFF_TO_PTR(c1), COEFF_TO_PTR(c2));
89         }
90         _fmpz_demote_val(f);    /* division by h may result in small value */
91         _fmpz_demote_val(s);    /* division by h may result in small value */
92     }
93 }
94