File: divide.cpp

package info (click to toggle)
monotone 0.31-6
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 20,680 kB
  • ctags: 14,801
  • sloc: cpp: 87,711; ansic: 64,862; sh: 5,691; lisp: 954; perl: 783; makefile: 509; python: 265; sql: 98; sed: 16
file content (100 lines) | stat: -rw-r--r-- 2,677 bytes parent folder | download
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
/*************************************************
* Division Algorithm Source File                 *
* (C) 1999-2005 The Botan Project                *
*************************************************/

#include <botan/numthry.h>
#include <botan/mp_core.h>

namespace Botan {

/*************************************************
* Solve x = q * y + r                            *
*************************************************/
void divide(const BigInt& x, const BigInt& y_arg, BigInt& q, BigInt& r)
   {
   BigInt y = y_arg;
   r = x;

   r.set_sign(BigInt::Positive);
   y.set_sign(BigInt::Positive);

   modifying_divide(r, y, q);

   if(x.sign() == BigInt::Negative)
      {
      q.flip_sign();
      if(r.is_nonzero()) { --q; r = y_arg.abs() - r; }
      }
   if(y_arg.sign() == BigInt::Negative)
      q.flip_sign();
   }

/*************************************************
* Solve x = q * y + r                            *
*************************************************/
void positive_divide(const BigInt& x, const BigInt& y_arg,
                     BigInt& q, BigInt& r)
   {
   BigInt y = y_arg;
   r = x;
   modifying_divide(r, y, q);
   }

/*************************************************
* Solve x = q * y + r                            *
*************************************************/
void modifying_divide(BigInt& x, BigInt& y, BigInt& q)
   {
   if(y.is_zero())
      throw BigInt::DivideByZero();
   if(x.is_negative() || y.is_negative())
      throw Invalid_Argument("Arguments to modifying_divide must be positive");

   s32bit compare = x.cmp(y);
   if(compare == -1) { q = 0; return; }
   if(compare ==  0) { q = 1; x = 0; return; }

   u32bit shifts = 0;
   while(y[y.sig_words()-1] < MP_WORD_TOP_BIT)
      { x <<= 1; y <<= 1; shifts++; }

   u32bit n = x.sig_words() - 1, t = y.sig_words() - 1;
   q.reg.create(n - t + 1);
   if(n <= t)
      {
      while(x > y) { x -= y; q.add(1); }
      x >>= shifts;
      return;
      }

   BigInt temp = y << (MP_WORD_BITS * (n-t));

   while(x >= temp) { x -= temp; q[n-t]++; }

   for(u32bit j = n; j != t; j--)
      {
      const word x_j0  = x.word_at(j);
      const word x_j1 = x.word_at(j-1);
      const word y_t  = y.word_at(t);

      if(x_j0 == y_t)
         q[j-t-1] = MP_WORD_MAX;
      else
         q[j-t-1] = bigint_divop(x_j0, x_j1, y_t);

      while(bigint_divcore(q[j-t-1], y_t, y.word_at(t-1),
                           x_j0, x_j1, x.word_at(j-2)))
         q[j-t-1]--;

      x -= (q[j-t-1] * y) << (MP_WORD_BITS * (j-t-1));
      if(x.is_negative())
         {
         x += y << (MP_WORD_BITS * (j-t-1));
         q[j-t-1]--;
         }
      }
   x >>= shifts;
   }

}