batchgcd.c (2355B)
1 #include <err.h> 2 #include <fmpz.h> 3 #include <fmpz_vec.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 7 #include "prodtree.h" 8 #include "batchgcd.h" 9 10 static inline void 11 remtree_compute(fmpz *tree, const slong tree_size) 12 { 13 slong i = tree_size - 2; 14 slong parent_distance = 1; 15 16 while (1) { 17 fmpz_mul(&tree[i], &tree[i], &tree[i]); 18 fmpz_mod(&tree[i], &tree[i + parent_distance], &tree[i]); 19 parent_distance++; 20 i--; 21 22 fmpz_mul(&tree[i], &tree[i], &tree[i]); 23 fmpz_mod(&tree[i], &tree[i + parent_distance], &tree[i]); 24 if(i == 0) break; 25 i--; 26 } 27 } 28 29 void 30 batch_gcd(fmpz *r, const fmpz *v, slong n) 31 { 32 fmpz *tree; 33 slong tree_size, i; 34 35 tree_size = prodtree_compute(&tree, v, n); 36 remtree_compute(tree, tree_size); 37 38 for(i = 0; i < n; i++) { 39 fmpz_fdiv_q(&r[i], &tree[i], &v[i]); 40 fmpz_gcd(&r[i], &r[i], &v[i]); 41 } 42 43 free(tree); 44 } 45 46 static inline slong 47 upper_bound_2pow(const slong x) 48 { 49 slong r = 1; 50 51 while (r < x) { 52 r <<= 1; 53 54 if (r == 0) { 55 err(EXIT_FAILURE, "upper bound 2pow failure"); 56 } 57 } 58 59 return r; 60 } 61 62 // incomplete prodtree is like a prodtree, just that we do not compute 63 // the root 64 static inline slong 65 incomplete_prodtree_compute(fmpz** res, const fmpz *v, slong nv) 66 { 67 slong ubound = upper_bound_2pow(nv); 68 slong tree_size = 2 * ubound - 1; 69 slong i, j; 70 71 *res = _fmpz_vec_init(tree_size); 72 73 // row 0, v and padded with ones 74 for (i = 0; i < nv; i++) { 75 fmpz_set(&(*res)[i], &v[i]); 76 } 77 for (i = nv; i < ubound; i++) { 78 fmpz_set_ui(&(*res)[i], 1); 79 } 80 81 // rest, not root 82 j = 0; 83 for (i = ubound; i < tree_size-1; i++) { 84 fmpz_mul(&(*res)[i], &(*res)[j], &(*res)[j + 1]); 85 j += 2; 86 } 87 88 return tree_size; 89 } 90 91 void 92 pelofske_gcd(fmpz *r, const fmpz *v, slong n) 93 { 94 fmpz *tree; 95 fmpz *bvec; 96 fmpz *bbtree; 97 slong tree_size, i, ninb, bbtree_size; 98 99 tree_size = incomplete_prodtree_compute(&tree, v, n); 100 101 bvec = _fmpz_vec_init(tree_size); 102 ninb = 0; 103 104 for(i = 0; i < tree_size-1; i+=2) { 105 fmpz_gcd(&bvec[ninb], &tree[i], &tree[i+1]); 106 if (fmpz_cmp_ui(&bvec[ninb], 1) != 0) { 107 ninb++; 108 } 109 } 110 111 bbtree_size = prodtree_compute(&bbtree, bvec, ninb); 112 113 for(i = 0; i < n; i++) { 114 fmpz_gcd(&r[i], &bbtree[bbtree_size-1], &v[i]); 115 } 116 117 _fmpz_vec_clear(tree, tree_size); 118 _fmpz_vec_clear(bvec, tree_size); 119 _fmpz_vec_clear(bbtree, bbtree_size); 120 }