nbcd.hpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #ifndef _NBCD_
  14. #define _NBCD_
  15. #ifdef _WIN32
  16. #ifdef NBCD_EXPORTS
  17. #define nbcd_decl __declspec(dllexport)
  18. #else
  19. #define nbcd_decl __declspec(dllimport)
  20. #endif
  21. #else
  22. #define nbcd_decl
  23. #endif
  24. #define DECIMAL_OVERLOAD
  25. template <byte length, byte precision> class decimal;
  26. /*
  27. * Decimal implements Binary Coded Decimal (BCD) arithmetic.
  28. *
  29. * The internal representation is an array of digits, with size
  30. * equals maxDigits, divided in two sections:
  31. * * 0~max/2: integer part
  32. * * max/2+1~max: decimal part
  33. *
  34. * The decimal point is always in the middle and msb and lsb
  35. * point to the beginning of the integer part and the end
  36. * of the decimal part. Sign is a boolean flag, but represented
  37. * with standard C/D/F flags (+/-/unsigned) in BCD format.
  38. *
  39. * This class is notably used in the Decimal run-time library
  40. * (nbcds.cpp), providing decimal arithmetic to ECL programs.
  41. */
  42. class nbcd_decl Decimal
  43. {
  44. public:
  45. Decimal() { setZero(); }
  46. Decimal(const Decimal & other);
  47. Decimal & abs();
  48. Decimal & add(const Decimal & other);
  49. int compareNull() const;
  50. int compare(const Decimal & other) const;
  51. Decimal & divide(const Decimal & other);
  52. Decimal & modulus(const Decimal & other);
  53. Decimal & multiply(const Decimal & other);
  54. Decimal & negate();
  55. Decimal & power(int value);
  56. Decimal & power(unsigned value);
  57. Decimal & round(int places=0); // -ve means left of decimal point e.g., -3 = to nearest 1000.
  58. Decimal & roundup(int places=0); // -ve means left of decimal point e.g., -3 = to nearest 1000.
  59. Decimal & setPrecision(byte numDigits, byte precision);
  60. Decimal & subtract(const Decimal & other);
  61. Decimal & truncate(int places=0);
  62. size32_t getStringLength() const;
  63. void getCString(size32_t length, char * buffer) const;
  64. char * getCString() const;
  65. void getDecimal(byte length, byte precision, void * buffer, byte signs=0xFD) const;
  66. __int64 getInt64() const;
  67. int getInt() const;
  68. double getReal() const;
  69. void getString(size32_t length, char * buffer) const;
  70. void getStringX(size32_t & length, char * & buffer) const;
  71. void getUDecimal(byte length, byte precision, void * buffer) const;
  72. unsigned __int64 getUInt64() const;
  73. unsigned int getUInt() const;
  74. void getClipPrecision(unsigned & digits, unsigned & precision);
  75. void getPrecision(unsigned & digits, unsigned & precison);
  76. // MORE: We could support NaNs for decimals at a later date by adding a member to this class.
  77. bool isZero() const;
  78. bool isValid() const { return true; }
  79. void set(const Decimal & value);
  80. void setCString(const char * buffer);
  81. void setDecimal(byte length, byte precision, const void * buffer);
  82. void setInt64(__int64 value);
  83. void setInt(int value);
  84. void setReal(double value);
  85. void setString(size32_t length, const char * buffer);
  86. void setUInt64(unsigned __int64 value);
  87. void setUInt(unsigned int value);
  88. void setUDecimal(byte length, byte precision, const void * buffer);
  89. void setZero();
  90. #ifdef DECIMAL_OVERLOAD
  91. template <byte length, byte precision>
  92. Decimal(const decimal<length, precision> & x) { setDecimal(length, precision, &x); }
  93. inline Decimal(int value) { setInt(value); }
  94. inline Decimal(unsigned value) { setUInt(value); }
  95. inline Decimal(__int64 value) { setInt64(value); }
  96. inline Decimal(unsigned __int64 value) { setUInt64(value); }
  97. inline Decimal(double value) { setReal(value); }
  98. inline Decimal(const char * value) { setCString(value); }
  99. inline Decimal & operator = (int value) { setInt(value); return *this; }
  100. inline Decimal & operator = (unsigned value) { setUInt(value); return *this; }
  101. inline Decimal & operator = (__int64 value) { setInt64(value); return *this; }
  102. inline Decimal & operator = (unsigned __int64 value) { setUInt64(value); return *this; }
  103. inline Decimal & operator = (double value) { setReal(value); return *this; }
  104. inline Decimal & operator = (const char * value) { setCString(value); return *this; }
  105. #endif
  106. protected:
  107. Decimal & addDigits(const Decimal & other);
  108. Decimal & subtractDigits(const Decimal & other);
  109. void clip(int & newLsb, int & newMsb) const;
  110. void clip(int & newLsb, int & newMsb, unsigned minLsb, unsigned maxMsb) const;
  111. void doGetDecimal(byte length, byte maxDigits, byte precision, void * buffer) const;
  112. void doPower(unsigned value);
  113. unsigned doGetString(char * target) const;
  114. void extendRange(byte oLsb, byte oMsb);
  115. void extendRange(const Decimal & other) { extendRange(other.lsb, other.msb); }
  116. void overflow();
  117. private:
  118. Decimal & incLSD();
  119. protected:
  120. enum {
  121. maxDigits=MAX_DECIMAL_DIGITS, // Total buffer size (integer+decimal)
  122. maxPrecision=MAX_DECIMAL_PRECISION, // Size of decimal part
  123. maxIntegerDigits=MAX_DECIMAL_LEADING, // Size of integer part
  124. lastDigit = maxDigits-1, // Last decimal digit
  125. zeroDigit = (maxDigits-maxIntegerDigits), // Unity digit (decimal point)
  126. };
  127. byte digits[maxDigits]; // stored little endian.
  128. byte msb; // Most significant integer digit
  129. byte lsb; // Least significant decimal digit
  130. byte negative; // byte to allow ^ operation
  131. };
  132. template <byte length, byte precision>
  133. class decimal
  134. {
  135. public:
  136. decimal() { memset(buffer, 0, length); }
  137. decimal(const Decimal & other) { other.getDecimal(length, precision, buffer); }
  138. protected:
  139. byte buffer[length];
  140. };
  141. template <byte length, byte precision>
  142. class udecimal
  143. {
  144. public:
  145. udecimal() { memset(buffer, 0, length); }
  146. udecimal(const Decimal & other) { other.getUDecimal(length, precision, buffer); }
  147. protected:
  148. byte buffer[length];
  149. };
  150. #ifdef DECIMAL_OVERLOAD
  151. inline Decimal operator + (const Decimal & left, const Decimal & right) { return Decimal(left).add(right); }
  152. inline Decimal operator - (const Decimal & left, const Decimal & right) { return Decimal(left).subtract(right); }
  153. inline Decimal operator * (const Decimal & left, const Decimal & right) { return Decimal(left).multiply(right); }
  154. inline Decimal operator / (const Decimal & left, const Decimal & right) { return Decimal(left).divide(right); }
  155. inline Decimal operator % (const Decimal & left, const Decimal & right) { return Decimal(left).modulus(right); }
  156. inline bool operator == (const Decimal & left, const Decimal & right) { return left.compare(right) == 0; }
  157. inline bool operator != (const Decimal & left, const Decimal & right) { return left.compare(right) != 0; }
  158. inline bool operator >= (const Decimal & left, const Decimal & right) { return left.compare(right) >= 0; }
  159. inline bool operator <= (const Decimal & left, const Decimal & right) { return left.compare(right) <= 0; }
  160. inline bool operator > (const Decimal & left, const Decimal & right) { return left.compare(right) > 0; }
  161. inline bool operator < (const Decimal & left, const Decimal & right) { return left.compare(right) < 0; }
  162. #endif
  163. //Various utility helper functions:
  164. nbcd_decl bool dec2Bool(size32_t bytes, const void * data);
  165. nbcd_decl bool udec2Bool(size32_t bytes, const void * data);
  166. nbcd_decl int decCompareDecimal(size32_t bytes, const void * _left, const void * _right);
  167. nbcd_decl int decCompareUDecimal(size32_t bytes, const void * _left, const void * _right);
  168. nbcd_decl bool decValid(bool isSigned, unsigned digits, const void * data);
  169. #endif