4f8aff2cceea543c05740863e48ecef5c516ed9c
[ipdf/code.git] / src / arbint.cpp
1 #include "arbint.h"
2 #include <algorithm>
3 #include <cstring>
4
5
6 #include <string>
7 #include <iomanip>
8 #include <sstream>
9 #include <cstdarg>
10
11 using namespace std;
12
13 namespace IPDF
14 {
15
16 Arbint::Arbint(digit_t i) : m_digits(1), m_sign(i < 0)
17 {
18         m_digits[0] = i;
19 }
20
21 Arbint::Arbint(unsigned n, digit_t d0, ...) : m_digits(n), m_sign(false)
22 {
23         va_list ap;
24         va_start(ap, d0);
25         if (n > 1)
26                 m_digits[0] = d0;
27         for (unsigned i = 1; i < n; ++i)
28         {
29                 m_digits[i] = va_arg(ap, digit_t);
30         }
31         va_end(ap);
32 }
33
34 Arbint::Arbint(const Arbint & cpy) : m_digits(cpy.m_digits.size()), m_sign(cpy.m_sign)
35 {
36         memcpy(m_digits.data(), cpy.m_digits.data(), 
37                 sizeof(digit_t)*m_digits.size());
38 }
39
40 Arbint & Arbint::operator=(const Arbint & cpy)
41 {
42         memmove(m_digits.data(), cpy.m_digits.data(), 
43                 sizeof(digit_t)*min(m_digits.size(), cpy.m_digits.size()));
44         if (cpy.m_digits.size() > m_digits.size())
45         {
46                 unsigned old_size = m_digits.size();
47                 m_digits.resize(cpy.m_digits.size());
48                 memset(m_digits.data()+old_size, 0, sizeof(digit_t)*m_digits.size()-old_size);
49         }
50         return *this;
51 }
52
53 void Arbint::Zero()
54 {
55         memset(m_digits.data(), 0, sizeof(digit_t)*m_digits.size());
56 }
57
58 unsigned Arbint::Shrink()
59 {
60         if (m_digits.size() <= 1)
61                 return 0;
62         unsigned i;
63         for (i = m_digits.size()-1; (i > 0 && m_digits[i] != 0L); --i);
64         unsigned result = m_digits.size() - i;
65         m_digits.resize(i);
66         return result;
67 }
68
69 Arbint & Arbint::operator+=(const Arbint & add)
70 {
71         if (m_sign == add.m_sign)
72         {
73                 // -a + -b == -(a + b)
74                 return AddBasic(add);
75         }
76         
77         if (m_sign)
78         {
79                 // -a + b == -(a - b)
80                 m_sign = false;
81                 SubBasic(add);
82                 m_sign = !m_sign;
83         }
84         else
85         {
86                 // a + -b == a - b
87                 SubBasic(add);
88         }
89         return *this;
90 }
91
92 Arbint & Arbint::operator-=(const Arbint & sub)
93 {
94         if (m_sign == sub.m_sign)
95                 return SubBasic(sub);
96         return AddBasic(sub);
97 }
98
99 Arbint & Arbint::AddBasic(const Arbint & add)
100 {
101         if (add.m_digits.size() >= m_digits.size())
102         {
103                 m_digits.resize(add.m_digits.size()+1,0L);
104         }
105         
106         digit_t carry = add_digits((digit_t*)m_digits.data(), 
107                         (digit_t*)add.m_digits.data(), add.m_digits.size());
108         if (carry != 0L)
109                 m_digits[m_digits.size()-1] = carry;
110         else if (m_digits.back() == 0L)
111                 m_digits.resize(m_digits.size()-1);
112         return *this;
113 }
114
115 Arbint & Arbint::SubBasic(const Arbint & sub)
116 {
117         if (sub.m_digits.size() >= m_digits.size())
118         {
119                 m_digits.resize(sub.m_digits.size(),0L);
120         }
121         digit_t borrow = sub_digits((digit_t*)m_digits.data(), 
122                         (digit_t*)sub.m_digits.data(), sub.m_digits.size());
123                 
124                 
125         //TODO: Write ASM to do this bit?
126         if (borrow != 0L)
127         {
128                 m_sign = !m_sign;
129                 for (unsigned i = 0; i < m_digits.size(); ++i)
130                         m_digits[i] = -m_digits[i];
131         }
132         return *this;
133         return *this;
134 }
135
136
137 string Arbint::Str(const string & base) const
138 {
139         string s("");
140         for (unsigned i = 0; i < m_digits.size(); ++i)
141         {
142                 digit_t w = m_digits[i];
143                 do
144                 {
145                         digit_t q = w % 10;
146                         w /= 10;
147                         s += ('0' + q);
148                 }
149                 while (w > 0);
150                 if (i+1 < m_digits.size()) s += ",";    
151         }
152         reverse(s.begin(), s.end());
153         return s;
154 }
155
156 bool Arbint::operator==(const Arbint & equ) const
157 {
158         if (m_sign != equ.m_sign) return false;
159         unsigned min_size = m_digits.size();
160         const Arbint * larger = &equ;
161         if (m_digits.size() > equ.m_digits.size())
162         {
163                 min_size = equ.m_digits.size();
164                 larger = this;
165         }
166         
167         if (memcmp(m_digits.data(), equ.m_digits.data(), min_size) != 0)
168                 return false;
169         
170         for (unsigned i = min_size; i < larger->m_digits.size(); ++i)
171         {
172                 if (larger->m_digits[i] != 0L)
173                         return false;
174         }
175         return true;
176 }
177
178 string Arbint::DigitStr() const
179 {
180         stringstream ss("");
181         //ss << std::hex << std::setfill('0');
182         for (unsigned i = 0; i < m_digits.size(); ++i)
183         {
184                 if (i != 0) ss << ',';
185                 ss << std::setw(2*sizeof(digit_t)) << static_cast<digit_t>(m_digits[i]);
186         }
187         return ss.str();
188 }
189
190 }

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