ac3994260836d567fa94f636aaab305151f2bb32
[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         if (div.IsZero())
118         {
119                 result = *this;
120                 return;
121         }
122         for (int i = 8*sizeof(digit_t)*m_digits.size(); i >= 0; --i)
123         {
124                 remainder <<= 1;
125                 if (GetBit(i))
126                         remainder.BitSet(0);
127                 else
128                         remainder.BitClear(0);
129                 if (remainder >= div)
130                 {
131                         remainder -= div;
132                         result.BitSet(i);
133                 }
134         }
135         result.m_sign = !(m_sign == div.m_sign);
136 }
137
138 Arbint & Arbint::operator+=(const Arbint & add)
139 {
140         if (m_sign == add.m_sign)
141         {
142                 // -a + -b == -(a + b)
143                 return AddBasic(add);
144         }
145         
146         if (m_sign)
147         {
148                 // -a + b == -(a - b)
149                 m_sign = false;
150                 SubBasic(add);
151                 m_sign = !m_sign;
152         }
153         else
154         {
155                 // a + -b == a - b
156                 SubBasic(add);
157         }
158         return *this;
159 }
160
161 Arbint & Arbint::operator-=(const Arbint & sub)
162 {
163         if (m_sign == sub.m_sign)
164                 return SubBasic(sub);
165         return AddBasic(sub);
166 }
167
168 Arbint & Arbint::AddBasic(const Arbint & add)
169 {
170         if (add.m_digits.size() >= m_digits.size())
171         {
172                 m_digits.resize(add.m_digits.size()+1,0L);
173         }
174         
175         digit_t carry = add_digits((digit_t*)m_digits.data(), 
176                         (digit_t*)add.m_digits.data(), add.m_digits.size());
177         if (carry != 0L)
178                 m_digits[m_digits.size()-1] = carry;
179         else if (m_digits.back() == 0L)
180                 m_digits.resize(m_digits.size()-1);
181         return *this;
182 }
183
184 Arbint & Arbint::SubBasic(const Arbint & sub)
185 {
186         if (sub.m_digits.size() >= m_digits.size())
187         {
188                 m_digits.resize(sub.m_digits.size(),0L);
189         }
190         digit_t borrow = sub_digits((digit_t*)m_digits.data(), 
191                         (digit_t*)sub.m_digits.data(), sub.m_digits.size());
192                 
193                 
194         //TODO: Write ASM to do this bit?
195         if (borrow != 0L)
196         {
197                 m_sign = !m_sign;
198                 for (unsigned i = 0; i < m_digits.size(); ++i)
199                         m_digits[i] = -m_digits[i];
200         }
201         return *this;
202 }
203
204
205 string Arbint::Str(const string & base) const
206 {
207         string s("");
208         Arbint cpy(*this);
209         
210         reverse(s.begin(), s.end());
211         return s;
212 }
213
214 bool Arbint::IsZero() const
215 {
216         for (unsigned i = m_digits.size()-1; i > 0; --i)
217         {
218                 if (m_digits[i] != 0L) return false;
219         }
220         return (m_digits[0] == 0L);
221 }
222
223 bool Arbint::operator==(const Arbint & equ) const
224 {
225         if (m_sign != equ.m_sign) 
226                 return false;
227         unsigned min_size = m_digits.size();
228         const Arbint * larger = &equ;
229         if (m_digits.size() > equ.m_digits.size())
230         {
231                 min_size = equ.m_digits.size();
232                 larger = this;
233         }
234         
235         if (memcmp(m_digits.data(), equ.m_digits.data(), sizeof(digit_t)*min_size) != 0)
236                 return false;
237         
238         for (unsigned i = min_size; i < larger->m_digits.size(); ++i)
239         {
240                 if (larger->m_digits[i] != 0L)
241                         return false;
242         }
243         return true;
244 }
245
246 bool Arbint::operator<(const Arbint & less) const
247 {
248         Arbint cpy(*this);
249         cpy -= less;
250         return (cpy.m_sign && !cpy.IsZero());
251 }
252
253 string Arbint::DigitStr() const
254 {
255         stringstream ss("");
256         //ss << std::hex << std::setfill('0');
257         for (unsigned i = 0; i < m_digits.size(); ++i)
258         {
259                 if (i != 0) ss << ',';
260                 //ss << std::setw(2*sizeof(digit_t)) << static_cast<digit_t>(m_digits[i]);
261                 ss << static_cast<digit_t>(m_digits[i]);
262         }
263         return ss.str();
264 }
265
266 Arbint & Arbint::operator>>=(unsigned amount)
267 {
268         // Shift by whole number of digits
269         unsigned whole = amount/(8*sizeof(digit_t));
270         unsigned old_size = m_digits.size();
271         
272         if (whole >= old_size)
273         {
274                 m_digits.resize(1,0L);
275                 m_digits[0] = 0L;
276                 return *this;
277         }
278         memmove(m_digits.data(), m_digits.data()+whole, sizeof(digit_t)*(old_size-whole));
279         m_digits.resize(old_size-whole, 0L);
280         
281         // Shift by partial amount
282         amount = amount %(8*sizeof(digit_t));
283         if (amount == 0)
284                 return *this;
285         
286         digit_t underflow = 0L;
287         for (int i = (int)(m_digits.size()-1); i >= 0; --i)
288         {
289                 unsigned shl = (8*sizeof(digit_t)-amount);
290                 digit_t next_underflow = (m_digits[i] << shl);
291                 //digit_t mask_upper = ~(0L >> amount);
292                 m_digits[i] = (m_digits[i] >> amount);// & mask_upper;
293                 m_digits[i] |= underflow;
294                 underflow = next_underflow;
295         }
296         return *this;
297 }
298
299 Arbint & Arbint::operator<<=(unsigned amount)
300 {
301         // Shift by whole number of digits
302         unsigned whole = amount/(8*sizeof(digit_t));
303         unsigned old_size = m_digits.size();
304         m_digits.resize(m_digits.size() + whole);
305         memmove(m_digits.data()+whole, m_digits.data(), sizeof(digit_t)*old_size);
306         memset(m_digits.data(), 0L, whole*sizeof(digit_t));
307         
308         
309         
310         // Partial shifting
311         amount = amount % (8*sizeof(digit_t));
312         if (amount == 0)
313                 return *this;
314                 
315         //Debug("Shift by %u from %u", amount, whole);
316         digit_t overflow = 0L;
317         for (unsigned i = whole; i < m_digits.size(); ++i)
318         {
319                 //Debug("Digit is %.16lx", m_digits[i]);
320                 unsigned shr = (8*sizeof(digit_t)-amount);
321                 //Debug("shr is %u", shr);
322                 digit_t next_overflow = (m_digits[i] >> shr);
323                 //Debug("Next overflow %.16lx", next_overflow);
324                 m_digits[i] <<= amount;
325                 //Debug("Before overflow %.16lx", m_digits[i]);
326                 m_digits[i] |= overflow;
327                 overflow = next_overflow;
328         }
329         if (overflow != 0L)
330                 m_digits.push_back(overflow);
331                 
332         return *this;
333 }
334
335 bool Arbint::GetBit(unsigned i) const
336 {
337         unsigned digit = i/(8*sizeof(digit_t));
338         if (digit >= m_digits.size())
339                 return false;
340                 
341         i = i % (8*sizeof(digit_t));
342         
343         return (m_digits[digit] & (1L << i));
344         
345 }
346
347 void Arbint::BitClear(unsigned i)
348 {
349         unsigned digit = i/(8*sizeof(digit_t));
350         if (digit >= m_digits.size())
351                 return;
352         i = i % (8*sizeof(digit_t));
353         m_digits[digit] &= ~(1L << i);  
354 }
355
356 void Arbint::BitSet(unsigned i)
357 {
358         unsigned digit = i/(8*sizeof(digit_t));
359         if (digit >= m_digits.size())
360         {
361                 m_digits.resize(digit+1, 0L);
362         }
363         i = i % (8*sizeof(digit_t));
364         m_digits[digit] |= (1L << i);           
365 }
366
367 }

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