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

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