123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332 |
- /*##############################################################################
- HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ############################################################################## */
- #include "platform.h"
- #include "nbcd.hpp"
- #include "jlib.hpp"
- #include "jexcept.hpp"
- #ifdef _WIN32
- #define NOMEMCPY volatile // stop VC++ doing a stupid optimization
- #else
- #define NOMEMCPY
- #endif
- static double Pow10[] = { 1, 10, 100, 1000, 10000, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10,1e11,1e12,1e13,1e14,1e15,1e16 };
- static int signMap[16] = { 0,0,0,0,0,0,0,0,0,0,+1,-1,+1,-1,+1,+1 };
- Decimal & Decimal::abs()
- {
- negative = false;
- return *this;
- }
- Decimal & Decimal::add(const Decimal & other)
- {
- if (negative == other.negative)
- return addDigits(other);
- else
- return subtractDigits(other);
- }
- Decimal & Decimal::addDigits(const Decimal & other)
- {
- extendRange(other);
- byte oLo = other.lsb;
- byte oHi = other.msb;
- byte hi = msb;
- unsigned idx;
- byte carry = 0;
- for (idx = oLo; (idx <= oHi); idx++)
- {
- digits[idx] += other.digits[idx] + carry;
- carry = 0;
- if (digits[idx] > 9)
- {
- carry++;
- digits[idx] -= 10;
- }
- }
- for (;carry && idx <= hi; idx++)
- {
- digits[idx]++;
- carry = 0;
- if (digits[idx] > 9)
- {
- carry = 1;
- digits[idx] -= 10;
- }
- }
- if (carry && hi != lastDigit)
- {
- digits[++hi] = carry;
- msb = hi;
- }
- return *this;
- }
- int Decimal::compareNull() const
- {
- byte idx;
- for (idx = lsb; idx <= msb; idx++)
- {
- if (digits[idx]) return negative ? -1 : +1;
- }
- return 0;
- }
- int Decimal::compare(const Decimal & other) const
- {
- int lo1, hi1, lo2, hi2;
- clip(lo1, hi1);
- other.clip(lo2, hi2);
- //First check for zero comparison..
- if (lo1 > hi1)
- {
- if (lo2 > hi2)
- return 0;
- return other.negative ? +1 : -1;
- }
- if (lo2 > hi2)
- return negative ? -1 : +1;
- if (negative ^ other.negative)
- return negative ? -1 : +1;
- if (hi1 != hi2)
- return (hi1 > hi2) ^ negative ? +1 : -1;
- int limit = lo1 < lo2 ? lo2 : lo1;
- for (;hi1 >= limit; hi1--)
- {
- int diff = digits[hi1] - other.digits[hi1];
- if (diff != 0)
- return (diff > 0) ^ negative ? +1 : -1;
- }
- if (lo1 == lo2)
- return 0;
- if (lo1 < lo2)
- return negative ? -1 : +1;
- return negative ? +1 : -1;
- }
- Decimal & Decimal::divide(const Decimal & other)
- {
- //NB: Round towards zero
- int lo1, hi1, lo2, hi2;
- clip(lo1, hi1);
- other.clip(lo2, hi2);
- int nd1 = hi1+1-lo1;
- int nd2 = hi2+1-lo2;
- int hi = (hi1-hi2)+zeroDigit; // how many digits will there be in the result
- int iters = hi+1;
- if (hi < 0)
- {
- setZero();
- return *this;
- }
- if (hi2 < lo2)
- {
- //Division by zero defined to return 0 instead of throw an exception
- setZero();
- return *this;
- }
- lsb = 0;
- msb = hi >= maxDigits ? maxDigits-1 : hi;
- const byte spare = 3;
- byte temp[maxDigits*2 + 3];
- unsigned numeratorDigits = (hi + 1) + nd2;
- memset(temp, 0, numeratorDigits+spare); // ensure two zero in msb, and below lsb. Also 2 zeros for looking 2 bytes ahead..
- byte * numerator = temp+spare;
- if (numeratorDigits > (unsigned)nd1)
- memcpy(numerator + numeratorDigits - 1 - nd1, digits+lo1, nd1);
- else
- memcpy(numerator, digits + hi1 + 1 - (numeratorDigits-1), numeratorDigits-1);
- unsigned divisor01 = other.digits[hi2] * 10;
- if (hi2 != lo2)
- divisor01 += other.digits[hi2-1];
- //MORE: Terminate early for exact divide..
- const byte * divisor = other.digits + lo2;
- for (int iter = iters; iter--; )
- {
- //The following guess for q is never too small, may be 1 too large
- byte * curNumerator = numerator + iter;
- unsigned numerator012 = curNumerator[nd2] * 100 + curNumerator[nd2-1] * 10 + curNumerator[nd2-2];
- unsigned q = numerator012 / divisor01;
- if (q == 10) q--;
- if (q)
- {
- unsigned carry = 0;
- for (int i = 0; i < nd2; i++)
- {
- int next = 90 + curNumerator[i] - divisor[i] * q - carry;
- div_t values = div(next, 10);
- carry = 9 - values.quot;
- curNumerator[i] = values.rem;
- }
- carry -= curNumerator[nd2];
- if (carry)
- {
- q--;
- assertex(carry==1);
- carry = 0;
- for (int i = 0; i < nd2; i++)
- {
- byte next = curNumerator[i] + divisor[i] + carry;
- carry = 0;
- if (next >= 10)
- {
- next -= 10;
- carry = 1;
- }
- curNumerator[i] = next;
- }
- assertex(carry);
- }
- }
- if (iter < maxDigits)
- digits[iter] = q;
- }
- //MORE: This should really calculate the next digit, and conditionally round the least significant digit.
- if (true)
- {
- //The following guess for q is never too small, may be 1 too large
- byte * curNumerator = numerator-1;
- unsigned numerator012 = curNumerator[nd2] * 100 + curNumerator[nd2-1] * 10 + curNumerator[nd2-2];
- unsigned q = numerator012 / divisor01;
- if (q == 5)
- {
- unsigned carry = 0;
- for (int i = 0; i < nd2; i++)
- {
- int next = 90 + curNumerator[i] - divisor[i] * q - carry;
- carry = 9 - next / 10;
- }
- carry -= curNumerator[nd2];
- if (carry)
- q--;
- }
- if (q >= 5)
- {
- for (int roundDigit=0; roundDigit < iters; roundDigit++)
- {
- unsigned next = digits[roundDigit]+1;
- if (next == 10)
- next = 0;
- digits[roundDigit] = next;
- if (next != 0)
- break;
- }
- }
- }
- negative ^= other.negative;
- return *this;
- }
- void Decimal::extendRange(byte oLsb, byte oMsb)
- {
- byte index;
- if (lsb > oLsb)
- {
- for (index = oLsb; index != lsb; index++)
- digits[index] =0;
- lsb = oLsb;
- }
- if (msb < oMsb)
- {
- for (index = msb+1; index <= oMsb; index++)
- digits[index] = 0;
- msb = oMsb;
- }
- }
- bool Decimal::isZero() const
- {
- //NB: Round towards zero
- int lo, hi;
- clip(lo, hi);
- return (hi < lo);
- }
- Decimal & Decimal::modulus(const Decimal & other)
- {
- Decimal left(*this);
- left.divide(other).truncate(0).multiply(other);
- return subtract(left);
- }
- Decimal & Decimal::multiply(const Decimal & other)
- {
- int low1, high1, low2, high2, lowt, hight;
- clip(low1, high1);
- other.clip(low2, high2);
- lowt = low1+low2-zeroDigit;
- if (lowt < 0) lowt = 0;
- hight = high1 + high2 - zeroDigit;
- if (hight >= maxDigits) hight = maxDigits-1;
- else if (hight < 0)
- {
- if (hight < -1)
- {
- setZero();
- return *this;
- }
- hight = 0;
- }
- unsigned temp[maxDigits*2];
- _clear(temp);
- // memset(temp+low1+low2, 0, (high1+high2-low1-low2+2)*sizeof(unsigned)); // only need to clear part of the target we're adding to.
- //More: could copy across 1st time round - might be worth it.
- const byte * digits1 = digits;
- const byte * digits2 = other.digits;
- for (int i = low1; i <= high1; i++)
- {
- byte next = digits1[i];
- if (next)
- {
- for (int j=low2; j <= high2; j++)
- temp[i+j] += next * digits2[j];
- }
- }
- //Now copy the results, taking care of the carries
- unsigned carry = 0;
- int j;
- for (j = low1+low2 - zeroDigit; j < lowt; j++)
- {
- unsigned next = temp[j+zeroDigit]+carry;
- //Round the least significant digit
- if (j+1 == lowt)
- next += 5;
- carry = next / 10;
- }
- for (j = lowt; j <= hight; j++)
- {
- div_t next = div(temp[j+zeroDigit]+carry, 10);
- digits[j] = next.rem;
- carry = next.quot;
- }
- while ((hight < maxDigits-1) && (carry != 0))
- {
- digits[++hight] = carry % 10;
- carry = carry / 10;
- }
- lsb = lowt;
- msb = hight;
- negative ^= other.negative;
- return *this;
- }
- Decimal & Decimal::negate()
- {
- negative = !negative;
- return *this;
- }
- Decimal & Decimal::power(unsigned value)
- {
- if (value == 0)
- setInt(1);
- else
- doPower(value);
- return *this;
- }
- Decimal & Decimal::power(int value)
- {
- if ( value >= 0)
- return power((unsigned)value);
- #if 1
- //This probably gives slightly more expected results, but both suffer from rounding errors.
- Decimal reciprocal;
- reciprocal.setInt(1);
- reciprocal.divide(*this);
- set(reciprocal);
- doPower((unsigned)-value);
- return *this;
- #else
- doPower((unsigned)-value);
- Decimal reciprocal;
- reciprocal.setInt(1);
- reciprocal.divide(*this);
- set(reciprocal);
- return *this;
- #endif
- }
- Decimal & Decimal::incLSD()
- {
- unsigned index = lsb;
- while (index <= msb)
- {
- if (++digits[index] != 10)
- {
- lsb = index;
- return *this;
- }
- digits[index] = 0;
- index++;
- }
- digits[++msb] = 1;
- return *this;
- }
- Decimal & Decimal::round(int places)
- {
- //out of range - either 0 or overflow
- if (places < -maxPrecision)
- {
- setZero();
- return *this;
- }
- if (zeroDigit - places <= lsb)
- return *this;
- lsb = zeroDigit - places;
- if (lsb > msb)
- {
- digits[lsb] = 0;
- if ((lsb == msb+1) && digits[msb] >= 5)
- digits[lsb]++;
- msb = lsb;
- return *this;
- }
- if (digits[lsb-1] < 5)
- return *this;
- return incLSD();
- }
- Decimal & Decimal::roundup(int places)
- {
- if ((places >= maxPrecision) || (zeroDigit - places <= lsb))
- return *this;
- unsigned lower = lsb;
- lsb = zeroDigit - places;
- for (unsigned i=lower; i < lsb; i++)
- {
- if (digits[i])
- return incLSD();
- }
- return *this;
- }
- void Decimal::getPrecision(unsigned & digits, unsigned & precision)
- {
- //Ensures digits>=precision && precision >= 0
- unsigned top = msb >= zeroDigit ? msb+1 : zeroDigit;
- unsigned low = lsb >= zeroDigit ? zeroDigit : lsb;
- digits = (top == low) ? 1 : top - low;
- precision = zeroDigit-low;
- }
- void Decimal::getClipPrecision(unsigned & digits, unsigned & precision)
- {
- int lo, hi;
- clip(lo, hi);
- if (lo > hi)
- {
- digits = 1;
- precision = 0;
- }
- else
- {
- //Ensures digits>=precision && precision >= 0
- unsigned top = hi >= zeroDigit ? hi+1 : zeroDigit;
- unsigned low = lo >= zeroDigit ? zeroDigit : lo;
- digits = (top == low) ? 1 : top - low;
- precision = zeroDigit-low;
- }
- }
- Decimal & Decimal::setPrecision(byte numDigits, byte precision)
- {
- unsigned char newhigh = zeroDigit + numDigits - precision - 1;
- unsigned char newlow = zeroDigit - precision;
- if (msb > newhigh)
- msb = newhigh;
- if (lsb < newlow)
- lsb = newlow;
- if (lsb > msb)
- {
- lsb = msb;
- digits[lsb] = 0;
- }
- return *this;
- }
- Decimal & Decimal::subtract(const Decimal & other)
- {
- if (negative != other.negative)
- return addDigits(other);
- else
- return subtractDigits(other);
- }
- Decimal & Decimal::subtractDigits(const Decimal & other)
- {
- extendRange(other);
- byte oLo = other.lsb;
- byte oHi = other.msb;
- byte hi = msb;
- unsigned idx;
- byte carry = 0;
- for (idx = oLo; (idx <= oHi); idx++)
- {
- int next = digits[idx] - (other.digits[idx] + carry);
- carry = 0;
- if (next < 0)
- {
- carry++;
- next += 10;
- }
- digits[idx] = next;
- }
- for (;carry && idx <= hi; idx++)
- {
- digits[idx]--;
- carry = 0;
- if (digits[idx] == 255)
- {
- carry = 1;
- digits[idx] += 10;
- }
- }
- if (carry)
- {
- //underflow => complement the result and add 1
- negative = !negative;
- carry = 1;
- for (idx = lsb; idx <= hi; idx++)
- {
- byte next = 9 - digits[idx] + carry;
- carry = 0;
- if (next == 10)
- {
- carry = 1;
- next -= 10;
- }
- digits[idx] = next;
- }
- assertex(!carry);
- }
- return *this;
- }
- Decimal & Decimal::truncate(int places)
- {
- //out of range - either 0 or overflow
- if (places <= -maxIntegerDigits)
- {
- setZero();
- return *this;
- }
- if (zeroDigit - places > lsb)
- {
- lsb = zeroDigit - places;
- if (lsb > msb)
- {
- digits[lsb] = 0;
- msb = lsb;
- }
- }
- return *this;
- }
- size32_t Decimal::getStringLength() const
- {
- int lo, hi;
- clip(lo, hi);
- if (lo > hi) // (lo == hi) && (digits[lo] == 0))
- return 1;
- byte top = (hi < zeroDigit) ? zeroDigit-1 : hi;
- byte bottom = (lo > zeroDigit) ? zeroDigit : lo;
- unsigned outLen = (top + 1 - bottom);
- if (negative) outLen++; // '-'
- if (lo < zeroDigit) outLen++; // '.'
- if (hi < zeroDigit) outLen++; // '0'
- return outLen;
- }
- void Decimal::getCString(size32_t length, char * buffer) const
- {
- unsigned len = getStringLength();
- if (len >= length)
- {
- memset(buffer, '*', length-1);
- buffer[length-1] = 0;
- return;
- }
- unsigned written = doGetString(buffer);
- assertex(len == written);
- buffer[len] = 0;
- }
- char * Decimal::getCString() const
- {
- unsigned len = getStringLength();
- char * buffer = (char *)malloc(len+1);
- unsigned written = doGetString(buffer);
- assertex(len == written);
- buffer[len] = 0;
- return buffer;
- }
- void Decimal::getDecimal(byte length, byte precision, void * buffer, byte signs) const
- {
- doGetDecimal(length, 2*length-1, precision, buffer);
- byte sign = negative ? (signs & 0x0f) : (signs >> 4);
- ((byte *)buffer)[length-1] |= sign;
- }
- __int64 Decimal::getInt64() const
- {
- unsigned __int64 value = getUInt64();
- if (negative)
- return -(__int64)value;
- return (__int64)value;
- }
- int Decimal::getInt() const
- {
- unsigned int value = getUInt();
- if (negative)
- return -(int) value;
- return (int) value;
- }
- double Decimal::getReal() const
- {
- int lo, hi;
- clip(lo, hi);
- double total = 0;
- byte sigDigits = 16; // Only worth taking 16 places over
- int i;
- for (i = hi; sigDigits && i >= lo; i--, sigDigits-- )
- total = total * 10 + digits[i];
- i++;
- if ( i > zeroDigit )
- {
- unsigned amount = i - zeroDigit;
- while ( amount > 15 )
- {
- total *= 1e16;
- amount -= 16;
- }
- total *= Pow10[ amount ];
- }
- else if ( i < zeroDigit )
- {
- unsigned amount = zeroDigit - i;
- while ( amount > 15 )
- {
- total /= 1e16;
- amount -= 16;
- }
- total /= Pow10[ amount ];
- }
- if (negative )
- return -total;
- else
- return total;
- }
- void Decimal::getString(size32_t length, char * buffer) const
- {
- unsigned len = getStringLength();
- if (len > length)
- {
- memset(buffer, '*', length);
- return;
- }
- unsigned written = doGetString(buffer);
- assertex(len == written);
- memset(buffer+len, ' ', length-len);
- }
- void Decimal::getStringX(size32_t & length, char * & buffer) const
- {
- unsigned len = getStringLength();
- buffer = (char *)malloc(len);
- unsigned written = doGetString(buffer);
- assertex(len == written);
- length = len;
- }
- void Decimal::getUDecimal(byte length, byte precision, void * buffer) const
- {
- doGetDecimal(length, 2*length, precision, buffer);
- }
- unsigned int Decimal::getUInt() const
- {
- const unsigned hi = msb;
- unsigned int value = 0;
- if (hi >= zeroDigit)
- {
- value = digits[hi];
- unsigned lo = lsb;
- if (lo < zeroDigit)
- {
- for (unsigned idx = hi-1; idx >= zeroDigit; idx--)
- value = value * 10 + digits[idx];
- }
- else
- {
- unsigned idx;
- for (idx = hi-1; idx >= lo; idx--)
- value = value * 10 + digits[idx];
- for (;idx >= zeroDigit;idx--)
- value *= 10;
- }
- }
- return value;
- }
- unsigned __int64 Decimal::getUInt64() const
- {
- //MORE: This isn't the most efficient way of doing it - see num2str in jutil for some hints.
- const unsigned hi = msb;
- unsigned __int64 value = 0;
- if (hi >= zeroDigit)
- {
- value = digits[hi];
- unsigned lo = lsb;
- if (lo < zeroDigit)
- {
- for (unsigned idx = hi-1; idx >= zeroDigit; idx--)
- value = value * 10 + digits[idx];
- }
- else
- {
- unsigned idx;
- for (idx = hi-1; idx >= lo; idx--)
- value = value * 10 + digits[idx];
- for (;idx >= zeroDigit;idx--)
- value *= 10;
- }
- }
- return value;
- }
- void Decimal::overflow()
- {
- }
- void Decimal::set(const Decimal & value)
- {
- memcpy(this, &value, sizeof(*this));
- }
- void Decimal::setCString(const char * buffer)
- {
- const char * cur = buffer;
- while (*cur == ' ')
- cur++;
- negative = false;
- if (*cur == '-')
- {
- negative = true;
- cur++;
- }
- const char * start = cur;
- while (isdigit(*cur))
- cur++;
- unsigned numDigits = (cur-start);
- if (numDigits > maxIntegerDigits)
- {
- overflow();
- numDigits = maxIntegerDigits;
- }
- int idx;
- for (idx = 0; (unsigned)idx < numDigits; idx++)
- digits[zeroDigit+idx] = cur[-(idx+1)] - '0'; // careful - if idx is unsigned, -(idx+1) is not sign-extended and fails if int size is not pointer size
- msb = zeroDigit+(numDigits-1);
- if (*cur == '.')
- {
- cur++;
- const char * start = cur;
- const char * limit = cur + maxPrecision;
- byte * digit = digits + zeroDigit;
- while ((cur < limit) && (isdigit(*cur)))
- *--digit = *cur++ - '0';
- lsb = zeroDigit - (cur-start);
- }
- else
- lsb = zeroDigit;
- }
- void Decimal::setDecimal(byte length, byte precision, const void * _buffer)
- {
- const byte * buffer = (const byte *)_buffer;
- lsb = zeroDigit - precision;
- msb = lsb + length*2 - 2;
- unsigned idx = 0;
- while (msb > maxDigits)
- {
- msb -= 2;
- idx++;
- }
- unsigned cur = msb;
- if (msb == maxDigits)
- {
- msb--;
- cur = msb;
- digits[cur--] = buffer[idx] & 0x0f;
- idx++;
- }
- for (; (int)idx < length-1; idx++)
- {
- byte next = buffer[idx];
- digits[cur--] = next >> 4;
- digits[cur--] = next & 0x0f;
- }
- byte next = buffer[idx];
- digits[cur--] = next >> 4;
- negative = (signMap[next & 0x0f] == -1);
- }
- void Decimal::setInt64(__int64 value)
- {
- if (value >= 0)
- setUInt64((unsigned __int64)value);
- else
- {
- setUInt64((unsigned __int64)-value);
- negative = true;
- }
- }
- void Decimal::setInt(int value)
- {
- if (value >= 0)
- setUInt((unsigned int)value);
- else
- {
- setUInt((unsigned int)-value);
- negative = true;
- }
- }
- void Decimal::setReal(double value)
- {
- setZero();
- int dec;
- int sign;
- char digitText[DOUBLE_SIG_DIGITS+2];
- if (!safe_ecvt(sizeof(digitText), digitText, value, DOUBLE_SIG_DIGITS, &dec, &sign))
- return;
- int len = DOUBLE_SIG_DIGITS;
- int hi = zeroDigit - 1 + dec;
- int lo = hi - (len -1);
- const char * finger = digitText;
- //Number too big - should it create a maximum value? or truncate as it currently does.
- if (hi >= maxDigits) // Most of this work is dealing with out of range cases
- {
- if (lo >= maxDigits)
- return;
-
- finger += (hi - (maxDigits-1));
- hi = maxDigits-1;
- }
-
- if (lo < 0)
- {
- if (hi < 0)
- return;
-
- lo = 0;
- }
-
- msb = hi;
- lsb = lo;
-
- for ( int i = hi; i >= lo; i-- )
- {
- byte next = *finger++ - '0';
- if (next < 10)
- digits[i] = next;
- else
- {
- //infinity????
- setZero();
- return;
- }
- }
- if (sign)
- negative = true;
- }
- void Decimal::setString(size32_t length, const char * buffer)
- {
- const char * limit = buffer+length;
- const char * cur = buffer;
- while ((cur < limit) && (*cur == ' '))
- cur++;
- negative = false;
- if ((cur < limit) && (*cur == '-'))
- {
- negative = true;
- cur++;
- }
- const char * start = cur;
- while ((cur < limit) && (isdigit(*cur)))
- cur++;
- unsigned numDigits = (cur-start);
- if (numDigits > maxIntegerDigits)
- {
- overflow();
- numDigits = maxIntegerDigits;
- }
- int idx;
- for (idx = 0; idx < (int)numDigits; idx++)
- digits[zeroDigit+idx] = cur[-(idx+1)] - '0'; // careful - if idx is unsigned, -(idx+1) is not sign-extended and fails if int size is not pointer size
- msb = zeroDigit+(numDigits-1);
- if ((cur < limit) && (*cur == '.'))
- {
- cur++;
- const char * start = cur;
- if (limit-cur > maxPrecision)
- limit = cur + maxPrecision;
- byte * digit = digits + zeroDigit;
- while ((cur < limit) && (isdigit(*cur)))
- *--digit = *cur++ - '0';
- lsb = zeroDigit - (cur-start);
- }
- else
- lsb = zeroDigit;
- }
- void Decimal::setUInt(unsigned int value)
- {
- negative = false;
- lsb = zeroDigit;
- unsigned idx = zeroDigit;
- while (value > 9)
- {
- unsigned int next = value / 10;
- digits[idx++] = value - next*10;
- value = next;
- }
- digits[idx] = value;
- msb = idx;
- }
- void Decimal::setUInt64(unsigned __int64 value)
- {
- negative = false;
- //MORE: This isn't the most efficient way of doing it - see num2str in jutil for some hints.
- lsb = zeroDigit;
- unsigned idx = zeroDigit;
- while (value > 9)
- {
- unsigned __int64 next = value / 10;
- digits[idx++] = (byte)(value - next*10);
- value = next;
- }
- digits[idx] = (byte)value;
- msb = idx;
- }
- void Decimal::setUDecimal(byte length, byte precision, const void * _buffer)
- {
- const byte * buffer = (const byte *)_buffer;
- lsb = zeroDigit - precision;
- msb = lsb + length*2 - 1;
- unsigned cur = msb;
- for (unsigned idx=0; idx < length; idx++)
- {
- byte next = buffer[idx];
- digits[cur--] = next >> 4;
- digits[cur--] = next & 0x0f;
- }
- negative = false;
- }
- //-- helper functions:
- void Decimal::clip(int & newLsb, int & newMsb) const
- {
- int lo = lsb;
- int hi = msb;
- while (digits[lo] == 0 && lo < hi)
- lo++;
- while (digits[hi] == 0 && hi >= lo)
- hi--;
- newLsb = lo;
- newMsb = hi;
- }
- void Decimal::clip(int & newLsb, int & newMsb, unsigned minLsb, unsigned maxMsb) const
- {
- clip(newLsb, newMsb);
- if (newLsb < (int)minLsb)
- newLsb = minLsb;
- if (newMsb > (int)maxMsb)
- newMsb = maxMsb;
- if (newMsb < newLsb)
- newMsb = newLsb-1;
- }
- unsigned Decimal::doGetString(char * buffer) const
- {
- char * cur = buffer;
- int lo, hi;
- clip(lo, hi);
- if (lo > hi) // || (lo == hi) && (digits[hi] == 0))
- {
- *cur = '0';
- return 1;
- }
- if (negative)
- *cur++ = '-';
- int idx;
- if (hi < zeroDigit)
- {
- *cur++ = '0';
- *cur++ = '.';
- for (idx = zeroDigit-1; idx > hi; idx--)
- *cur++ = '0';
- for (;idx >= lo; idx--)
- *cur++ = '0' + digits[idx];
- }
- else
- {
- if (lo < zeroDigit)
- {
- for (idx = hi; idx >= zeroDigit; idx--)
- *cur++ = '0' + digits[idx];
- *cur++ = '.';
- for (; idx >= lo; idx--)
- *cur++ = '0' + digits[idx];
- }
- else
- {
- for (idx = hi; idx >= lo; idx--)
- *cur++ = '0' + digits[idx];
- for (; idx >= zeroDigit; idx--)
- *cur++ = '0';
- }
- }
- return cur-buffer;
- }
- void Decimal::doGetDecimal(byte length, byte maxDigits, byte precision, void * buffer) const
- {
- int tgtHighPos = zeroDigit+maxDigits-precision-1;
- int tgtLowPos = tgtHighPos - length*2 + 1;
- int lowPos, highPos;
- clip(lowPos, highPos, zeroDigit-precision, zeroDigit+maxDigits-precision-1);
- if ((lowPos > highPos) || (highPos > tgtHighPos))
- {
- //zero or overflow...
- memset(buffer, 0, length);
- return;
- }
- int copyHighPos = highPos;
- if (tgtLowPos > copyHighPos)
- copyHighPos = tgtLowPos;
- else if (tgtHighPos < copyHighPos)
- copyHighPos = tgtHighPos; // overflow....
- int copyLowPos = lowPos;
- if (tgtLowPos > copyLowPos)
- copyLowPos = tgtLowPos;
- NOMEMCPY byte * tgt = (byte *)buffer;
- //First pad with zeros.
- if (tgtHighPos > copyHighPos)
- {
- unsigned zeros = tgtHighPos-copyHighPos;
- while (zeros >= 2)
- {
- *tgt++ = 0;
- zeros -= 2;
- }
- if (zeros != 0)
- *tgt++ = digits[copyHighPos--];
- }
- //Now will with characters
- while (copyLowPos < copyHighPos)
- {
- byte next = digits[copyHighPos];
- byte next2 = digits[copyHighPos-1];
- *tgt++ = (byte)(next << 4) | next2;
- copyHighPos -= 2;
- }
- if (copyLowPos == copyHighPos)
- {
- *tgt++ = digits[copyLowPos] << 4;
- copyLowPos -= 2;
- }
- while (copyLowPos > tgtLowPos)
- {
- *tgt++ = 0;
- copyLowPos -= 2;
- }
- }
- void Decimal::doPower(unsigned value)
- {
- if (value == 1)
- return;
- if (value & 1)
- {
- Decimal saved(*this);
- doPower(value >> 1);
- multiply(*this);
- multiply(saved);
- }
- else
- {
- doPower(value >> 1);
- multiply(*this);
- }
- }
- void Decimal::setZero()
- {
- negative = false;
- lsb = msb = zeroDigit;
- digits[zeroDigit] = 0;
- }
- //---------------------------------------------------------------------------
- bool dec2Bool(size32_t bytes, const void * _data)
- {
- const byte * data = (const byte *)_data;
- //ignore the sign
- if (data[--bytes] & 0xf0)
- return true;
- while (bytes--)
- if (*data++)
- return true;
- return false;
- }
- bool udec2Bool(size32_t bytes, const void * _data)
- {
- const byte * data = (const byte *)_data;
- while (bytes--)
- if (*data++)
- return true;
- return false;
- }
- int decCompareDecimal(size32_t bytes, const void * _left, const void * _right)
- {
- const byte * left = (const byte *)_left;
- const byte * right = (const byte *)_right;
- bytes--;
- byte signLeft = left[bytes] & 0x0f;
- byte signRight = right[bytes] & 0x0f;
- if (signMap[signLeft] != signMap[signRight])
- {
- int res = signMap[signLeft] - signMap[signRight];
- // could be +0 and -0......
- if ((left[bytes] & 0xf0) || (right[bytes] & 0xf0))
- return res;
- while (bytes--)
- if (left[bytes] || right[bytes])
- return res;
- return 0;
- }
- bool numbersAreNegative = (signMap[signLeft] == -1);
- while (bytes--)
- {
- byte l = *left++;
- byte r = *right++;
- int res = l - r;
- if (res)
- return numbersAreNegative ? -res : res;
- }
- int res = (*left & 0xf0) - (*right & 0xf0);
- if (res)
- return numbersAreNegative ? -res : res;
- return 0;
- }
- int decCompareUDecimal(size32_t bytes, const void * _left, const void * _right)
- {
- const byte * left = (const byte *)_left;
- const byte * right = (const byte *)_right;
- while (bytes--)
- {
- byte l = *left++;
- byte r = *right++;
- int res = l - r;
- if (res)
- return res;
- }
- return 0;
- }
- bool decValid(bool isSigned, unsigned digits, const void * data)
- {
- if (data && digits)
- {
- if ((isSigned && digits % 2 == 0) || (!isSigned && digits % 2 != 0))
- {
- if (*((byte*)data)&0xf0)
- return false;
- digits++;
- }
- unsigned bytes = isSigned ? digits/2+1 : (digits+1)/2;
- byte *dp = (byte * )data;
- if (isSigned)
- {
- byte sign = dp[--bytes] & 0x0f;
- // allow 0x0F and 0x0C for positive and 0x0D for negative signs
- if (!(sign == 0x0f || sign == 0x0d || sign == 0x0c))
- return false;
- if ((byte)(dp[bytes] & 0xf0u) > 0x90u)
- return false;
- }
- // This code assumes 32bit registers.
- unsigned dwords = bytes / 4;
- bytes %= 4;
- while(bytes--)
- {
- byte b = dp[dwords*4 + bytes];
- if (((b&0xF0u) > 0x90u) || ((b&0x0Fu) > 0x09u))
- return false;
- }
- // see http://www.cs.uiowa.edu/~jones/bcd/bcd.html for an explanation of this code
- unsigned __int32 *wp = (unsigned __int32 *)data;
- while (dwords--)
- {
- unsigned __int32 l = wp[dwords];
- if ((unsigned __int32 )(l&0xF0000000) > 0x90000000u)
- return false;
- __int32 l1 = l + 0x66666666;
- __int32 l2 = l1 ^ l;
- __int32 l3 = l2 & 0x11111110;
- if (l3)
- return false;
- }
- }
- return true;
- }
|