ffead.server.doc
Bigdecimal.cpp
1 /*
2  Copyright 2009-2012, Sumeet Chhetri
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 /*
17  * Bigdecimal.cpp
18  *
19  * Created on: 06-Mar-2013
20  * Author: sumeetc
21  */
22 
23 #include "Bigdecimal.h"
24 
25 Bigdecimal::Bigdecimal() {
26  isPositive = true;
27  this->parts.push_back(Bigint::ZERO_INT);
28  this->decimalDigits = 0;
29  this->decimalStartsAt = 0;
30 }
31 
32 Bigdecimal::~Bigdecimal() {
33 }
34 
35 Bigdecimal::Bigdecimal(string value)
36 {
37  create(value);
38 }
39 
40 void Bigdecimal::create(string value)
41 {
42  isPositive = true;
43  parts.clear();
44  string temp = StringUtil::trimCopy(value);
45  int minusSign = temp.find_last_of("-");
46  if(minusSign>0)
47  throw "Invalid -";
48  else if(minusSign==0)
49  {
50  isPositive = false;
51  temp = temp.substr(1);
52  }
53  if(temp.find_first_not_of("0")==string::npos)
54  {
55  this->decimalStartsAt = 0;
56  this->decimalDigits = 0;
57  isPositive = true;
58  this->parts.push_back(Bigint::ZERO_INT);
59  return;
60  }
61  temp = temp.substr(temp.find_first_not_of("0"));
62  if(temp.find(".")!=string::npos)
63  {
64  if(temp.find(".")!=temp.find_last_of("."))
65  {
66  throw "Invalid decimal Number";
67  }
68  else
69  {
70  decimalDigits = temp.length() - temp.find(".") - 1;
71  decimalStartsAt = (int)temp.find(".");
72  StringUtil::replaceFirst(temp, ".", "");
73  temp = temp.substr(0, temp.find_last_not_of("0")+1);
74  }
75  }
76  else
77  {
78  this->decimalStartsAt = 0;
79  this->decimalDigits = 0;
80  }
81  while((int)temp.length()>Bigint::NUM_LENGTH)
82  {
83  try {
84  int x = CastUtil::lexical_cast<int>(temp.substr(temp.length()-Bigint::NUM_LENGTH));
85  temp = temp.substr(0, temp.length()-Bigint::NUM_LENGTH);
86  parts.push_back(x);
87  } catch(...) {
88  throw "Invalid Bigdecimal value";
89  }
90  }
91  if(temp.length()>0)
92  {
93  try {
94  int x = CastUtil::lexical_cast<int>(temp);
95  parts.push_back(x);
96  } catch(...) {
97  throw "Invalid Bigdecimal value";
98  }
99  }
100  if(parts.at(parts.size()-1)==0)
101  parts.erase(parts.begin()+(parts.size()-1));
102  checkAndSetIfZero();
103 }
104 
105 void Bigdecimal::checkAndSetIfZero()
106 {
107  bool flag = false;
108  for (int i=0;i<(int)parts.size();i++) {
109  if(parts.at(i)>0)
110  {
111  flag = true;
112  break;
113  }
114  }
115  if(!flag || parts.size()==0)
116  {
117  parts.clear();
118  this->parts.push_back(Bigint::ZERO_INT);
119  isPositive = true;
120  }
121 }
122 
123 void Bigdecimal::add(Bigdecimal number)
124 {
125  string fval = toString();
126  string sval = number.toString();
127  int maxdecdigits = decimalDigits>number.decimalDigits?decimalDigits:number.decimalDigits;
128  for (int j = 0; j < maxdecdigits-decimalDigits; j++) {
129  fval.append(Bigint::ZERO);
130  }
131  for (int j = 0; j < maxdecdigits-number.decimalDigits; j++) {
132  sval.append(Bigint::ZERO);
133  }
134  StringUtil::replaceFirst(fval, ".", "");
135  StringUtil::replaceFirst(sval, ".", "");
136  Bigint fnum(fval);
137  Bigint snum(sval);
138  fnum.add(sval);
139  this->parts = fnum.parts;
140  this->isPositive = fnum.isPositive;
141  decimalDigits = (decimalDigits>number.decimalDigits?decimalDigits:number.decimalDigits);
142 }
143 
144 Bigdecimal Bigdecimal::operator+(Bigdecimal number)
145 {
146  Bigdecimal temp = *this;
147  temp.add(number);
148  return temp;
149 }
150 
151 Bigdecimal Bigdecimal::operator-(Bigdecimal number)
152 {
153  Bigdecimal temp = *this;
154  temp.subtract(number);
155  return temp;
156 }
157 
158 Bigdecimal Bigdecimal::operator*(Bigdecimal number)
159 {
160  Bigdecimal temp = *this;
161  temp.multiply(number);
162  return temp;
163 }
164 
165 Bigdecimal Bigdecimal::operator/(Bigdecimal number)
166 {
167  Bigdecimal temp = *this;
168  temp.divide(number);
169  return temp;
170 }
171 
172 Bigdecimal& Bigdecimal::operator++()
173 {
174  Bigdecimal temp("1");
175  this->add(temp);
176  return *this;
177 }
178 
179 Bigdecimal& Bigdecimal::operator+=(Bigdecimal number)
180 {
181  this->add(number);
182  return *this;
183 }
184 
185 Bigdecimal& Bigdecimal::operator--()
186 {
187  Bigdecimal temp("1");
188  this->subtract(temp);
189  return *this;
190 }
191 
192 Bigdecimal& Bigdecimal::operator-=(Bigdecimal number)
193 {
194  this->subtract(number);
195  return *this;
196 }
197 
198 bool operator==(Bigdecimal &lhs, Bigdecimal &rhs)
199 {
200  if(lhs.compare(rhs)==0)
201  return true;
202  return false;
203 }
204 
205 bool operator!=(Bigdecimal &lhs, Bigdecimal &rhs)
206 {
207  if(lhs.compare(rhs)!=0)
208  return true;
209  return false;
210 }
211 
212 bool operator<(Bigdecimal &lhs, Bigdecimal &rhs)
213 {
214  if(lhs.compare(rhs)==-1)
215  return true;
216  return false;
217 }
218 
219 bool operator<=(Bigdecimal &lhs, Bigdecimal &rhs)
220 {
221  if(lhs.compare(rhs)<=0)
222  return true;
223  return false;
224 }
225 
226 bool operator>(Bigdecimal &lhs, Bigdecimal &rhs)
227 {
228  if(lhs.compare(rhs)==1)
229  return true;
230  return false;
231 }
232 
233 bool operator>=(Bigdecimal &lhs, Bigdecimal &rhs)
234 {
235  if(lhs.compare(rhs)>=0)
236  return true;
237  return false;
238 }
239 
240 void Bigdecimal::subtract(Bigdecimal number)
241 {
242  string fval = toString();
243  string sval = number.toString();
244  int maxdecdigits = decimalDigits>number.decimalDigits?decimalDigits:number.decimalDigits;
245  for (int j = 0; j < maxdecdigits-decimalDigits; j++) {
246  fval.append(Bigint::ZERO);
247  }
248  for (int j = 0; j < maxdecdigits-number.decimalDigits; j++) {
249  sval.append(Bigint::ZERO);
250  }
251  StringUtil::replaceFirst(fval, ".", "");
252  StringUtil::replaceFirst(sval, ".", "");
253  Bigint fnum(fval);
254  Bigint snum(sval);
255  fnum.subtract(sval);
256  this->parts = fnum.parts;
257  this->isPositive = fnum.isPositive;
258  decimalDigits = (decimalDigits>number.decimalDigits?decimalDigits:number.decimalDigits);
259 }
260 
261 void Bigdecimal::multiply(Bigdecimal number)
262 {
263  string fval = toString();
264  string sval = number.toString();
265  int maxdecdigits = decimalDigits>number.decimalDigits?decimalDigits:number.decimalDigits;
266  for (int j = 0; j < maxdecdigits-decimalDigits; j++) {
267  fval.append(Bigint::ZERO);
268  }
269  for (int j = 0; j < maxdecdigits-number.decimalDigits; j++) {
270  sval.append(Bigint::ZERO);
271  }
272  StringUtil::replaceFirst(fval, ".", "");
273  StringUtil::replaceFirst(sval, ".", "");
274  Bigint fnum(fval);
275  Bigint snum(sval);
276  fnum.multiply(sval);
277  this->parts = fnum.parts;
278  this->isPositive = fnum.isPositive;
279  decimalDigits += number.decimalDigits;
280 }
281 
282 void Bigdecimal::divide(Bigdecimal number, int precision)
283 {
284  string fval = toString();
285  string sval = number.toString();
286  int maxdecdigits = decimalDigits>number.decimalDigits?decimalDigits:number.decimalDigits;
287  for (int j = 0; j < maxdecdigits-decimalDigits; j++) {
288  fval.append(Bigint::ZERO);
289  }
290  for (int j = 0; j < maxdecdigits-number.decimalDigits; j++) {
291  sval.append(Bigint::ZERO);
292  }
293  StringUtil::replaceFirst(fval, ".", "");
294  StringUtil::replaceFirst(sval, ".", "");
295  Bigint fnum(fval);
296  Bigint snum(sval);
297  fnum.internalDivide(sval, true, precision-1);
298  this->parts = fnum.parts;
299  this->isPositive = fnum.isPositive;
300  this->decimalStartsAt = fnum.decimalStartsAt;
301  decimalDigits -= number.decimalDigits;
302 }
303 
304 
305 int Bigdecimal::compare(Bigdecimal number1, Bigdecimal number2)
306 {
307  return number1.compare(number2);
308 }
309 
310 int Bigdecimal::compare(Bigdecimal number)
311 {
312  if(isPositive==number.isPositive)
313  {
314  string fnvalue = toString();
315  string snvalue = number.toString();
316  Bigint fnum, snum;
317  if(decimalStartsAt>0)
318  {
319  Bigint temp(fnvalue.substr(0, decimalStartsAt));
320  fnum = temp;
321  }
322  else
323  {
324  Bigint temp(fnvalue);
325  fnum = temp;
326  }
327  if(number.decimalStartsAt>0)
328  {
329  Bigint temp(snvalue.substr(0, number.decimalStartsAt));
330  snum = temp;
331  }
332  else
333  {
334  Bigint temp(snvalue);
335  snum = temp;
336  }
337  int compVal = fnum.compare(snum);
338  if(compVal==0)
339  {
340  string fmantstr = fnvalue.substr(decimalStartsAt+1, decimalDigits);
341  string smantstr = snvalue.substr(number.decimalStartsAt+1, number.decimalDigits);
342  int maxdecdigits = decimalDigits>number.decimalDigits?decimalDigits:number.decimalDigits;
343  for (int j = 0; j < maxdecdigits-decimalDigits; j++) {
344  fmantstr.append(Bigint::ZERO);
345  }
346  for (int j = 0; j < maxdecdigits-number.decimalDigits; j++) {
347  smantstr.append(Bigint::ZERO);
348  }
349  Bigint fmantissa(fmantstr);
350  Bigint smantissa(smantstr);
351  return fmantissa.compare(smantissa);
352  }
353  return compVal;
354  }
355  else if(isPositive && !number.isPositive)
356  {
357  return 1;
358  }
359  else
360  {
361  return -1;
362  }
363 }
364 
365 string Bigdecimal::toString()
366 {
367  if(parts.size()==0)
368  return Bigint::ZERO;
369  string build;
370  vector<int> nparts = parts;
371  std::reverse(nparts.begin(),nparts.end());
372  if(!isPositive)
373  {
374  build.append(Bigint::MINUS);
375  }
376  for (int i=0;i<(int)nparts.size();i++) {
377  if(i!=0)
378  {
379  string numstr = CastUtil::lexical_cast<string>(nparts.at(i));
380  for (int j = 0; j < Bigint::NUM_LENGTH-(int)numstr.length(); j++) {
381  build.append(Bigint::ZERO);
382  }
383  build.append(numstr);
384  }
385  else
386  {
387  build.append(CastUtil::lexical_cast<string>(nparts.at(i)));
388  }
389  }
390  if(decimalDigits>0)
391  {
392  build = build.substr(0, build.find_last_not_of("0")+1);
393  build = build.substr(0, build.length()-decimalDigits) + "." + build.substr(build.length()-decimalDigits);;
394  }
395  else if(decimalStartsAt>0)
396  {
397  build = build.substr(0, decimalStartsAt) + "." + build.substr(decimalStartsAt);
398  }
399  return build;
400 }