59e22523c51b9d612626dc5f9f59833f8195b00b
[ipdf/code.git] / src / arbint.cpp
1 /**
2  * @file arbint.cpp
3  * @brief Arbitrary sized integer definitions
4  * @see arbint.h
5  * @see add_digits_asm.s
6  * @see sub_digits_asm.s
7  * @see mul_digits_asm.s
8  */
9
10 #include "arbint.h"
11 #include <algorithm>
12 #include <cstring>
13
14
15 #include <string>
16 #include <iomanip>
17 #include <sstream>
18 #include <cstdarg>
19
20 #include "rational.h"
21
22 using namespace std;
23
24 namespace IPDF
25 {
26         
27 /** Absolute value hackery **/
28 template <> Arbint Tabs(const Arbint & a)
29 {
30         //Debug("Called");
31         return a.Abs();
32 }
33
34
35 Arbint::Arbint(int64_t i) : m_digits(1), m_sign(i < 0)
36 {
37         m_digits[0] = llabs(i);
38 }
39
40 Arbint::Arbint(unsigned n, digit_t d0, ...) : m_digits(n), m_sign(false)
41 {
42         va_list ap;
43         va_start(ap, d0);
44         if (n >= 1)
45                 m_digits[0] = d0;
46         for (unsigned i = 1; i < n; ++i)
47         {
48                 m_digits[i] = va_arg(ap, digit_t);
49         }
50         va_end(ap);
51 }
52
53 Arbint::Arbint(const Arbint & cpy) : m_digits(cpy.m_digits), m_sign(cpy.m_sign)
54 {
55         
56 }
57
58 Arbint::Arbint(const vector<digit_t> & digits) : m_digits(digits), m_sign(false)
59 {
60         
61 }
62
63 Arbint & Arbint::operator=(const Arbint & cpy)
64 {
65         m_digits = cpy.m_digits;
66         m_sign = cpy.m_sign;
67         return *this;
68 }
69
70 void Arbint::Zero()
71 {
72         m_digits.resize(1, 0L);
73 }
74
75 unsigned Arbint::Shrink()
76 {
77         if (m_digits.size() <= 1)
78                 return 0;
79         unsigned i;
80         for (i = m_digits.size()-1; (i > 0 && m_digits[i] != 0L); --i);
81         unsigned result = m_digits.size() - i;
82         m_digits.resize(i);
83         return result;
84 }
85
86 Arbint & Arbint::operator*=(const Arbint & mul)
87 {
88         vector<digit_t> new_digits(m_digits.size(), 0L);
89         new_digits.reserve(new_digits.size()+mul.m_digits.size());
90         for (unsigned i = 0; i < mul.m_digits.size(); ++i)
91         {
92                 vector<digit_t> step(m_digits.size()+i, 0L);
93                 memcpy(step.data()+i, m_digits.data(), sizeof(digit_t)*m_digits.size());
94                 
95                 digit_t overflow = mul_digits((digit_t*)step.data()+i, mul.m_digits[i], m_digits.size());
96                 if (overflow != 0L)
97                 {
98                         step.push_back(overflow);
99                 }
100                 new_digits.resize(max(new_digits.size(), step.size()), 0L);
101                 digit_t carry = add_digits((digit_t*)new_digits.data(), step.data(), step.size());
102                 if (carry != 0L)
103                 {
104                         new_digits.push_back(carry);
105                 }
106         }
107         
108         m_digits.swap(new_digits);
109         m_sign = !(m_sign == mul.m_sign);
110         return *this;
111 }
112
113 void Arbint::Division(const Arbint & div, Arbint & result, Arbint & remainder) const
114 {
115         remainder = 0;
116         result = 0;
117         for (int i = 8*sizeof(digit_t)*m_digits.size(); i >= 0; --i)
118         {
119                 remainder <<= 1;
120                 if (GetBit(i))
121                         remainder.BitSet(0);
122                 else
123                         remainder.BitClear(0);
124                 if (remainder >= div)
125                 {
126                         remainder -= div;
127                         result.BitSet(i);
128                 }
129         }
130 }
131
132 Arbint & Arbint::operator+=(const Arbint & add)
133 {
134         if (m_sign == add.m_sign)
135         {
136                 // -a + -b == -(a + b)
137                 return AddBasic(add);
138         }
139         
140         if (m_sign)
141         {
142                 // -a + b == -(a - b)
143                 m_sign = false;
144                 SubBasic(add);
145                 m_sign = !m_sign;
146         }
147         else
148         {
149                 // a + -b == a - b
150                 SubBasic(add);
151         }
152         return *this;
153 }
154
155 Arbint & Arbint::operator-=(const Arbint & sub)
156 {
157         if (m_sign == sub.m_sign)
158                 return SubBasic(sub);
159         return AddBasic(sub);
160 }
161
162 Arbint & Arbint::AddBasic(const Arbint & add)
163 {
164         if (add.m_digits.size() >= m_digits.size())
165         {
166                 m_digits.resize(add.m_digits.size()+1,0L);
167         }
168         
169         digit_t carry = add_digits((digit_t*)m_digits.data(), 
170                         (digit_t*)add.m_digits.data(), add.m_digits.size());
171         if (carry != 0L)
172                 m_digits[m_digits.size()-1] = carry;
173         else if (m_digits.back() == 0L)
174                 m_digits.resize(m_digits.size()-1);
175         return *this;
176 }
177
178 Arbint & Arbint::SubBasic(const Arbint & sub)
179 {
180         if (sub.m_digits.size() >= m_digits.size())
181         {
182                 m_digits.resize(sub.m_digits.size(),0L);
183         }
184         digit_t borrow = sub_digits((digit_t*)m_digits.data(), 
185                         (digit_t*)sub.m_digits.data(), sub.m_digits.size());
186                 
187                 
188         //TODO: Write ASM to do this bit?
189         if (borrow != 0L)
190         {
191                 m_sign = !m_sign;
192                 for (unsigned i = 0; i < m_digits.size(); ++i)
193                         m_digits[i] = -m_digits[i];
194         }
195         return *this;
196 }
197
198
199 string Arbint::Str(const string & base) const
200 {
201         string s("");
202         Arbint cpy(*this);
203         
204         reverse(s.begin(), s.end());
205         return s;
206 }
207
208 bool Arbint::IsZero() const
209 {
210         for (unsigned i = m_digits.size()-1; i > 0; --i)
211         {
212                 if (m_digits[i] != 0L) return false;
213         }
214         return (m_digits[0] == 0L);
215 }
216
217 bool Arbint::operator==(const Arbint & equ) const
218 {
219         if (m_sign != equ.m_sign) 
220                 return false;
221         unsigned min_size = m_digits.size();
222         const Arbint * larger = &equ;
223         if (m_digits.size() > equ.m_digits.size())
224         {
225                 min_size = equ.m_digits.size();
226                 larger = this;
227         }
228         
229         if (memcmp(m_digits.data(), equ.m_digits.data(), sizeof(digit_t)*min_size) != 0)
230                 return false;
231         
232         for (unsigned i = min_size; i < larger->m_digits.size(); ++i)
233         {
234                 if (larger->m_digits[i] != 0L)
235                         return false;
236         }
237         return true;
238 }
239
240 bool Arbint::operator<(const Arbint & less) const
241 {
242         Arbint cpy(*this);
243         cpy -= less;
244         return (cpy.m_sign && !cpy.IsZero());
245 }
246
247 string Arbint::DigitStr() const
248 {
249         stringstream ss("");
250         //ss << std::hex << std::setfill('0');
251         for (unsigned i = 0; i < m_digits.size(); ++i)
252         {
253                 if (i != 0) ss << ',';
254                 //ss << std::setw(2*sizeof(digit_t)) << static_cast<digit_t>(m_digits[i]);
255                 ss << static_cast<digit_t>(m_digits[i]);
256         }
257         return ss.str();
258 }
259
260 Arbint & Arbint::operator>>=(unsigned amount)
261 {
262         // Shift by whole number of digits
263         unsigned whole = amount/(8*sizeof(digit_t));
264         unsigned old_size = m_digits.size();
265         
266         if (whole >= old_size)
267         {
268                 m_digits.resize(1);
269                 m_digits[0] = 0L;
270                 return *this;
271         }
272         memmove(m_digits.data(), m_digits.data()+whole, sizeof(digit_t)*(old_size-whole));
273         m_digits.resize(old_size-whole, 0L);
274         
275         // Shift by partial amount
276         amount = amount %(8*sizeof(digit_t));
277         if (amount == 0)
278                 return *this;
279         
280         digit_t underflow = 0L;
281         for (int i = (int)(m_digits.size()-1); i >= 0; --i)
282         {
283                 unsigned shl = (8*sizeof(digit_t)-amount);
284                 digit_t next_underflow = (m_digits[i] << shl);
285                 //digit_t mask_upper = ~(0L >> amount);
286                 m_digits[i] = (m_digits[i] >> amount);// & mask_upper;
287                 m_digits[i] |= underflow;
288                 underflow = next_underflow;
289         }
290         return *this;
291 }
292
293 Arbint & Arbint::operator<<=(unsigned amount)
294 {
295         // Shift by whole number of digits
296         unsigned whole = amount/(8*sizeof(digit_t));
297         unsigned old_size = m_digits.size();
298         m_digits.resize(m_digits.size() + whole);
299         memmove(m_digits.data()+whole, m_digits.data(), sizeof(digit_t)*old_size);
300         memset(m_digits.data(), 0L, whole*sizeof(digit_t));
301         
302         
303         
304         // Partial shifting
305         amount = amount % (8*sizeof(digit_t));
306         if (amount == 0)
307                 return *this;
308                 
309         //Debug("Shift by %u from %u", amount, whole);
310         digit_t overflow = 0L;
311         for (unsigned i = whole; i < m_digits.size(); ++i)
312         {
313                 //Debug("Digit is %.16lx", m_digits[i]);
314                 unsigned shr = (8*sizeof(digit_t)-amount);
315                 //Debug("shr is %u", shr);
316                 digit_t next_overflow = (m_digits[i] >> shr);
317                 //Debug("Next overflow %.16lx", next_overflow);
318                 m_digits[i] <<= amount;
319                 //Debug("Before overflow %.16lx", m_digits[i]);
320                 m_digits[i] |= overflow;
321                 overflow = next_overflow;
322         }
323         if (overflow != 0L)
324                 m_digits.push_back(overflow);
325                 
326         return *this;
327 }
328
329 bool Arbint::GetBit(unsigned i) const
330 {
331         unsigned digit = i/(8*sizeof(digit_t));
332         if (digit >= m_digits.size())
333                 return false;
334                 
335         i = i % (8*sizeof(digit_t));
336         
337         return (m_digits[digit] & (1L << i));
338         
339 }
340
341 void Arbint::BitClear(unsigned i)
342 {
343         unsigned digit = i/(8*sizeof(digit_t));
344         if (digit >= m_digits.size())
345                 return;
346         i = i % (8*sizeof(digit_t));
347         m_digits[digit] &= ~(1L << i);  
348 }
349
350 void Arbint::BitSet(unsigned i)
351 {
352         unsigned digit = i/(8*sizeof(digit_t));
353         if (digit >= m_digits.size())
354         {
355                 m_digits.resize(digit+1, 0L);
356         }
357         i = i % (8*sizeof(digit_t));
358         m_digits[digit] |= (1L << i);           
359 }
360
361 }

UCC git Repository :: git.ucc.asn.au