summaryrefslogtreecommitdiff
path: root/src/libbiguint/bu_divmod_internal.c
blob: 13d3583bc55bed27fa3b32e18708f240baedfea5 (plain)
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
/* ISC license. */

#include <skalibs/biguint.h>

/*
   u = u/a mod m. a and m must be relatively prime - otherwise, infinite loop.
   a is not immutable.
   Original idea: see http://research.sun.com/techrep/2001/abstract-95.html
*/

void bu_divmod_internal (uint32_t *u, uint32_t *a, uint32_t const *m, unsigned int n)
{
  uint32_t bb[n] ; uint32_t *b = bb ;
  uint32_t vv[n] ; uint32_t *v = vv ;
  bu_copy_internal(b, m, n) ;
  bu_zero(v, n) ;

 /*** XXX: this iterates like mad, should probably be optimized more */
  for (;;)
  {
    while (!(a[0] & 1))
    {
      bu_srb(a, n) ;
      if (u[0] & 1) bu_add(u, n, u, n, m, n) ;
      bu_srb(u, n) ;
    }
    if ((a[0] == 1) && (bu_len(a, n) == 1)) break ;
    if (bu_cmp(a, n, b, n) < 0)
    {
      uint32_t *t = a ; a = b ; b = t ;
      t = u ; u = v ; v = t ;
    }
    bu_add(a, n, a, n, b, n) ;
    bu_add(u, n, u, n, v, n) ;
  }
}