Divide some numbers by 5.
[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         
78         if (m_digits.size() <= 1)
79                 return 0;
80         
81         unsigned shrunk = 0;
82         while (m_digits.size() > 1 && m_digits[m_digits.size()-1] == 0L)
83         {
84                 //Debug("Shrink 1");
85                 m_digits.pop_back();
86                 shrunk++;
87         }
88         return shrunk;
89 }
90
91 void Arbint::GrowDigit(digit_t new_msd)
92 {
93         static unsigned total_grows = 0;
94         static unsigned biggest_arbint = 1;
95         m_digits.push_back(new_msd);
96         total_grows++;
97         if (m_digits.size() > biggest_arbint)
98         {
99                 biggest_arbint = m_digits.size();
100                 Warn("New biggest Arbint of size %u", m_digits.size());
101         }
102         //Warn("Arbint grows digit (%.16lx), this->m_digits.size() = %u, total grown = %u", new_msd, m_digits.size(), ++total_grows);
103         //if (total_grows++ > 10000)
104         //{
105         //      Fatal("Too many GrowDigit calls!");
106         //}
107 }
108
109 Arbint & Arbint::operator*=(const Arbint & mul)
110 {
111         vector<digit_t> new_digits(m_digits.size(), 0L);
112         new_digits.reserve(new_digits.size()+mul.m_digits.size());
113         for (unsigned i = 0; i < mul.m_digits.size(); ++i)
114         {
115                 vector<digit_t> step(m_digits.size()+i, 0L);
116                 memcpy(step.data()+i, m_digits.data(), sizeof(digit_t)*m_digits.size());
117                 
118                 digit_t overflow = mul_digits((digit_t*)step.data()+i, mul.m_digits[i], m_digits.size());
119                 if (overflow != 0L)
120                 {
121                         step.push_back(overflow);
122                 }
123                 new_digits.resize(max(new_digits.size(), step.size()), 0L);
124                 digit_t carry = add_digits((digit_t*)new_digits.data(), step.data(), step.size());
125                 if (carry != 0L)
126                 {
127                         Debug("Add carry");
128                         GrowDigit(carry);
129                 }
130         }
131         
132         m_digits.swap(new_digits);
133         m_sign = !(m_sign == mul.m_sign);
134         Shrink();
135         return *this;
136 }
137
138 void Arbint::Division(const Arbint & div, Arbint & result, Arbint & remainder) const
139 {
140         remainder = 0;
141         result = 0;
142         if (div.IsZero())
143         {
144                 result = *this;
145                 return;
146         }
147         /* may break things (even more that is)
148         else if (div.m_digits.size() == 1)
149         {
150                 result.m_digits.resize(m_digits.size(), 0L);
151                 remainder = Arbint(div_digits((digit_t*)&m_digits[0], div.m_digits[0], m_digits.size(), result.m_digits.data()));
152                 result.m_sign = !(m_sign == div.m_sign);
153                 return;
154         } */
155         
156         for (int i = 8*sizeof(digit_t)*m_digits.size(); i >= 0; --i)
157         {
158                 remainder <<= 1;
159                 if (GetBit(i))
160                         remainder.BitSet(0);
161                 else
162                         remainder.BitClear(0);
163                 if (remainder >= div)
164                 {
165                         remainder -= div;
166                         result.BitSet(i);
167                 }
168         }
169         result.m_sign = !(m_sign == div.m_sign);
170         result.Shrink();
171 }
172
173 Arbint & Arbint::operator+=(const Arbint & add)
174 {
175         if (m_sign == add.m_sign)
176         {
177                 // -a + -b == -(a + b)
178                 return AddBasic(add);
179         }
180         
181         if (m_sign)
182         {
183                 // -a + b == -(a - b)
184                 m_sign = false;
185                 SubBasic(add);
186                 m_sign = !m_sign;
187         }
188         else
189         {
190                 // a + -b == a - b
191                 SubBasic(add);
192         }
193         Shrink();
194         return *this;
195 }
196
197 Arbint & Arbint::operator-=(const Arbint & sub)
198 {
199         if (m_sign == sub.m_sign)
200                 return SubBasic(sub);
201         return AddBasic(sub);
202 }
203
204 Arbint & Arbint::AddBasic(const Arbint & add)
205 {
206         // Add any leading zeros to this number
207         while (m_digits.size() < add.m_digits.size())
208         {
209                 GrowDigit(0L);
210         }
211         //m_digits.resize(add.m_digits.size()+1,0L);
212         
213         digit_t carry = add_digits((digit_t*)m_digits.data(), 
214                         (digit_t*)add.m_digits.data(), add.m_digits.size());
215                         
216         // This number had more digits but there is a carry left over
217         if (carry != 0L && m_digits.size() > add.m_digits.size())
218         {
219                 vector<digit_t> carry_digits(m_digits.size() - add.m_digits.size(), 0L);
220                 carry_digits[0] = carry;
221                 carry = add_digits((digit_t*)m_digits.data()+add.m_digits.size(), 
222                         (digit_t*)carry_digits.data(), m_digits.size()-add.m_digits.size());
223         }
224         
225         // There is still a carry left over
226         if (carry != 0L)
227         {
228                 GrowDigit(carry);
229         }
230         Shrink();
231         return *this;
232 }
233
234 Arbint & Arbint::SubBasic(const Arbint & sub)
235 {
236         // Add leading zeros
237         while (sub.m_digits.size() > m_digits.size())
238         {
239                 GrowDigit(0L);
240         }
241         
242         // Do subtraction on digits
243         digit_t borrow = sub_digits((digit_t*)m_digits.data(), 
244                         (digit_t*)sub.m_digits.data(), sub.m_digits.size());
245
246         // This number had more digits but there is a borrow left over  
247         if (borrow != 0L && m_digits.size() > sub.m_digits.size())
248         {
249                 vector<digit_t> borrow_digits(m_digits.size()-sub.m_digits.size(), 0L);
250                 borrow_digits[0] = borrow;
251                 borrow = sub_digits((digit_t*)m_digits.data()+sub.m_digits.size(), 
252                         (digit_t*)borrow_digits.data(), m_digits.size()-sub.m_digits.size());
253         }
254         
255         // borrow is still set => number is negative
256         if (borrow != 0L)
257         {
258                 m_sign = !m_sign;
259                 for (unsigned i = 0; i < m_digits.size(); ++i)
260                         m_digits[i] = (~m_digits[i]);
261                 vector<digit_t> one_digits(m_digits.size(), 0L);
262                 one_digits[0] = 1L;
263                 add_digits((digit_t*)m_digits.data(), (digit_t*)one_digits.data(), m_digits.size());
264         }
265         Shrink();
266         return *this;
267 }
268
269
270 string Arbint::Str(const string & base) const
271 {
272         string s("");
273         Arbint cpy(*this);
274         
275         reverse(s.begin(), s.end());
276         return s;
277 }
278
279 bool Arbint::IsZero() const
280 {
281         for (unsigned i = m_digits.size()-1; i > 0; --i)
282         {
283                 if (m_digits[i] != 0L) return false;
284         }
285         return (m_digits[0] == 0L);
286 }
287
288 bool Arbint::operator==(const Arbint & equ) const
289 {
290         if (m_sign != equ.m_sign) 
291                 return false;
292         unsigned min_size = m_digits.size();
293         const Arbint * larger = &equ;
294         if (m_digits.size() > equ.m_digits.size())
295         {
296                 min_size = equ.m_digits.size();
297                 larger = this;
298         }
299         
300         if (memcmp(m_digits.data(), equ.m_digits.data(), sizeof(digit_t)*min_size) != 0)
301                 return false;
302         
303         for (unsigned i = min_size; i < larger->m_digits.size(); ++i)
304         {
305                 if (larger->m_digits[i] != 0L)
306                         return false;
307         }
308         return true;
309 }
310
311 bool Arbint::operator<(const Arbint & less) const
312 {
313         Arbint cpy(*this);
314         cpy -= less;
315         return (cpy.m_sign && !cpy.IsZero());
316 }
317
318 string Arbint::DigitStr() const
319 {
320         stringstream ss("");
321         //ss << std::hex << std::setfill('0');
322         for (unsigned i = 0; i < m_digits.size(); ++i)
323         {
324                 if (i != 0) ss << ',';
325                 //ss << std::setw(2*sizeof(digit_t)) << static_cast<digit_t>(m_digits[i]);
326                 ss << static_cast<digit_t>(m_digits[i]);
327         }
328         return ss.str();
329 }
330
331 Arbint & Arbint::operator>>=(unsigned amount)
332 {
333         // Shift by whole number of digits
334         unsigned whole = amount/(8*sizeof(digit_t));
335         unsigned old_size = m_digits.size();
336         
337         if (whole >= old_size)
338         {
339                 m_digits.resize(1,0L);
340                 m_digits[0] = 0L;
341                 return *this;
342         }
343         memmove(m_digits.data(), m_digits.data()+whole, sizeof(digit_t)*(old_size-whole));
344         m_digits.resize(old_size-whole, 0L);
345         
346         // Shift by partial amount
347         amount = amount %(8*sizeof(digit_t));
348         if (amount == 0)
349                 return *this;
350         
351         digit_t underflow = 0L;
352         for (int i = (int)(m_digits.size()-1); i >= 0; --i)
353         {
354                 unsigned shl = (8*sizeof(digit_t)-amount);
355                 digit_t next_underflow = (m_digits[i] << shl);
356                 //digit_t mask_upper = ~(0L >> amount);
357                 m_digits[i] = (m_digits[i] >> amount);// & mask_upper;
358                 m_digits[i] |= underflow;
359                 underflow = next_underflow;
360         }
361         Shrink();
362         return *this;
363 }
364
365 Arbint & Arbint::operator<<=(unsigned amount)
366 {
367         // Shift by whole number of digits
368         unsigned whole = amount/(8*sizeof(digit_t));
369         unsigned old_size = m_digits.size();
370         for (unsigned i = 0; i < whole; ++i)
371         {
372                 //Debug("i = %u, whole = %u", i, whole);
373                 GrowDigit(0L);//m_digits.resize(m_digits.size() + whole);
374         }
375         memmove(m_digits.data()+whole, m_digits.data(), sizeof(digit_t)*old_size);
376         memset(m_digits.data(), 0L, whole*sizeof(digit_t));
377         
378         
379         
380         // Partial shifting
381         amount = amount % (8*sizeof(digit_t));
382         if (amount == 0)
383                 return *this;
384                 
385         //Debug("Shift by %u from %u", amount, whole);
386         digit_t overflow = 0L;
387         for (unsigned i = whole; i < m_digits.size(); ++i)
388         {
389                 //Debug("Digit is %.16lx", m_digits[i]);
390                 unsigned shr = (8*sizeof(digit_t)-amount);
391                 //Debug("shr is %u", shr);
392                 digit_t next_overflow = (m_digits[i] >> shr);
393                 //Debug("Next overflow %.16lx", next_overflow);
394                 m_digits[i] <<= amount;
395                 //Debug("Before overflow %.16lx", m_digits[i]);
396                 m_digits[i] |= overflow;
397                 overflow = next_overflow;
398         }
399         if (overflow != 0L)
400                 m_digits.push_back(overflow);
401         Shrink();
402         return *this;
403 }
404
405 bool Arbint::GetBit(unsigned i) const
406 {
407         unsigned digit = i/(8*sizeof(digit_t));
408         if (digit >= m_digits.size())
409                 return false;
410                 
411         i = i % (8*sizeof(digit_t));
412         
413         return (m_digits[digit] & (1L << i));
414         
415 }
416
417 void Arbint::BitClear(unsigned i)
418 {
419         unsigned digit = i/(8*sizeof(digit_t));
420         if (digit >= m_digits.size())
421                 return;
422         i = i % (8*sizeof(digit_t));
423         m_digits[digit] &= ~(1L << i);  
424 }
425
426 void Arbint::BitSet(unsigned i)
427 {
428         unsigned digit = i/(8*sizeof(digit_t));
429         while (m_digits.size() < digit+1)
430         {
431                 //Debug("Grow BitSet Size %u, digit %u", m_digits.size(), digit);
432                 GrowDigit(0L);
433         }
434                 
435         i = i % (8*sizeof(digit_t));
436         m_digits[digit] |= (1L << i);           
437 }
438
439 }

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