/src/gmp-6.2.1/mpn/bsqrtinv.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* mpn_bsqrtinv, compute r such that r^2 * y = 1 (mod 2^{b+1}). |
2 | | |
3 | | Contributed to the GNU project by Martin Boij (as part of perfpow.c). |
4 | | |
5 | | Copyright 2009, 2010, 2012, 2015 Free Software Foundation, Inc. |
6 | | |
7 | | This file is part of the GNU MP Library. |
8 | | |
9 | | The GNU MP Library is free software; you can redistribute it and/or modify |
10 | | it under the terms of either: |
11 | | |
12 | | * the GNU Lesser General Public License as published by the Free |
13 | | Software Foundation; either version 3 of the License, or (at your |
14 | | option) any later version. |
15 | | |
16 | | or |
17 | | |
18 | | * the GNU General Public License as published by the Free Software |
19 | | Foundation; either version 2 of the License, or (at your option) any |
20 | | later version. |
21 | | |
22 | | or both in parallel, as here. |
23 | | |
24 | | The GNU MP Library is distributed in the hope that it will be useful, but |
25 | | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
26 | | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
27 | | for more details. |
28 | | |
29 | | You should have received copies of the GNU General Public License and the |
30 | | GNU Lesser General Public License along with the GNU MP Library. If not, |
31 | | see https://www.gnu.org/licenses/. */ |
32 | | |
33 | | #include "gmp-impl.h" |
34 | | |
35 | | /* Compute r such that r^2 * y = 1 (mod 2^{b+1}). |
36 | | Return non-zero if such an integer r exists. |
37 | | |
38 | | Iterates |
39 | | r' <-- (3r - r^3 y) / 2 |
40 | | using Hensel lifting. Since we divide by two, the Hensel lifting is |
41 | | somewhat degenerates. Therefore, we lift from 2^b to 2^{b+1}-1. |
42 | | |
43 | | FIXME: |
44 | | (1) Simplify to do precision book-keeping in limbs rather than bits. |
45 | | |
46 | | (2) Rewrite iteration as |
47 | | r' <-- r - r (r^2 y - 1) / 2 |
48 | | and take advantage of zero low part of r^2 y - 1. |
49 | | |
50 | | (3) Use wrap-around trick. |
51 | | |
52 | | (4) Use a small table to get starting value. |
53 | | */ |
54 | | int |
55 | | mpn_bsqrtinv (mp_ptr rp, mp_srcptr yp, mp_bitcnt_t bnb, mp_ptr tp) |
56 | 0 | { |
57 | 0 | mp_ptr tp2; |
58 | 0 | mp_size_t bn, order[GMP_LIMB_BITS + 1]; |
59 | 0 | int i, d; |
60 | |
|
61 | 0 | ASSERT (bnb > 0); |
62 | | |
63 | 0 | bn = 1 + bnb / GMP_LIMB_BITS; |
64 | |
|
65 | 0 | tp2 = tp + bn; |
66 | |
|
67 | 0 | rp[0] = 1; |
68 | 0 | if (bnb == 1) |
69 | 0 | { |
70 | 0 | if ((yp[0] & 3) != 1) |
71 | 0 | return 0; |
72 | 0 | } |
73 | 0 | else |
74 | 0 | { |
75 | 0 | if ((yp[0] & 7) != 1) |
76 | 0 | return 0; |
77 | | |
78 | 0 | d = 0; |
79 | 0 | for (; bnb != 2; bnb = (bnb + 2) >> 1) |
80 | 0 | order[d++] = bnb; |
81 | |
|
82 | 0 | for (i = d - 1; i >= 0; i--) |
83 | 0 | { |
84 | 0 | bnb = order[i]; |
85 | 0 | bn = 1 + bnb / GMP_LIMB_BITS; |
86 | |
|
87 | 0 | mpn_sqrlo (tp, rp, bn); |
88 | 0 | mpn_mullo_n (tp2, rp, tp, bn); /* tp2 <- rp ^ 3 */ |
89 | |
|
90 | 0 | mpn_mul_1 (tp, rp, bn, 3); |
91 | |
|
92 | 0 | mpn_mullo_n (rp, yp, tp2, bn); |
93 | |
|
94 | 0 | #if HAVE_NATIVE_mpn_rsh1sub_n |
95 | 0 | mpn_rsh1sub_n (rp, tp, rp, bn); |
96 | | #else |
97 | | mpn_sub_n (tp2, tp, rp, bn); |
98 | | mpn_rshift (rp, tp2, bn, 1); |
99 | | #endif |
100 | 0 | } |
101 | 0 | } |
102 | 0 | return 1; |
103 | 0 | } |