BigNum.cxx

Go to the documentation of this file.
00001 /**************************************************************************
00002  *
00003  * Copyright (C) 2007, The EROS Group, LLC.
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or
00007  * without modification, are permitted provided that the following
00008  * conditions are met:
00009  *
00010  *   - Redistributions of source code must contain the above
00011  *     copyright notice, this list of conditions, and the following
00012  *     disclaimer.
00013  *
00014  *   - Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions, and the following
00016  *     disclaimer in the documentation and/or other materials
00017  *     provided with the distribution.
00018  *
00019  *   - Neither the names of the copyright holders nor the names of any
00020  *     of any contributors may be used to endorse or promote products
00021  *     derived from this software without specific prior written
00022  *     permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00025  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00026  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00027  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00028  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00029  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00030  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00031  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00032  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00033  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00034  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00035  *
00036  **************************************************************************/
00037 
00038 #include <assert.h>
00039 #include <string>
00040 #include <string.h>  /* For memset() */
00041 #include <libsherpa/BigNum.hxx>
00042 #include <libsherpa/UExcept.hxx>
00043 
00044 // Note that this implementation relies on calloc() for the sake of
00045 // using realloc, but we only do this on heap-allocated arrays of
00046 // scalars so no consideration of destructor logic need apply.
00047 
00048 const uint64_t UINT32_T_MAX = 4294967295ull;
00049 
00055 static void *
00056 rmemset(void *s, int c, size_t n)
00057 {
00058   unsigned char *cp = (unsigned char *) s;
00059   for (size_t i = n; i > 0; i--)
00060     cp[i-1] = c;
00061 
00062   return s;
00063 }
00064 
00065 static inline uint32_t max(uint32_t a, uint32_t b)
00066 {
00067   return (a > b) ? a : b;
00068 }
00069 
00070 static inline uint32_t min(uint32_t a, uint32_t b)
00071 {
00072   return (a < b) ? a : b;
00073 }
00074 
00075 namespace sherpa {
00076   // These operate on "raw" vectors and sizes, which are assumed to *be*
00077   // vectors.
00078 
00079   struct nvec {
00080     size_t len;
00081     uint32_t *vec;
00082 
00083     inline nvec()
00084     {
00085       len = 0;
00086       vec = 0;
00087     }
00088 
00089     inline nvec(const sherpa::BigNum& bn)
00090     {
00091       if (bn.nDigits == 1) {
00092         len = 1;
00093         vec = (uint32_t *) &bn.oneDigit;
00094       }
00095       else {
00096         len = bn.nDigits;
00097         vec = (uint32_t *) bn.digits;
00098       }
00099     }
00100 
00101     inline nvec(size_t l, uint32_t *v)
00102     {
00103       len = l, vec = v;
00104     }
00105 
00106     inline uint64_t getDigit(size_t i) const
00107     {
00108       return (i >= len) ? 0 : vec[i];
00109     }
00110   } ;
00111 
00112   static uint32_t u_zero = 0;
00113   static const nvec nv_zero(1, &u_zero);
00114   static uint32_t u_one = 1;
00115   static const nvec nv_one(1, &u_one);
00116 
00120   static int
00121   vu_cmp(const nvec n1, const nvec n2)
00122   {
00123     // Recall that the arguments may be denormalized:
00124     size_t len = max(n1.len, n2.len);
00125 
00126     for (size_t i = 0; i < len; i++) {
00127       size_t pos = len - i - 1;
00128 
00129       if (n1.getDigit(pos) < n2.getDigit(pos))
00130         return -1;
00131       if (n1.getDigit(pos) > n2.getDigit(pos))
00132         return 1;
00133     }
00134 
00135     return 0;
00136   }
00137 
00141   static void
00142   vu_rshift_digits(const nvec n1, size_t nShift, nvec n2)
00143   {
00144     if (nShift > n1.len) {
00145       memset(n2.vec, 0, n2.len * sizeof(uint32_t));
00146       return;
00147     }
00148 
00149     for (size_t i = 0; i < min(n1.len - nShift, n2.len); i++)
00150       n2.vec[i] = n1.vec[i + nShift];
00151     for (size_t i = n1.len - nShift; i <n2.len; i++)
00152       n2.vec[i] = 0;
00153 
00154     return;
00155   }
00156 
00160   static void
00161   vu_lshift_digits(const nvec n1, size_t nShift, nvec n2)
00162   {
00163     for (size_t i = 0; i < min(n1.len, n2.len - nShift); i++)
00164       n2.vec[i+nShift] = n1.vec[i];
00165 
00166     for (size_t i = 0; i < nShift; i++)
00167       n2.vec[i] = 0;
00168 
00169     return;
00170   }
00171 
00175   static void
00176   vu_rshift_bits(const nvec n1, size_t nShift, nvec n2)
00177   {
00178     vu_rshift_digits(n1, nShift / 32, n2);
00179     nShift %= 32;
00180 
00181     for (size_t i = 0; i < n2.len; i++) {
00182       uint32_t u = n2.getDigit(i) >> nShift;
00183       u |= (n2.getDigit(i+1) << (32 - nShift));
00184 
00185       n2.vec[i] = u;
00186     }
00187 
00188     return;
00189   }
00190 
00194   static void
00195   vu_lshift_bits(const nvec n1, size_t nShift, nvec n2)
00196   {
00197     vu_lshift_digits(n1, nShift / 32, n2);
00198     nShift %= 32;
00199 
00200     for (size_t i = 0; i < min(n1.len, n2.len - nShift); i++) {
00201       size_t pos = n2.len - i - 1;
00202 
00203       uint32_t u = n2.getDigit(pos) << nShift;
00204       if (pos > 0)
00205         u |= n2.getDigit(pos-1) >> (32 - nShift);
00206       n2.vec[pos] = u;
00207     }
00208 
00209     return;
00210   }
00211 
00212   static inline unsigned
00213   vu_get_bit(const nvec n1, size_t bit)
00214   {
00215     return (n1.vec[bit/32] & (1u << (bit % 32))) ? 1 : 0;
00216   }
00217 
00218   static inline void
00219   vu_set_bit(nvec n1, size_t bit)
00220   {
00221     n1.vec[bit/32] |= (1u << (bit % 32));
00222   }
00223 
00224   static inline void
00225   vu_clear_bit(nvec n1, size_t bit)
00226   {
00227     n1.vec[bit/32] &= ~(1u << (bit % 32));
00228   }
00229 
00230   static inline void
00231   vu_copy(const nvec n1, nvec n2)
00232   {
00233     vu_lshift_digits(n1, 0, n2);
00234   }
00235 
00236   BigNum BigNum::lshift_digits(size_t n) const
00237   {
00238     if ((nDigits == 1) && (oneDigit == 0))
00239       return *this;
00240 
00241     if (n == 0)
00242       return *this;
00243 
00244     size_t nNewDigits = nDigits + n;
00245     uint32_t *newDigits = (uint32_t *) alloca(nNewDigits * sizeof(uint32_t));
00246     rmemset(newDigits, 0, nNewDigits * sizeof(uint32_t));
00247 
00248     for (size_t i = 0; i < nNewDigits; i++)
00249       newDigits[i+n] = getDigit(i);
00250 
00251     return BigNum(nNewDigits, newDigits, negative);
00252   }
00253 
00254 
00262   static void
00263   vu_sub(const nvec n1, const nvec n2, nvec n3)
00264   {
00265     uint64_t borrow = 0llu;
00266 
00267     assert(n1.len <= n3.len);
00268 
00269     for (size_t i = n1.len; i < n3.len; i++)
00270       n3.vec[i] = 0;
00271 
00272     for (size_t i = 0; i < n1.len; i++) {
00273       // Note that in the following carry does not get truncated but
00274       // oDigits[i] DOES.
00275       uint64_t n1digit = n1.getDigit(i);
00276       uint64_t n2digit = n2.getDigit(i) + borrow;
00277 
00278       borrow = 0;
00279       if (n1digit < n2digit) {
00280         n1digit += (UINT32_T_MAX + 1);
00281         borrow = 1;
00282       }
00283 
00284       assert(i < n3.len);
00285       n3.vec[i] = n1digit - n2digit;
00286     }
00287 
00288     assert(borrow == 0);
00289   }
00290 
00297   static void
00298   vu_add(const nvec n1, const nvec n2, nvec n3)
00299   {
00300     uint64_t carry = 0;
00301 
00302     for (size_t i = 0; i < n3.len; i++) {
00303       carry = n1.getDigit(i) + n2.getDigit(i) + carry;
00304       if (i < n3.len)
00305         n3.vec[i] = carry;      // truncates
00306       carry >>= 32;
00307     }
00308 
00309     assert(carry == 0);
00310   }
00311 
00318   static void
00319   vu_mul(const nvec n1, const nvec n2, nvec n3)
00320   {
00321     uint64_t carry = 0llu;
00322 
00323     nvec step;
00324     step.len = n1.len + n2.len;
00325     step.vec = (uint32_t *) alloca(step.len * sizeof(uint32_t));
00326     rmemset(step.vec, 0, step.len * sizeof(uint32_t));
00327 
00328     nvec result;
00329     result.len = n1.len + n2.len;
00330     result.vec = (uint32_t *) alloca(result.len * sizeof(uint32_t));
00331     rmemset(result.vec, 0, result.len * sizeof(uint32_t));
00332 
00333     for (size_t i = 0; i < n1.len; i++) {
00334       memset(step.vec, 0, step.len * sizeof(uint32_t));
00335       carry = 0llu;
00336 
00337       for (size_t j = 0; j < step.len; j++) {
00338         carry = n1.getDigit(i) * n2.getDigit(j) + carry;
00339         step.vec[i+j] = carry;  // truncating
00340         carry >>= 32;
00341       }
00342 
00343       vu_add(result, step, result);
00344     }
00345 
00346     assert(carry == 0);
00347     vu_copy(result, n3);
00348   }
00349 
00351   static void
00352   vu_divqr(const nvec dividend, const nvec divisor,
00353            nvec quotient, nvec remainder)
00354   {
00355     int cmp = vu_cmp(dividend, divisor);
00356     if (cmp < 0) {
00357       vu_copy(nv_zero, quotient);
00358       vu_copy(dividend, remainder);
00359       return;
00360     }
00361     else if (cmp == 0) {
00362       vu_copy(nv_one, quotient);
00363       vu_copy(nv_zero, remainder);
00364       return;
00365     }
00366 
00367     // Need to do things the hard way...
00368 
00369     nvec q;
00370     q.len = dividend.len;  // conservative
00371     q.vec = (uint32_t *) alloca(q.len * sizeof(uint32_t));
00372     rmemset(q.vec, 0, q.len * sizeof(uint32_t));
00373 
00374     // Internal working copies of quotient and remainder:
00375     nvec tmp;
00376     tmp.len = q.len + divisor.len;      // because of vu_mul requirement
00377     tmp.vec = (uint32_t *) alloca(tmp.len * sizeof(uint32_t));
00378 
00379     size_t bits = q.len * 32;
00380 
00381     for (size_t i = 0; i < bits; i++) {
00382       size_t bitndx = bits - i - 1;
00383 
00384       vu_set_bit(q, bitndx);
00385 
00386       vu_mul(divisor, q, tmp);
00387       if (vu_cmp(tmp, dividend) > 0)
00388         vu_clear_bit(q, bitndx);
00389     }
00390 
00391     vu_copy(q, quotient);
00392     vu_mul(divisor, q, tmp);
00393     vu_sub(dividend, tmp, remainder);
00394   }
00395 
00396   BigNum::~BigNum()
00397   {
00398     if (nDigits > 1)
00399       delete [] digits;
00400   }
00401 
00402   BigNum::BigNum(const BigNum& other)
00403   {
00404     negative = other.negative;
00405     nDigits = other.nDigits;
00406     if (nDigits > 1) {
00407       digits = new uint32_t[nDigits];
00408       for (size_t i = 0; i < nDigits; i++)
00409         digits[i] = other.digits[i];
00410     }
00411     else
00412       oneDigit = other.oneDigit;
00413   }
00414 
00415   BigNum& BigNum::operator=(const BigNum& other)
00416   {
00417     if (nDigits > 1)
00418       delete [] digits;
00419 
00420     negative = other.negative;
00421     nDigits = other.nDigits;
00422     if (nDigits > 1) {
00423       digits = new uint32_t[nDigits];
00424       for (size_t i = 0; i < nDigits; i++)
00425         digits[i] = other.digits[i];
00426     }
00427     else
00428       oneDigit = other.oneDigit;
00429 
00430     return *this;
00431   }
00432 
00433   BigNum::BigNum(uint64_t u, bool neg)
00434   {
00435     negative = neg;
00436     if (u > UINT32_T_MAX) {
00437       nDigits = 2;
00438       digits = new uint32_t[nDigits];
00439       digits[0] = u;            // truncating
00440       digits[1] = (u >> 32);
00441     }
00442     else {
00443       nDigits = 1;
00444       oneDigit = u;
00445     }
00446   }
00447 
00448   BigNum::BigNum(uint64_t u)
00449   {
00450     negative = false;
00451     if (u > UINT32_T_MAX) {
00452       nDigits = 2;
00453       digits = new uint32_t[nDigits];
00454       digits[0] = u;            // truncating
00455       digits[1] = (u >> 32);
00456     }
00457     else {
00458       nDigits = 1;
00459       oneDigit = u;
00460     }
00461   }
00462 
00463   BigNum::BigNum(int64_t i)
00464   {
00465     if (i < 0) {
00466       negative = true;
00467       i = -i;
00468     }
00469     else
00470       negative = false;
00471 
00472     // Rest proceeds as for uint64_t:
00473     uint64_t u = i;
00474     if (u > UINT32_T_MAX) {
00475       nDigits = 2;
00476       digits = new uint32_t[nDigits];
00477       digits[0] = u;            // truncating
00478       digits[1] = (u >> 32);
00479     }
00480     else {
00481       nDigits = 1;
00482       oneDigit = u;
00483     }
00484   }
00485 
00486   // This should be called *only* in return position, because it
00487   // potentially modifies an argument!!
00488   inline
00489   BigNum::BigNum(size_t _nDigits, uint32_t* _digits, bool _negative)
00490   {
00491     negative = _negative;
00492     nDigits = _nDigits;
00493 
00494     while (nDigits > 1 && (_digits[nDigits - 1] == 0))
00495       nDigits--;
00496 
00497     if (nDigits == 1) {
00498       oneDigit = _digits[0];
00499 
00500       if (oneDigit == 0)
00501         negative = false;
00502     }
00503     else {
00504       digits = new uint32_t[nDigits];
00505       for (size_t i = 0; i < nDigits; i++)
00506         digits[i] = _digits[i];
00507 
00508       return;
00509     }
00510   }
00511 
00512   BigNum::BigNum(const std::string& s, uint32_t radix)
00513   {
00514     // Defer setting is_negative, because the iterative multiplication
00515     // by radix can get the wrong answer if there is an even number of
00516     // digits.
00517 
00518     bool is_negative = false;
00519 
00520     // Initialize to zero so that we are well-formed for the loop below.
00521     negative = false;
00522     nDigits = 1;
00523     oneDigit = 0;
00524 
00525     size_t i = 0;
00526 
00527     if (s[0] == '-') {
00528       is_negative = true;
00529       i++;
00530     }
00531     else if (s[0] == '+') {
00532       i++;
00533     }
00534 
00535     if (radix == 0) {
00536       if (s[i] == '0' && ((s[i+1] == 'x') || (s[i+1] == 'X'))) {
00537         radix = 16;
00538         i += 2;
00539       }
00540       else if (s[i] == 0) {
00541         radix = 8;
00542         i += 1;
00543       }
00544       else
00545         radix = 10;
00546     }
00547 
00548     for (; i < s.size(); i++) {
00549       char c = s[i];
00550       uint32_t thisDigit = 0;
00551 
00552       if (c >= '0' && c <= '9')
00553         thisDigit = c - '0';
00554       else if (c >= 'a' && c <= 'f')
00555         thisDigit = 10 + (c - 'a');
00556       else if (c >= 'A' && c <= 'F')
00557         thisDigit = 10 + (c - 'A');
00558 
00559       *this = *this * radix + thisDigit;
00560     }
00561 
00562     if (is_negative)
00563       negative = is_negative;
00564   }
00565 
00566   BigNum BigNum::operator+(const BigNum& other) const
00567   {
00568     // Check if this is really addition:
00569     if (negative == other.negative) {
00570       const nvec nvother(other);
00571       const nvec nvthis(*this);
00572 
00573       nvec n3;
00574       n3.len = max(nvother.len, nvthis.len) + 1;
00575       n3.vec = (uint32_t *) alloca(n3.len * sizeof(uint32_t));
00576 
00577       vu_add(nvthis, nvother, n3);
00578 
00579       return BigNum(n3.len, n3.vec, negative);
00580     }
00581 
00582     if (negative)               // !other.negative
00583       return (other - this->abs());
00584 
00585     // !negative, other.negative
00586     return (*this - other.abs());
00587   }
00588 
00589   BigNum BigNum::operator-(const BigNum& other) const
00590   {
00591     const nvec nvother(other);
00592     const nvec nvthis(*this);
00593 
00594     // Check for addition in disguise:
00595     if (negative != other.negative) {
00596       size_t osize = max(nDigits, other.nDigits) + 1;
00597       uint32_t *oDigits = (uint32_t *) alloca(osize * sizeof(uint32_t));
00598 
00599       nvec n3(osize, oDigits);
00600       vu_add(nvthis, nvother, n3);
00601 
00602       return BigNum(n3.len, n3.vec, negative);
00603     }
00604 
00605     // Both negative or both positive: result sign follows magnitude:
00606     nvec n3;
00607     n3.len = max(nvother.len, nvthis.len);
00608     n3.vec = (uint32_t *) alloca(n3.len * sizeof(uint32_t));
00609 
00610     if (vu_cmp(nvthis, nvother) > 0) {
00611       vu_sub(nvthis, nvother, n3);
00612       return BigNum(n3.len, n3.vec, negative);
00613     }
00614     else {
00615       vu_sub(nvother, nvthis, n3);
00616       return BigNum(n3.len, n3.vec, !negative);
00617     }
00618 
00619   }
00620 
00621   BigNum BigNum::operator*(const BigNum& other) const
00622   {
00623     bool result_neg = (negative != other.negative);
00624 
00625     const nvec nvother(other);
00626     const nvec nvthis(*this);
00627 
00628     nvec n3;
00629     n3.len = nvother.len + nvthis.len;
00630     n3.vec = (uint32_t *) alloca(n3.len * sizeof(uint32_t));
00631 
00632     // u_mul is faster if argument is the shorter one.
00633     vu_mul(nvother, nvthis, n3);
00634 
00635     return BigNum(n3.len, n3.vec, result_neg);
00636   }
00637 
00638   BigNum BigNum::operator/(const BigNum& other) const
00639   {
00640     if (other == 0)
00641       THROW(excpt::BadValue, "Divide by zero");
00642 
00643     bool result_neg = (negative != other.negative);
00644 
00645     const nvec nvthis(*this);
00646     const nvec nvother(other);
00647 
00648     // Following are longer than we need, but required to satisfy
00649     // vu_sub input field length requirements.
00650     nvec r;                     // will be discarded
00651     r.len = nvthis.len;
00652     r.vec = (uint32_t *) alloca(r.len * sizeof(uint32_t));
00653 
00654     nvec q;
00655     q.len = nvthis.len;
00656     q.vec = (uint32_t *) alloca(q.len * sizeof(uint32_t));
00657 
00658     vu_divqr(nvthis, nvother, q, r);
00659 
00660     return BigNum(q.len, q.vec, result_neg);
00661   }
00662 
00663   BigNum BigNum::operator%(const BigNum& other) const
00664   {
00665     const nvec nvthis(*this);
00666     const nvec nvother(other);
00667 
00668     // Following are longer than we need, but required to satisfy
00669     // vu_sub input field length requirements.
00670     nvec r;
00671     r.len = nvthis.len;
00672     r.vec = (uint32_t *) alloca(r.len * sizeof(uint32_t));
00673 
00674     nvec q;                     // will be discarded
00675     q.len = nvthis.len;
00676     q.vec = (uint32_t *) alloca(q.len * sizeof(uint32_t));
00677 
00678     vu_divqr(nvthis, nvother, q, r);
00679 
00680     // remainder sign follows sign of *this:
00681     return BigNum(r.len, r.vec, negative);
00682   }
00683 
00684   int BigNum::cmp(const BigNum& other) const
00685   {
00686     if (negative == other.negative) {
00687       const nvec n1(*this);
00688       const nvec n2(other);
00689       int result= vu_cmp(n1, n2);
00690       return negative ? -result : result;
00691     }
00692     else if (negative)
00693       return -1;
00694     else
00695       return 1;
00696   }
00697 
00698   BigNum BigNum::abs() const
00699   {
00700     if (negative) {
00701       BigNum v = *this;
00702       v.negative = false;
00703       return v;
00704     }
00705     else
00706       return *this;
00707   }
00708 
00709   BigNum BigNum::neg() const
00710   {
00711     if (nDigits == 0 && oneDigit == 0)
00712       return *this;
00713 
00714     BigNum v = *this;
00715     v.negative = !negative;
00716     return v;
00717   }
00718 
00719   BigNum BigNum::operator<<(size_t n)
00720   {
00721     nvec nv;
00722     nv.len = nDigits + ((n+31)/32); // upper bound
00723     nv.vec = (uint32_t *) alloca(nv.len * sizeof(uint32_t));
00724 
00725     const nvec me(*this);
00726     vu_lshift_bits(me, n, nv);
00727 
00728     return BigNum(nv.len, nv.vec, negative);
00729   }
00730 
00731   BigNum BigNum::operator>>(size_t n)
00732   {
00733     nvec nv;
00734     nv.len = nDigits - (n/32);  // upper bound
00735     nv.vec = (uint32_t *) alloca(nv.len * sizeof(uint32_t));
00736 
00737     const nvec me(*this);
00738     vu_rshift_bits(me, n, nv);
00739 
00740     return BigNum(nv.len, nv.vec, negative);
00741   }
00742 
00743   std::string BigNum::asString(uint32_t radix) const
00744   {
00745     static const char *hexdigits = "0123456789ABCDEF";
00746     std::string s;
00747 
00748     if (negative)
00749       s.append(1, '-');
00750 
00751     if (radix == 16) {
00752       for (size_t i = 0; i < nDigits; i++) {
00753         size_t pos = nDigits - i - 1;
00754         uint32_t u = getDigit(pos);
00755 
00756         for (size_t hd = 0; hd < sizeof(u)*2; hd++) {
00757           uint32_t nibble = sizeof(u)*2 - hd - 1;
00758 
00759           uint32_t digit = (u >> (nibble * 4)) & 0xFu;
00760         
00761           if (digit == 0) {
00762             if (s.size())
00763               s.append(1, hexdigits[digit]);
00764           }
00765           else
00766             s.append(1, hexdigits[digit]);
00767         }
00768       }
00769 
00770       return s;
00771     }
00772     else {
00773       BigNum me = *this;
00774 
00775 #if 0
00776       BigNum lastPlace(radix);
00777       BigNum place(radix);
00778 
00779       while (place < *this) {
00780         lastPlace = place;
00781         place = lastPlace * radix;
00782       }
00783 
00784       // Place is now too big. Back off one:
00785       place = lastPlace;
00786 
00787       while (place != BigNum(0)) {
00788         BigNum thisDigit = me / place;
00789 
00790         if (thisDigit == 0) {
00791           if (s.size())
00792             s.append(1, hexdigits[thisDigit.oneDigit]);
00793         }
00794         else                    // non-zero digit
00795           s.append(1, hexdigits[thisDigit.oneDigit]);
00796 
00797         me = me - (thisDigit * place);
00798         place = place / radix;
00799       }
00800 
00801       if (s.size() == 0)
00802         s.append(1, '0');
00803 #else
00804       std::string result;
00805 
00806       while (me != 0) {
00807         BigNum thisDigit = me % radix;
00808 
00809         result.append(1, hexdigits[thisDigit.getDigit(0)]);
00810         
00811         me /= radix;
00812       }
00813 
00814       if (result.size() == 0)
00815         result.append(1, '0');
00816 
00817       for (size_t i = 0; i < result.size(); i++)
00818         s.append(1, result[result.size() - i - 1]);
00819 
00820 #endif
00821     }
00822 
00823     return s;
00824   }
00825 
00826   void BigNum::toStream(std::ostream& strm, uint32_t radix) const
00827   {
00828     strm << asString(radix);
00829   }
00830 
00831   void BigNum::fromStream(std::istream& strm, uint32_t radix)
00832   {
00833     *this = 0;
00834 
00835     for(;;) {
00836       char c;
00837       strm >> c;
00838 
00839       if ('0' <= c && c <= '9' && radix > (size_t)(c - '0')) {
00840         *this *= radix;
00841         *this += (c - '0');
00842       }
00843       else if (radix == 16 && 'a' <= c && c <= 'f') {
00844           *this *= radix;
00845           *this += (c - 'a' + 10);
00846       }
00847       else if (radix == 16 && 'A' <= c && c <= 'F') {
00848           *this *= radix;
00849           *this += (c - 'A' + 10);
00850       }
00851       else {
00852         strm.putback(c);
00853         return;
00854       }
00855     }
00856   }
00857 }

Generated on Sat Feb 4 23:59:28 2012 for BitC Compiler by  doxygen 1.4.7