| /* | 
 | ****************************************************************************** | 
 | *   Copyright (C) 1997-2001, International Business Machines | 
 | *   Corporation and others.  All Rights Reserved. | 
 | ****************************************************************************** | 
 | *   file name:  llong.cpp | 
 | *   encoding:   US-ASCII | 
 | *   tab size:   8 (not used) | 
 | *   indentation:4 | 
 | * | 
 | * Modification history | 
 | * Date        Name      Comments | 
 | * 10/11/2001  Doug      Ported from ICU4J (thanks to Mike Cowlishaw) | 
 | */ | 
 |  | 
 | #include "llong.h" | 
 | #include <float.h> | 
 |  | 
 | U_NAMESPACE_BEGIN | 
 |  | 
 | #if 0 | 
 | /* | 
 |  * This should work, I think, but SOLARISCC -xO3 can't handle it. | 
 |  * Works with SOLARISGCC, SOLARISCC -g, Win32... | 
 |  * | 
 |  */ | 
 | const llong& llong::kMaxValue = llong(0x7fffffff, 0xffffffff); | 
 | const llong& llong::kMinValue = llong(0x80000000, 0x0); | 
 | const llong& llong::kMinusOne = llong(0xffffffff, 0xffffffff); | 
 | const llong& llong::kZero = llong(0x0, 0x0); | 
 | const llong& llong::kOne = llong(0x0, 0x1); | 
 | const llong& llong::kTwo = llong(0x0, 0x2); | 
 | const llong& llong::kMaxDouble = llong(0x200000, 0x0); | 
 | const llong& llong::kMinDouble = -kMaxDouble; | 
 |  | 
 | static llong kMaxValueObj(0x7fffffff, 0xffffffff); | 
 | static llong kMinValueObj(0x80000000, 0x0); | 
 | static llong kMinusOneObj(0xffffffff, 0xffffffff); | 
 | static llong kZeroObj(0x0, 0x0); | 
 | static llong kOneObj(0x0, 0x1); | 
 | static llong kTwoObj(0x0, 0x2); | 
 | static llong kMaxDoubleObj(0x200000, 0x0); | 
 | static llong kMinDoubleObj(-kMaxDoubleObj); | 
 |  | 
 | const llong& llong::kMaxValue = kMaxValueObj; | 
 | const llong& llong::kMinValue = kMinValueObj; | 
 | const llong& llong::kMinusOne = kMinusOneObj; | 
 | const llong& llong::kZero = kZeroObj; | 
 | const llong& llong::kOne = kOneObj; | 
 | const llong& llong::kTwo = kTwoObj; | 
 | const llong& llong::kMaxDouble = kMaxDoubleObj; | 
 | const llong& llong::kMinDouble = kMinDoubleObj; | 
 |  | 
 | const double llong::kDMax = llong_asDouble(kMaxDouble); | 
 | const double llong::kDMin = -kDMax; | 
 | #endif | 
 |  | 
 | #define SQRT231 46340 | 
 |  | 
 | // Keep all math as a double. Solaris 64-bit fails otherwise | 
 | const double llong::kD32 = ((double)((uint32_t)0xffffffffu)) + 1.0; | 
 |  | 
 | llong::llong(double d) { // avoid dependency on bit representation of double | 
 |     if (uprv_isNaN(d)) { | 
 |         hi = 0; | 
 |         lo = 0; /* zero */ | 
 |     } else { | 
 |         double mant = uprv_maxMantissa(); | 
 |         if (d < -mant) { | 
 |             d = -mant; | 
 |         } else if (d > mant) { | 
 |             d = mant; | 
 |         } | 
 |         UBool neg = d < 0;  | 
 |         if (neg) { | 
 |             d = -d; | 
 |         } | 
 |         d = uprv_floor(d); | 
 |         hi = (int32_t)uprv_floor(d / kD32); | 
 |         d -= kD32 * hi; | 
 |         lo = (uint32_t)d; | 
 |         if (neg) { | 
 |             negate(); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | llong& llong::operator*=(const llong& rhs) | 
 | { | 
 |     // optimize small positive multiplications | 
 |     if (hi == 0 && rhs.hi == 0 && lo < SQRT231 && rhs.lo < SQRT231) { | 
 |         lo *= rhs.lo; | 
 |     } else { | 
 |         int retry = 0; | 
 |  | 
 |         llong a(*this); | 
 |         if (a.isNegative()) { | 
 |             retry = 1; | 
 |             a.negate(); | 
 |         } | 
 |  | 
 |         llong b(rhs); | 
 |         if (b.isNegative()) { | 
 |             retry = 1; | 
 |             b.negate(); | 
 |         } | 
 |  | 
 |         llong r; | 
 |         // optimize small negative multiplications | 
 |         if (retry && a.hi == 0 && b.hi == 0 && a.lo < SQRT231 && b.lo < SQRT231) { | 
 |             r.lo = a.lo * b.lo; | 
 |         } else { | 
 |             if (a < b) { | 
 |                 llong t = a; | 
 |                 a = b; | 
 |                 b = t; | 
 |             } | 
 |             while (b.notZero()) { | 
 |                 if (b.lo & 0x1) { | 
 |                     r += a; | 
 |                 } | 
 |                 b.ushr(1); // in case someone came in with 0x80000000, 0x80000000 for b | 
 |                 a <<= 1; | 
 |             } | 
 |         } | 
 |         if (isNegative() != rhs.isNegative()) { | 
 |             r.negate(); | 
 |         } | 
 |         *this = r; | 
 |     } | 
 |     return *this; | 
 | } | 
 |  | 
 | llong& llong::operator/=(const llong& rhs)  | 
 | { | 
 |     if (isZero()) { | 
 |         return *this; | 
 |     } | 
 |     int32_t sign = 1; | 
 |     llong a(*this); | 
 |     if (a.isNegative()) { | 
 |         sign = -1; | 
 |         a.negate(); | 
 |     } | 
 |     llong b(rhs); | 
 |     if (b.isNegative()) { | 
 |         sign = -sign; | 
 |         b.negate(); | 
 |     } | 
 |  | 
 |     if (b.isZero()) { // should throw div by zero error | 
 |         *this = sign < 0 ? llong(0x80000000, 0) : llong(0x7fffffff, 0xffffffff); | 
 |     } else if (a.hi == 0 && b.hi == 0) { | 
 |         *this = (int32_t)(sign * (a.lo / b.lo)); | 
 |     } else if (b > a) { | 
 |         hi = 0; | 
 |         lo = 0; /* zero */ | 
 |     } else if (b == a) { | 
 |         *this = sign; | 
 |     } else { | 
 |         llong r; | 
 |         llong m((int32_t)1); | 
 |  | 
 |         while (b.ule(a)) { // a positive so topmost bit is 0, this will always terminate | 
 |             m <<= 1; | 
 |             b <<= 1; | 
 |         } | 
 |  | 
 |         do { | 
 |             m.ushr(1); // don't sign-extend! | 
 |             if (m.isZero()) break; | 
 |  | 
 |             b.ushr(1); | 
 |             if (b <= a) { | 
 |                 r |= m; | 
 |                 a -= b; | 
 |             } | 
 |         } while (a >= rhs); | 
 |  | 
 |         if (sign < 0) { | 
 |             r.negate(); | 
 |         } | 
 |         *this = r; | 
 |     } | 
 |     return *this; | 
 | } | 
 |  | 
 | static const uint8_t asciiDigits[] = {  | 
 |     0x30u, 0x31u, 0x32u, 0x33u, 0x34u, 0x35u, 0x36u, 0x37u, | 
 |     0x38u, 0x39u, 0x61u, 0x62u, 0x63u, 0x64u, 0x65u, 0x66u, | 
 |     0x67u, 0x68u, 0x69u, 0x6au, 0x6bu, 0x6cu, 0x6du, 0x6eu, | 
 |     0x6fu, 0x70u, 0x71u, 0x72u, 0x73u, 0x74u, 0x75u, 0x76u, | 
 |     0x77u, 0x78u, 0x79u, 0x7au,   | 
 | }; | 
 |  | 
 | static const UChar kUMinus = (UChar)0x002d; | 
 |  | 
 | static const char kMinus = '-'; | 
 |  | 
 | static const uint8_t digitInfo[] = { | 
 |         0,     0,     0,     0,     0,     0,     0,     0, | 
 |         0,     0,     0,     0,     0,     0,     0,     0, | 
 |         0,     0,     0,     0,     0,     0,     0,     0, | 
 |         0,     0,     0,     0,     0,     0,     0,     0, | 
 |         0,     0,     0,     0,     0,     0,     0,     0, | 
 |         0,     0,     0,     0,     0,     0,     0,     0, | 
 |     0x80u, 0x81u, 0x82u, 0x83u, 0x84u, 0x85u, 0x86u, 0x87u, | 
 |     0x88u, 0x89u,     0,     0,     0,     0,     0,     0, | 
 |         0, 0x8au, 0x8bu, 0x8cu, 0x8du, 0x8eu, 0x8fu, 0x90u, | 
 |     0x91u, 0x92u, 0x93u, 0x94u, 0x95u, 0x96u, 0x97u, 0x98u, | 
 |     0x99u, 0x9au, 0x9bu, 0x9cu, 0x9du, 0x9eu, 0x9fu, 0xa0u, | 
 |     0xa1u, 0xa2u, 0xa3u,     0,     0,     0,     0,     0, | 
 |         0, 0x8au, 0x8bu, 0x8cu, 0x8du, 0x8eu, 0x8fu, 0x90u, | 
 |     0x91u, 0x92u, 0x93u, 0x94u, 0x95u, 0x96u, 0x97u, 0x98u, | 
 |     0x99u, 0x9au, 0x9bu, 0x9cu, 0x9du, 0x9eu, 0x9fu, 0xa0u, | 
 |     0xa1u, 0xa2u, 0xa3u,     0,     0,     0,     0,     0, | 
 | }; | 
 |  | 
 | #ifdef RBNF_DEBUG | 
 | llong llong::atoll(const char* str, uint32_t radix) | 
 | { | 
 |     if (radix > 36) { | 
 |         radix = 36; | 
 |     } else if (radix < 2) { | 
 |         radix = 2; | 
 |     } | 
 |     llong lradix(radix); | 
 |  | 
 |     int neg = 0; | 
 |     if (*str == kMinus) { | 
 |         ++str; | 
 |         neg = 1; | 
 |     } | 
 |     llong result; | 
 |     uint8_t b; | 
 |     while ((b = digitInfo[*str++]) && ((b &= 0x7f) < radix)) { | 
 |         result *= lradix; | 
 |         result += (int32_t)b; | 
 |     } | 
 |     if (neg) { | 
 |         result.negate(); | 
 |     } | 
 |     return result; | 
 | } | 
 | #endif | 
 |  | 
 | llong llong::utoll(const UChar* str, uint32_t radix) | 
 | { | 
 |     if (radix > 36) { | 
 |         radix = 36; | 
 |     } else if (radix < 2) { | 
 |         radix = 2; | 
 |     } | 
 |     llong lradix(radix); | 
 |  | 
 |     int neg = 0; | 
 |     if (*str == kUMinus) { | 
 |         ++str; | 
 |         neg = 1; | 
 |     } | 
 |     llong result; | 
 |     UChar c; | 
 |     uint8_t b; | 
 |     while (((c = *str++) < 0x0080) && (b = digitInfo[c]) && ((b &= 0x7f) < radix)) { | 
 |         result *= lradix; | 
 |         result += (int32_t)b; | 
 |     } | 
 |     if (neg) { | 
 |         result.negate(); | 
 |     } | 
 |     return result; | 
 | } | 
 |  | 
 | #ifdef RBNF_DEBUG | 
 | uint32_t llong::lltoa(char* buf, uint32_t len, uint32_t radix, UBool raw) const | 
 | {     | 
 |     if (radix > 36) { | 
 |         radix = 36; | 
 |     } else if (radix < 2) { | 
 |         radix = 2; | 
 |     } | 
 |     llong base(radix); | 
 |  | 
 |     char* p = buf; | 
 |     llong w(*this); | 
 |     if (len && w.isNegative() && (radix == 10) && !raw) { | 
 |         w.negate(); | 
 |         *p++ = kMinus; | 
 |         --len; | 
 |     } else if (len && w.isZero()) { | 
 | 		*p++ = (char)raw ? 0 : asciiDigits[0]; | 
 | 		--len; | 
 |     } | 
 |  | 
 |     while (len && w.notZero()) { | 
 |         llong n = w / base; | 
 |         llong m = n * base; | 
 |         int32_t d = (w-m).asInt(); | 
 |         *p++ = raw ? (char)d : asciiDigits[d]; | 
 |         w = n; | 
 |         --len; | 
 |     } | 
 |     if (len) { | 
 |         *p = 0; // null terminate if room for caller convenience | 
 |     } | 
 |  | 
 |     len = p - buf; | 
 |     if (*buf == kMinus) { | 
 |         ++buf; | 
 |     } | 
 |     while (--p > buf) { | 
 |         char c = *p; | 
 |         *p = *buf; | 
 |         *buf = c; | 
 |         ++buf; | 
 |     } | 
 |  | 
 |     return len; | 
 | } | 
 | #endif | 
 |  | 
 | uint32_t llong::lltou(UChar* buf, uint32_t len, uint32_t radix, UBool raw) const | 
 | {     | 
 |     if (radix > 36) { | 
 |         radix = 36; | 
 |     } else if (radix < 2) { | 
 |         radix = 2; | 
 |     } | 
 |     llong base(radix); | 
 |  | 
 |     UChar* p = buf; | 
 |     llong w(*this); | 
 |     if (len && w.isNegative() && (radix == 10) && !raw) { | 
 |         w.negate(); | 
 |         *p++ = kUMinus; | 
 |         --len; | 
 |     } else if (len && w.isZero()) { | 
 | 		*p++ = (UChar)raw ? 0 : asciiDigits[0]; | 
 | 		--len; | 
 | 	} | 
 |  | 
 | 	while (len && w.notZero()) { | 
 | 		llong n = w / base; | 
 | 		llong m = n * base; | 
 | 		int32_t d = (w-m).asInt(); | 
 | 		*p++ = (UChar)(raw ? d : asciiDigits[d]); | 
 | 		w = n; | 
 | 		--len; | 
 | 	} | 
 |     if (len) { | 
 |         *p = 0; // null terminate if room for caller convenience | 
 |     } | 
 |  | 
 |     len = p - buf; | 
 |     if (*buf == kUMinus) { | 
 |         ++buf; | 
 |     } | 
 |     while (--p > buf) { | 
 |         UChar c = *p; | 
 |         *p = *buf; | 
 |         *buf = c; | 
 |         ++buf; | 
 |     } | 
 |  | 
 |     return len; | 
 | } | 
 |  | 
 | U_NAMESPACE_END |