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

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