12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298 |
- /*##############################################################################
- 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(const Decimal & other)
- {
- memcpy(this, &other, sizeof(*this));
- }
- 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;
- 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 = 2;
- 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 > 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.
- 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 cary of the carries
- unsigned carry = 0;
- int j;
- for (j = low1+low2 - zeroDigit; j < lowt; j++)
- carry = (temp[j+zeroDigit]+carry)/10;
- for (j = lowt; j <= hight; j++)
- {
- div_t next = div(temp[j+zeroDigit]+carry, 10);
- digits[j] = next.rem;
- carry = next.quot;
- }
- if ((hight < maxDigits-1) && (carry != 0))
- digits[++hight] = 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;
- }
|