/* ****************************************************************************** * 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 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