File: mul_1x1.c

package info (click to toggle)
flint-arb 1%3A2.23.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 14,672 kB
  • sloc: ansic: 204,753; sh: 570; makefile: 287; python: 268
file content (128 lines) | stat: -rw-r--r-- 3,588 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
    Copyright (C) 2013, 2014 Fredrik Johansson

    This file is part of Arb.

    Arb is free software: you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License (LGPL) as published
    by the Free Software Foundation; either version 2.1 of the License, or
    (at your option) any later version.  See <http://www.gnu.org/licenses/>.
*/

#include "fmpr.h"

slong
_fmpr_mul_1x1(fmpr_t z, mp_limb_t u, const fmpz_t xexp, mp_limb_t v,
    const fmpz_t yexp, int negative, slong prec, fmpr_rnd_t rnd)
{
    slong lead, trail, bc, shift, ret;
    mp_limb_t hi, lo;

    umul_ppmm(hi, lo, u, v);
    shift = 0;

    if (hi == 0)
    {
        /* 1 limb */
        count_leading_zeros(lead, lo);
        bc = FLINT_BITS - lead;

        ret = FMPR_RESULT_EXACT;
        if (bc > prec)
        {
            shift += bc - prec;
            lo = (lo >> shift) + rounds_up(rnd, negative);
            count_trailing_zeros(trail, lo);
            lo >>= trail;
            shift += trail;
            ret = trail;

            /* special case: if the mantissa overflowed to the next power of two,
               the error bound must be multiplied by two */
            ret -= (trail == prec);
        }

        if (!negative)
            fmpz_set_ui(fmpr_manref(z), lo);
        else
            fmpz_neg_ui(fmpr_manref(z), lo);
    }
    else
    {
        /* 2 limbs */
        count_leading_zeros(lead, hi);
        bc = 2 * FLINT_BITS - lead;

        ret = FMPR_RESULT_EXACT;

        if (bc > prec)
        {
            shift += bc - prec;

            /* round */
            if (shift < FLINT_BITS)
            {
                lo = (lo >> shift) | (hi << (FLINT_BITS - shift));
                hi >>= shift;
            }
            else
            {
                lo = hi >> (shift - FLINT_BITS);
                hi = 0;
            }

            if (rounds_up(rnd, negative))
                add_ssaaaa(hi, lo, hi, lo, 0, 1);

            /* remove trailing zeros */
            if (lo == 0)
            {
                count_trailing_zeros(trail, hi);
                hi >>= trail;
                shift += FLINT_BITS + trail;
                ret = FLINT_BITS + trail;

                /* special case: if the mantissa overflowed to the next power of two,
                   the error bound must be multiplied by two */
                ret -= (FLINT_BITS + trail == prec);

                if (!negative)
                    fmpz_set_ui(fmpr_manref(z), hi);
                else
                    fmpz_neg_ui(fmpr_manref(z), hi);
            }
            else
            {
                count_trailing_zeros(trail, lo);

                if (trail != 0)
                {
                    lo = (lo >> trail) | (hi << (FLINT_BITS - trail));
                    hi >>= trail;
                    shift += trail;
                }
                ret = trail;

                /* special case: if the mantissa overflowed to the next power of two,
                   the error bound must be multiplied by two */
                ret -= (trail == prec);

                if (!negative)
                    fmpz_set_uiui(fmpr_manref(z), hi, lo);
                else
                    fmpz_neg_uiui(fmpr_manref(z), hi, lo);
            }
        }
        else
        {
            if (!negative)
                fmpz_set_uiui(fmpr_manref(z), hi, lo);
            else
                fmpz_neg_uiui(fmpr_manref(z), hi, lo);
        }
    }

    fmpz_add2_fmpz_si_inline(fmpr_expref(z), xexp, yexp, shift);
    return ret;
}