Arbint subtraction should work* now
[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         while (m_digits.size() < add.m_digits.size())
207         {
208                 
209                 Debug("Size is %u, add's size is %u", m_digits.size(), add.m_digits.size());
210                 GrowDigit(0L);
211         }
212         //m_digits.resize(add.m_digits.size()+1,0L);
213         
214         digit_t carry = add_digits((digit_t*)m_digits.data(), 
215                         (digit_t*)add.m_digits.data(), add.m_digits.size());
216         if (carry != 0L)
217         {
218                 Debug("Grow carry %lu", carry);
219                 GrowDigit(carry);
220         }
221         Shrink();
222         return *this;
223 }
224
225 Arbint & Arbint::SubBasic(const Arbint & sub)
226 {
227         bool fith = false;
228         while (sub.m_digits.size() > m_digits.size())
229         {
230                 fith = false;
231                 GrowDigit(0L);
232         }
233         if (fith)
234         {
235                 Debug("START sub was %c%s, I am %c%s", SignChar(), sub.DigitStr().c_str(), SignChar(), DigitStr().c_str());
236         }
237         
238         digit_t borrow = sub_digits((digit_t*)m_digits.data(), 
239                         (digit_t*)sub.m_digits.data(), sub.m_digits.size());
240                 
241         if (fith)
242         {
243                 Debug("SUB_DIGITS -> sub was %c%s, I am %c%s, borrow is %lu", SignChar(), sub.DigitStr().c_str(), SignChar(), DigitStr().c_str(), borrow);
244         }
245                 
246         //TODO: Write ASM to do this bit?
247         if (borrow != 0L)
248         {
249                 if (sub.m_digits.size() < m_digits.size())
250                 {
251                         m_digits[m_digits.size()-1] -= borrow;
252                 }
253                 else
254                 {
255                         m_sign = !m_sign;
256                         for (unsigned i = 0; i < m_digits.size(); ++i)
257                                 m_digits[i] = (~m_digits[i]);
258                         vector<digit_t> one_digits(m_digits.size(), 0L);
259                         one_digits[0] = 1L;
260                         add_digits((digit_t*)m_digits.data(), (digit_t*)one_digits.data(), m_digits.size());
261                 }
262         }
263         if (fith)
264         {
265                 Debug("END -> sub was %c%s, I am %c%s", sub.SignChar(), sub.DigitStr().c_str(), SignChar(), DigitStr().c_str());
266         }
267         Shrink();
268         if (fith)
269         {
270                 Debug("SHRUNK -> sub was %c%s, I am %c%s", sub.SignChar(), sub.DigitStr().c_str(), SignChar(), DigitStr().c_str());
271         }
272         return *this;
273 }
274
275
276 string Arbint::Str(const string & base) const
277 {
278         string s("");
279         Arbint cpy(*this);
280         
281         reverse(s.begin(), s.end());
282         return s;
283 }
284
285 bool Arbint::IsZero() const
286 {
287         for (unsigned i = m_digits.size()-1; i > 0; --i)
288         {
289                 if (m_digits[i] != 0L) return false;
290         }
291         return (m_digits[0] == 0L);
292 }
293
294 bool Arbint::operator==(const Arbint & equ) const
295 {
296         if (m_sign != equ.m_sign) 
297                 return false;
298         unsigned min_size = m_digits.size();
299         const Arbint * larger = &equ;
300         if (m_digits.size() > equ.m_digits.size())
301         {
302                 min_size = equ.m_digits.size();
303                 larger = this;
304         }
305         
306         if (memcmp(m_digits.data(), equ.m_digits.data(), sizeof(digit_t)*min_size) != 0)
307                 return false;
308         
309         for (unsigned i = min_size; i < larger->m_digits.size(); ++i)
310         {
311                 if (larger->m_digits[i] != 0L)
312                         return false;
313         }
314         return true;
315 }
316
317 bool Arbint::operator<(const Arbint & less) const
318 {
319         Arbint cpy(*this);
320         cpy -= less;
321         return (cpy.m_sign && !cpy.IsZero());
322 }
323
324 string Arbint::DigitStr() const
325 {
326         stringstream ss("");
327         //ss << std::hex << std::setfill('0');
328         for (unsigned i = 0; i < m_digits.size(); ++i)
329         {
330                 if (i != 0) ss << ',';
331                 //ss << std::setw(2*sizeof(digit_t)) << static_cast<digit_t>(m_digits[i]);
332                 ss << static_cast<digit_t>(m_digits[i]);
333         }
334         return ss.str();
335 }
336
337 Arbint & Arbint::operator>>=(unsigned amount)
338 {
339         // Shift by whole number of digits
340         unsigned whole = amount/(8*sizeof(digit_t));
341         unsigned old_size = m_digits.size();
342         
343         if (whole >= old_size)
344         {
345                 m_digits.resize(1,0L);
346                 m_digits[0] = 0L;
347                 return *this;
348         }
349         memmove(m_digits.data(), m_digits.data()+whole, sizeof(digit_t)*(old_size-whole));
350         m_digits.resize(old_size-whole, 0L);
351         
352         // Shift by partial amount
353         amount = amount %(8*sizeof(digit_t));
354         if (amount == 0)
355                 return *this;
356         
357         digit_t underflow = 0L;
358         for (int i = (int)(m_digits.size()-1); i >= 0; --i)
359         {
360                 unsigned shl = (8*sizeof(digit_t)-amount);
361                 digit_t next_underflow = (m_digits[i] << shl);
362                 //digit_t mask_upper = ~(0L >> amount);
363                 m_digits[i] = (m_digits[i] >> amount);// & mask_upper;
364                 m_digits[i] |= underflow;
365                 underflow = next_underflow;
366         }
367         Shrink();
368         return *this;
369 }
370
371 Arbint & Arbint::operator<<=(unsigned amount)
372 {
373         // Shift by whole number of digits
374         unsigned whole = amount/(8*sizeof(digit_t));
375         unsigned old_size = m_digits.size();
376         for (unsigned i = 0; i < whole; ++i)
377         {
378                 //Debug("i = %u, whole = %u", i, whole);
379                 GrowDigit(0L);//m_digits.resize(m_digits.size() + whole);
380         }
381         memmove(m_digits.data()+whole, m_digits.data(), sizeof(digit_t)*old_size);
382         memset(m_digits.data(), 0L, whole*sizeof(digit_t));
383         
384         
385         
386         // Partial shifting
387         amount = amount % (8*sizeof(digit_t));
388         if (amount == 0)
389                 return *this;
390                 
391         //Debug("Shift by %u from %u", amount, whole);
392         digit_t overflow = 0L;
393         for (unsigned i = whole; i < m_digits.size(); ++i)
394         {
395                 //Debug("Digit is %.16lx", m_digits[i]);
396                 unsigned shr = (8*sizeof(digit_t)-amount);
397                 //Debug("shr is %u", shr);
398                 digit_t next_overflow = (m_digits[i] >> shr);
399                 //Debug("Next overflow %.16lx", next_overflow);
400                 m_digits[i] <<= amount;
401                 //Debug("Before overflow %.16lx", m_digits[i]);
402                 m_digits[i] |= overflow;
403                 overflow = next_overflow;
404         }
405         if (overflow != 0L)
406                 m_digits.push_back(overflow);
407         Shrink();
408         return *this;
409 }
410
411 bool Arbint::GetBit(unsigned i) const
412 {
413         unsigned digit = i/(8*sizeof(digit_t));
414         if (digit >= m_digits.size())
415                 return false;
416                 
417         i = i % (8*sizeof(digit_t));
418         
419         return (m_digits[digit] & (1L << i));
420         
421 }
422
423 void Arbint::BitClear(unsigned i)
424 {
425         unsigned digit = i/(8*sizeof(digit_t));
426         if (digit >= m_digits.size())
427                 return;
428         i = i % (8*sizeof(digit_t));
429         m_digits[digit] &= ~(1L << i);  
430 }
431
432 void Arbint::BitSet(unsigned i)
433 {
434         unsigned digit = i/(8*sizeof(digit_t));
435         while (m_digits.size() < digit+1)
436         {
437                 //Debug("Grow BitSet Size %u, digit %u", m_digits.size(), digit);
438                 GrowDigit(0L);
439         }
440                 
441         i = i % (8*sizeof(digit_t));
442         m_digits[digit] |= (1L << i);           
443 }
444
445 }

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