nbcd.hpp 8.3 KB

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