OnixS CME Drop Copy Handler C++ library  5.7.1
API documentation
Numeric.h
Go to the documentation of this file.
1 // Copyright Onix Solutions Limited [OnixS]. All rights reserved.
2 //
3 // This software owned by Onix Solutions Limited [OnixS] and is protected by copyright law
4 // and international copyright treaties.
5 //
6 // Access to and use of the software is governed by the terms of the applicable OnixS Software
7 // Services Agreement (the Agreement) and Customer end user license agreements granting
8 // a non-assignable, non-transferable and non-exclusive license to use the software
9 // for it's own data processing purposes under the terms defined in the Agreement.
10 //
11 // Except as otherwise granted within the terms of the Agreement, copying or reproduction of any
12 // part of this source code or associated reference material to any other location for further
13 // reproduction or redistribution, and any amendments to this copyright notice, are expressly
14 // prohibited.
15 //
16 // Any reproduction or redistribution for sale or hiring of the Software not in accordance with
17 // the terms of the Agreement is a violation of copyright law.
18 //
19 
20 #pragma once
21 
22 #include "OnixS/CME/DropCopy/Export.h"
23 
24 #include <cassert>
25 #include <cmath>
26 #include <ostream>
27 #include <stdexcept>
28 #include <string>
29 
30 namespace OnixS { namespace CME { namespace DropCopy {
31 
32 typedef int Int32;
33 typedef unsigned int UInt32;
34 
35 typedef long long Int64;
36 typedef unsigned long long UInt64;
37 
38 typedef double Double;
39 
40 typedef Int64 DecimalMantissa;
41 typedef Int32 DecimalExponent;
42 
43 /// Decimal type for better precision.
44 class ONIXS_CME_DROP_COPY_EXPORT Decimal
45 {
46 public:
47  /// Initializes instance from compound components.
48  Decimal(DecimalMantissa mantissa = 0, DecimalExponent exponent = 0);
49 
50  /// Converts Double value to decimal.
51  /// \param value double precision floating-point value.
52  /// \param precision defines conversion precision.
53  Decimal(Double value, size_t precision);
54 
55  /// Initializes as copy of given value.
56  Decimal(const Decimal& other);
57 
58  /// Returns mantissa part of decimal.
59  DecimalMantissa mantissa() const;
60 
61  /// Updates mantissa part of decimal.
62  void mantissa(DecimalMantissa);
63 
64  /// Returns exponent part of decimal.
65  DecimalExponent exponent() const;
66 
67  /// Updates exponent part of decimal.
68  void exponent(DecimalExponent);
69 
70  /// Compares two numbers.
71  bool operator==(const Decimal&) const;
72 
73  /// Compares two numbers.
74  bool operator!=(const Decimal&) const;
75 
76  /// Establishes order between two values.
77  bool operator<(const Decimal&) const;
78 
79  /// Establishes order between two values.
80  bool operator>(const Decimal&) const;
81 
82  /// Casts to whole integer number as regular
83  /// floating point value is casted.
84  /// \throw domain_error exception on failure.
85  operator Int32() const;
86 
87  /// Casts to whole integer number as regular
88  /// floating point value is casted.
89  /// \throw domain_error exception on failure.
90  operator UInt32() const;
91 
92  /// Casts to whole integer number as regular
93  /// floating point value is casted.
94  /// \throw domain_error exception on failure.
95  operator Int64() const;
96 
97  /// Casts to whole integer number as regular
98  /// floating point value is casted.
99  /// \throw domain_error exception on failure.
100  operator UInt64() const;
101 
102  /// Casts to whole floating point as regular
103  /// value is casted to a smaller precision.
104  /// \throw domain_error exception on failure.
105  operator Double() const;
106 
107  /// Casts to whole integer number as regular
108  /// floating point value is casted.
109  /// \returns false if conversion fails.
110  bool toNumber(Int32&) const;
111 
112  /// Casts to whole integer number as regular
113  /// floating point value is casted.
114  /// \returns false if conversion fails.
115  bool toNumber(UInt32&) const;
116 
117  /// Casts to whole integer number as regular
118  /// floating point value is casted.
119  /// \returns false if conversion fails.
120  bool toNumber(Int64&) const;
121 
122  /// Casts to whole integer number as regular
123  /// floating point value is casted.
124  /// \returns false if conversion fails.
125  bool toNumber(UInt64&) const;
126 
127  /// Casts to double floating point number.
128  /// \returns false if conversion fails.
129  bool toNumber(Double&) const;
130 
131  /// Fast cast to double floating point number.
132  /// \note For the sake of performance no range checks are done.
133  /// Result may be invalid if decimal cannot be represented as double value.
134  /// Warning: result may be different (less precise) from toNumber(Double&)
135  /// result due to performance vs precision trade-off.
136  Double toDoubleUnchecked() const;
137 
138  /// Fast cast from double floating point number.
139  /// \note For the sake of performance no range checks are done.
140  /// Result may be invalid if decimal cannot be represented as double value.
141  /// Warning: result may be different (less precise) from Decimal(Double, size_t)
142  /// result due to performance vs precision trade-off.
143  static Decimal fromDoubleUnchecked(Double value, size_t precision);
144 
145  /// Appends text presentation to given string.
146  void toString(std::string&) const;
147 
148  /// Returns text presentation of decimal.
149  std::string toString() const;
150 
151  /// Reinitializes instance from another one.
152  Decimal& operator=(const Decimal& other);
153 
154  /// Attempts to parse decimal value
155  /// from its string/text presentation.
156  /// \returns false on parsing failure.
157  static bool tryParse(const char* buffer, size_t bufferSize, Decimal&);
158 
159  /// Parses decimal from string presentation.
160  /// \throw std::exception on failure.
161  static Decimal parse(const char* buffer, size_t bufferSize);
162 
163 private:
164  /// Mantissa.
165  DecimalMantissa mantissa_;
166 
167  /// Exponent.
168  DecimalExponent exponent_;
169 };
170 
171 inline Decimal::Decimal(DecimalMantissa mantissa, DecimalExponent exponent)
172  : mantissa_(mantissa)
173  , exponent_(exponent)
174 {
175 }
176 
177 inline Decimal::Decimal(const Decimal& other)
178  : mantissa_(other.mantissa_)
179  , exponent_(other.exponent_)
180 {
181 }
182 
183 inline DecimalMantissa Decimal::mantissa() const
184 {
185  return mantissa_;
186 }
187 
188 inline void Decimal::mantissa(DecimalMantissa value)
189 {
190  mantissa_ = value;
191 }
192 
193 inline DecimalExponent Decimal::exponent() const
194 {
195  return exponent_;
196 }
197 
198 inline void Decimal::exponent(DecimalExponent value)
199 {
200  exponent_ = value;
201 }
202 
203 inline Decimal& Decimal::operator=(const Decimal& other)
204 {
205  mantissa_ = other.mantissa_;
206  exponent_ = other.exponent_;
207 
208  return *this;
209 }
210 
211 inline Decimal::operator Int32() const
212 {
213  Int32 number;
214 
215  if (toNumber(number))
216  {
217  return number;
218  }
219 
220  throw std::domain_error("Cannot cast value to target type. ");
221 }
222 
223 inline Decimal::operator UInt32() const
224 {
225  UInt32 number;
226 
227  if (toNumber(number))
228  {
229  return number;
230  }
231 
232  throw std::domain_error("Cannot cast value to target type. ");
233 }
234 
235 inline Decimal::operator Int64() const
236 {
237  Int64 number;
238 
239  if (toNumber(number))
240  {
241  return number;
242  }
243 
244  throw std::domain_error("Cannot cast value to target type. ");
245 }
246 
247 inline Decimal::operator UInt64() const
248 {
249  UInt64 number;
250 
251  if (toNumber(number))
252  {
253  return number;
254  }
255 
256  throw std::domain_error("Cannot cast value to target type. ");
257 }
258 
259 inline Decimal::operator Double() const
260 {
261  Double number;
262 
263  if (toNumber(number))
264  {
265  return number;
266  }
267 
268  throw std::domain_error("Cannot cast value to target type. ");
269 }
270 
271 inline std::string Decimal::toString() const
272 {
273  std::string presentation;
274  toString(presentation);
275  return presentation;
276 }
277 
278 namespace NumericDetails {
279 static const int maxAbsPower10 = 20;
280 static const int powers10Size = maxAbsPower10 * 2 + 1; // Negative, positive and zero powers
281 
282 static const double powers10[] = {1E-20, 1E-19, 1E-18, 1E-17, 1E-16, 1E-15, 1E-14, 1E-13, 1E-12,
283  1E-11, 1E-10, 1E-9, 1E-8, 1E-7, 1E-6, 1E-5, 1E-4, 1E-3,
284  1E-2, 1E-1, 1E0, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6,
285  1E7, 1E8, 1E9, 1E10, 1E11, 1E12, 1E13, 1E14, 1E15,
286  1E16, 1E17, 1E18, 1E19, 1E20};
287 
289 {
290  const int offset = power + maxAbsPower10;
291  if (offset >= 0 && offset < powers10Size)
292  {
293  return powers10[offset];
294  }
295 
296  throw std::invalid_argument("Invalid power argument, must be in range [-20, 20]");
297 }
298 }
299 
300 inline Double Decimal::toDoubleUnchecked() const
301 {
302  using namespace NumericDetails;
303  return mantissa_ * fastPower10(exponent_);
304 }
305 
306 inline Decimal Decimal::fromDoubleUnchecked(Double value, size_t precision)
307 {
308  using namespace NumericDetails;
309  DecimalExponent convertedExponent = 0;
310 
311  Double dummy;
312  if (fabs(modf(value, &dummy)) != 0.0)
313  {
314  const DecimalExponent exp = static_cast<DecimalExponent>(precision);
315 
316  // Apply last digit rounding
317  const Double rounding = 0.5 * fastPower10(-exp);
318  value += (value > 0) ? rounding : -rounding;
319 
320  value *= fastPower10(exp);
321  convertedExponent = -exp;
322  }
323 
324  return Decimal(static_cast<DecimalMantissa>(value), convertedExponent);
325 }
326 
327 /// Helper class for conversion from string to number.
328 struct ONIXS_CME_DROP_COPY_EXPORT Number
329 {
330  static bool tryParse(const char* buffer, size_t bufferSize, Int32& number);
331  static bool tryParse(const char* buffer, size_t bufferSize, UInt32& number);
332  static bool tryParse(const char* buffer, size_t bufferSize, Int64& number);
333  static bool tryParse(const char* buffer, size_t bufferSize, UInt64& number);
334  static bool tryParse(const char* buffer, size_t bufferSize, Double& number);
335  static bool tryParse(const char* buffer, size_t bufferSize, Decimal& number);
336 };
337 
338 /// Comparator aggregate providing compare functions.
339 /// Such functions can be generic (slower, but able to deal
340 /// with any decimal) or fixed point based (faster, but assuming that
341 /// all compating values have the same exponent).
342 struct ONIXS_CME_DROP_COPY_EXPORT DecimalComparator
343 {
344  /// Comparing function signature.
345  typedef bool (*CompareFunction)(const Decimal&, const Decimal&);
346 
347  /// Comparing functions.
348  const CompareFunction equal;
349  const CompareFunction nonEqual;
350  const CompareFunction less;
351  const CompareFunction greater;
352 
353  /// Constructor.
355  const CompareFunction equalFunc,
356  const CompareFunction nonEqualFunc,
357  const CompareFunction lessFunc,
358  const CompareFunction greaterFunc
359  )
360  : equal(equalFunc)
361  , nonEqual(nonEqualFunc)
362  , less(lessFunc)
363  , greater(greaterFunc)
364  {
365  }
366 
367  // Assignment operator: not defined.
369 
370  /// Returns true if this instance is fixed point decimal comparator.
371  bool fixedPoint() const;
372 
373  /// Returns true if this instance is generic decimal comparator.
374  bool genericDecimal() const;
375 };
376 
377 /// Helper functions for generic decimal case.
378 namespace GenericDecimal {
379 inline bool equal(const Decimal& lhs, const Decimal& rhs)
380 {
381  return lhs == rhs;
382 }
383 
384 inline bool nonEqual(const Decimal& lhs, const Decimal& rhs)
385 {
386  return lhs != rhs;
387 }
388 
389 inline bool less(const Decimal& lhs, const Decimal& rhs)
390 {
391  return lhs < rhs;
392 }
393 
394 inline bool greater(const Decimal& lhs, const Decimal& rhs)
395 {
396  return lhs > rhs;
397 }
398 
399 ONIXS_CME_DROP_COPY_EXPORT extern const DecimalComparator Comparator;
400 }
401 
402 /// Helper functions for CME fixed point decimal case.
403 namespace FixedPointDecimal {
404 inline bool equal(const Decimal& lhs, const Decimal& rhs)
405 {
406  assert(lhs.exponent() == rhs.exponent());
407  return lhs.mantissa() == rhs.mantissa();
408 }
409 
410 inline bool nonEqual(const Decimal& lhs, const Decimal& rhs)
411 {
412  assert(lhs.exponent() == rhs.exponent());
413  return lhs.mantissa() != rhs.mantissa();
414 }
415 
416 inline bool less(const Decimal& lhs, const Decimal& rhs)
417 {
418  assert(lhs.exponent() == rhs.exponent());
419  return lhs.mantissa() < rhs.mantissa();
420 }
421 
422 inline bool greater(const Decimal& lhs, const Decimal& rhs)
423 {
424  assert(lhs.exponent() == rhs.exponent());
425  return lhs.mantissa() > rhs.mantissa();
426 }
427 
428 ONIXS_CME_DROP_COPY_EXPORT extern const DecimalComparator Comparator;
429 }
430 
431 inline bool DecimalComparator::fixedPoint() const
432 {
433  return this == &FixedPointDecimal::Comparator;
434 }
435 
437 {
438  return this == &GenericDecimal::Comparator;
439 }
440 
441 static const DecimalComparator& defaultDecimalComparator = GenericDecimal::Comparator;
442 
443 }}}
444 
445 namespace std {
446 
447 // Outputs decimal into standard stream.
448 ONIXS_CME_DROP_COPY_EXPORT std::ostream&
449 operator<<(std::ostream&, const OnixS::CME::DropCopy::Decimal&);
450 
451 }
const CompareFunction greater
Definition: Numeric.h:351
Double toDoubleUnchecked() const
Definition: Numeric.h:300
static bool tryParse(const char *buffer, size_t bufferSize, Decimal &)
DecimalComparator(const CompareFunction equalFunc, const CompareFunction nonEqualFunc, const CompareFunction lessFunc, const CompareFunction greaterFunc)
Constructor.
Definition: Numeric.h:354
bool nonEqual(const Decimal &lhs, const Decimal &rhs)
Definition: Numeric.h:410
long long Int64
Definition: Numeric.h:35
Decimal & operator=(const Decimal &other)
Reinitializes instance from another one.
Definition: Numeric.h:203
bool greater(const Decimal &lhs, const Decimal &rhs)
Definition: Numeric.h:422
bool operator==(const FieldValueRef &ref, const std::string &str)
Definition: Messaging.h:188
STL namespace.
DecimalMantissa mantissa() const
Returns mantissa part of decimal.
Definition: Numeric.h:183
bool operator!=(const FieldValueRef &ref, const std::string &str)
Definition: Messaging.h:193
unsigned long long UInt64
Definition: Numeric.h:36
OnixS::CME::DropCopy::Double fastPower10(int power)
Definition: Numeric.h:288
bool fixedPoint() const
Returns true if this instance is fixed point decimal comparator.
Definition: Numeric.h:431
const DecimalComparator Comparator
const CompareFunction equal
Comparing functions.
Definition: Numeric.h:348
Helper class for conversion from string to number.
Definition: Numeric.h:328
bool toNumber(Int32 &) const
static Decimal fromDoubleUnchecked(Double value, size_t precision)
Definition: Numeric.h:306
std::string toString() const
Returns text presentation of decimal.
Definition: Numeric.h:271
DecimalExponent exponent() const
Returns exponent part of decimal.
Definition: Numeric.h:193
bool equal(const Decimal &lhs, const Decimal &rhs)
Definition: Numeric.h:404
unsigned int UInt32
Definition: Numeric.h:33
const CompareFunction nonEqual
Definition: Numeric.h:349
const DecimalComparator Comparator
Int32 DecimalExponent
Definition: Numeric.h:41
Decimal type for better precision.
Definition: Numeric.h:44
bool less(const Decimal &lhs, const Decimal &rhs)
Definition: Numeric.h:416
Decimal(DecimalMantissa mantissa=0, DecimalExponent exponent=0)
Initializes instance from compound components.
Definition: Numeric.h:171
Int64 DecimalMantissa
Definition: Numeric.h:40
bool genericDecimal() const
Returns true if this instance is generic decimal comparator.
Definition: Numeric.h:436