1 
2 /**
3  *    Copyright (C) 2018-present MongoDB, Inc.
4  *
5  *    This program is free software: you can redistribute it and/or modify
6  *    it under the terms of the Server Side Public License, version 1,
7  *    as published by MongoDB, Inc.
8  *
9  *    This program is distributed in the hope that it will be useful,
10  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *    Server Side Public License for more details.
13  *
14  *    You should have received a copy of the Server Side Public License
15  *    along with this program. If not, see
16  *    <http://www.mongodb.com/licensing/server-side-public-license>.
17  *
18  *    As a special exception, the copyright holders give permission to link the
19  *    code of portions of this program with the OpenSSL library under certain
20  *    conditions as described in each individual source file and distribute
21  *    linked combinations including the program with the OpenSSL library. You
22  *    must comply with the Server Side Public License in all respects for
23  *    all of the code used other than as permitted herein. If you modify file(s)
24  *    with this exception, you may extend this exception to your version of the
25  *    file(s), but you are not obligated to do so. If you do not wish to do so,
26  *    delete this exception statement from your version. If you delete this
27  *    exception statement from all source files in the program, then also delete
28  *    it in the license file.
29  */
30 
31 #pragma once
32 
33 #include <array>
34 #include <cstdint>
35 #include <iostream>
36 #include <string>
37 #include <utility>
38 
39 #include "mongo/config.h"
40 
41 #include "mongo/util/assert_util.h"
42 
43 namespace mongo {
44 
45 /**
46  * Wrapper class for the MongoDB Decimal128 data type. Sample usage:
47  *     Decimal128 d1("+10.0");
48  *     Decimal128 d2("+0.1")
49  *     Decimal128 sum = d1.add(d2)
50  *     std::cout << sum << std::endl;
51  */
52 class Decimal128 {
53 public:
54     /**
55      * Static constants to get Decimal128 representations of specific numbers
56      * kLargestPositive -> 9999999999999999999999999999999999E6111
57      * kSmallestPositive -> 1E-6176
58      * kLargestNegative -> -9999999999999999999999999999999999E6111
59      * kSmallestNegative -> -1E-6176
60      * kLargestNegativeExponentZero -> 0E-6176
61      */
62     static const Decimal128 kLargestPositive;
63     static const Decimal128 kSmallestPositive;
64     static const Decimal128 kLargestNegative;
65     static const Decimal128 kSmallestNegative;
66 
67     static const Decimal128 kNormalizedZero;  // zero with exponent 0
68     static const Decimal128 kLargestNegativeExponentZero;
69 
70     static const Decimal128 kPositiveInfinity;
71     static const Decimal128 kNegativeInfinity;
72     static const Decimal128 kPositiveNaN;
73     static const Decimal128 kNegativeNaN;
74 
75     static const uint32_t kMaxBiasedExponent = 6143 + 6144;
76     // Biased exponent of a Decimal128 with least significant digit in the units place
77     static const int32_t kExponentBias = 6143 + 33;
78     static const uint32_t kInfinityExponent = kMaxBiasedExponent + 1;  // internal convention only
79 
80     /**
81      * This struct holds the raw data for IEEE 754-2008 data types
82      */
83     struct Value {
84         std::uint64_t low64;
85         std::uint64_t high64;
86     };
87 
88     enum RoundingMode {
89         kRoundTiesToEven = 0,
90         kRoundTowardNegative = 1,
91         kRoundTowardPositive = 2,
92         kRoundTowardZero = 3,
93         kRoundTiesToAway = 4
94     };
95 
96     /**
97      * Indicates if constructing a Decimal128 from a double should round the double to 15 digits
98      * (so the conversion will correctly round-trip decimals), or round to the full 34 digits.
99      */
100     enum RoundingPrecision { kRoundTo15Digits = 0, kRoundTo34Digits = 1 };
101 
102     /**
103      * The signaling flag enum determines the signaling nature of a decimal operation.
104      * The values of these flags are defined in the Intel RDFP math library.
105      *
106      * The provided hasFlag method checks whether provided signalingFlags contains flag f.
107      *
108      * Example:
109      *     Decimal128 dcml = Decimal128('0.1');
110      *     std::uint32_t sigFlag = Decimal128::SignalingFlag::kNoFlag;
111      *     double dbl = dcml.toDouble(&sigFlag);
112      *     if Decimal128::hasFlag(sigFlag, SignalingFlag::kInexact)
113      *         cout << "inexact decimal to double conversion!" << endl;
114      */
115     enum SignalingFlag {
116         kNoFlag = 0x00,
117         kInvalid = 0x01,
118         kDivideByZero = 0x04,
119         kOverflow = 0x08,
120         kUnderflow = 0x10,
121         kInexact = 0x20,
122     };
123 
hasFlag(std::uint32_t signalingFlags,SignalingFlag f)124     static bool hasFlag(std::uint32_t signalingFlags, SignalingFlag f) {
125         return ((signalingFlags & f) != 0u);
126     }
127 
128     /**
129      * Returns true if a valid Decimal can be constructed from the given arguments.
130      */
isValid(uint64_t sign,uint64_t exponent,uint64_t coefficientHigh,uint64_t coefficientLow)131     static bool isValid(uint64_t sign,
132                         uint64_t exponent,
133                         uint64_t coefficientHigh,
134                         uint64_t coefficientLow) {
135         if (coefficientHigh >= 0x1ed09bead87c0 &&
136             (coefficientHigh != 0x1ed09bead87c0 || coefficientLow != 0x378d8e63ffffffff)) {
137             return false;
138         }
139         auto value =
140             Value{coefficientLow,
141                   (sign << kSignFieldPos) | (exponent << kExponentFieldPos) | coefficientHigh};
142 
143         return Decimal128(value).getBiasedExponent() == exponent;
144     }
145 
146     /**
147      * Construct a 0E0 valued Decimal128.
148      */
Decimal128()149     Decimal128() : _value(kNormalizedZero._value) {}
150 
151     /**
152      * This constructor takes in a raw decimal128 type, which consists of two
153      * uint64_t's. This class performs an endian check on the system to ensure
154      * that the Value.high64 represents the higher 64 bits.
155      */
Decimal128(Decimal128::Value dec128Value)156     explicit Decimal128(Decimal128::Value dec128Value) : _value(dec128Value) {}
157 
158     /**
159      * Constructs a Decimal128 from parts, dealing with proper encoding of the combination field.
160      * Assumes that the value will be inside the valid range of finite values. (No NaN/Inf, etc.)
161      */
Decimal128(uint64_t sign,uint64_t exponent,uint64_t coefficientHigh,uint64_t coefficientLow)162     Decimal128(uint64_t sign, uint64_t exponent, uint64_t coefficientHigh, uint64_t coefficientLow)
163         : _value(
164               Value{coefficientLow,
165                     (sign << kSignFieldPos) | (exponent << kExponentFieldPos) | coefficientHigh}) {
166         dassert(isValid(sign, exponent, coefficientHigh, coefficientLow));
167     }
168 
169     explicit Decimal128(std::int32_t int32Value);
170     explicit Decimal128(std::int64_t int64Value);
171 
172     /**
173      * This constructor takes a double and constructs a Decimal128 object given a roundMode, either
174      * to full precision, or with a fixed precision of 15 decimal digits. When a double is used to
175      * store a decimal floating point number, it is only correct up to 15 digits after converting
176      * back to decimal, so the 15 digit rounding is used for mixed-mode operations.
177      * The general idea is to quantize the direct double->dec128 conversion
178      * with a quantum of 1E(-15 +/- base10 exponent equivalent of the double).
179      * To do this, we find the smallest (abs value) base 10 exponent greater
180      * than the double's base 2 exp and shift the quantizer's exp accordingly.
181      */
182     explicit Decimal128(double doubleValue,
183                         RoundingPrecision roundPrecision = kRoundTo15Digits,
184                         RoundingMode roundMode = kRoundTiesToEven);
185 
186     /**
187      * This constructor takes a string and constructs a Decimal128 object from it.
188      * Inputs larger than 34 digits of precision are rounded according to the
189      * specified rounding mode. The following (and variations) are all accepted:
190      * "+2.02E200"
191      * "2.02E+200"
192      * "-202E-500"
193      * "somethingE200" --> NaN
194      * "200E9999999999" --> +Inf
195      * "-200E9999999999" --> -Inf
196      */
197     explicit Decimal128(std::string stringValue, RoundingMode roundMode = kRoundTiesToEven);
198 
199     Decimal128(std::string stringValue,
200                std::uint32_t* signalingFlag,
201                RoundingMode roundMode = kRoundTiesToEven);
202 
203     /**
204      * This function gets the inner Value struct storing a Decimal128 value.
205      */
206     Value getValue() const;
207 
208     /**
209      *  Extracts the biased exponent from the combination field.
210      */
getBiasedExponent()211     uint32_t getBiasedExponent() const {
212         const uint64_t combo = _getCombinationField();
213         if (combo < kCombinationNonCanonical)
214             return combo >> 3;
215 
216         return combo >= kCombinationInfinity
217             ? kMaxBiasedExponent + 1           // NaN or Inf
218             : (combo >> 1) & ((1 << 14) - 1);  // non-canonical representation
219     }
220 
221     /**
222      * Returns the high 49 bits of the 113-bit binary encoded coefficient. Returns 0 for
223      * non-canonical or non-finite numbers.
224      */
getCoefficientHigh()225     uint64_t getCoefficientHigh() const {
226         return _getCombinationField() < kCombinationNonCanonical
227             ? _value.high64 & kCanonicalCoefficientHighFieldMask
228             : 0;
229     }
230 
231     /**
232      * Returns the low 64 bits of the 113-bit binary encoded coefficient. Returns 0 for
233      * non-canonical or non-finite numbers.
234      */
getCoefficientLow()235     uint64_t getCoefficientLow() const {
236         return _getCombinationField() < kCombinationNonCanonical ? _value.low64 : 0;
237     }
238 
239     /**
240      * Returns the absolute value of this.
241      */
242     Decimal128 toAbs() const;
243 
244     /**
245      * Returns `this` with inverted sign bit
246      */
negate()247     Decimal128 negate() const {
248         Value negated = {_value.low64, _value.high64 ^ (1ULL << 63)};
249         return Decimal128(negated);
250     }
251 
252 
253     /**
254      * This set of functions converts a Decimal128 to a certain integer type with a
255      * given rounding mode.
256      *
257      * Each function is overloaded to provide an optional signalingFlags output parameter
258      * that can be set to one of the Decimal128::SignalingFlag enumerators:
259      * kNoFlag, kInvalid
260      *
261      * Note: The signaling flags for these functions only signal
262      * an invalid conversion. If inexact conversion flags are necessary, call
263      * the toTypeExact version of the function defined below. This set of operations
264      * (toInt, toLong) has better performance than the latter.
265      */
266     std::int32_t toInt(RoundingMode roundMode = kRoundTiesToEven) const;
267     std::int32_t toInt(std::uint32_t* signalingFlags,
268                        RoundingMode roundMode = kRoundTiesToEven) const;
269     std::int64_t toLong(RoundingMode roundMode = kRoundTiesToEven) const;
270     std::int64_t toLong(std::uint32_t* signalingFlags,
271                         RoundingMode roundMode = kRoundTiesToEven) const;
272 
273     /**
274      * This set of functions converts a Decimal128 to a certain integer type with a
275      * given rounding mode. The signaling flags for these functions will also signal
276      * inexact computation.
277      *
278      * Each function is overloaded to provide an optional signalingFlags output parameter
279      * that can be set to one of the Decimal128::SignalingFlag enumerators:
280      * kNoFlag, kInexact, kInvalid
281      */
282     std::int32_t toIntExact(RoundingMode roundMode = kRoundTiesToEven) const;
283     std::int32_t toIntExact(std::uint32_t* signalingFlags,
284                             RoundingMode roundMode = kRoundTiesToEven) const;
285     std::int64_t toLongExact(RoundingMode roundMode = kRoundTiesToEven) const;
286     std::int64_t toLongExact(std::uint32_t* signalingFlags,
287                              RoundingMode roundMode = kRoundTiesToEven) const;
288 
289     /**
290      * These functions convert decimals to doubles and have the ability to signal
291      * inexact, underflow, overflow, and invalid operation.
292      *
293      * This function is overloaded to provide an optional signalingFlags output parameter
294      * that can be set to one of the Decimal128::SignalingFlag enumerators:
295      * kNoFlag, kInexact, kUnderflow, kOverflow, kInvalid
296      */
297     double toDouble(RoundingMode roundMode = kRoundTiesToEven) const;
298     double toDouble(std::uint32_t* signalingFlags, RoundingMode roundMode = kRoundTiesToEven) const;
299 
300     /**
301      * This function converts a Decimal128 to a string with the following semantics:
302      *
303      * Suppose Decimal128 D has P significant digits and exponent Exp.
304      * Define SE to be the scientific exponent of D equal to Exp + P - 1.
305      *
306      * Define format E as normalized scientific notation (ex: 1.0522E+16)
307      * Define format F as a regular formatted number with no exponent (ex: 105.22)
308      *
309      * In order to improve decimal type readability,
310      * if SE >= 12 or SE <= -4, use format E to display D.
311      * if Exp > 0, use format E to display D because adding trailing zeros implies
312      * extra, incorrect precision
313      *
314      * Otherwise, display using F with no exponent (add leading zeros if necessary).
315      *
316      * This conversion to string is roughly based on the G C99 printf specifier and
317      * existing behavior for the double numeric type in MongoDB.
318      */
319     std::string toString() const;
320 
321     /**
322      * This set of functions check whether a Decimal128 is Zero, NaN, or +/- Inf
323      */
324     bool isZero() const;
325     bool isNaN() const;
326     bool isInfinite() const;
327     bool isNegative() const;
328 
329     /**
330      * Return true if and only if a Decimal128 is Zero, Normal, or Subnormal (not Inf or NaN)
331      */
332     bool isFinite() const;
333 
334     /**
335      * This set of mathematical operation functions implement the corresponding
336      * IEEE 754-2008 operations on self and other.
337      * The 'add' and 'multiply' methods are commutative, so a.add(b) is equivalent to b.add(a).
338      * Rounding of results that require a precision greater than 34 decimal digits
339      * is performed using the supplied rounding mode (defaulting to kRoundTiesToEven).
340      * NaNs and infinities are handled according to the IEEE 754-2008 specification.
341      *
342      * Each function is overloaded to provide an optional signalingFlags output parameter
343      * that can be set to one of the Decimal128::SignalingFlag enumerators:
344      * kNoFlag, kInexact, kUnderflow, kOverflow, kInvalid
345      *
346      * The divide operation may also set signalingFlags to kDivideByZero
347      */
348     Decimal128 add(const Decimal128& other, RoundingMode roundMode = kRoundTiesToEven) const;
349     Decimal128 add(const Decimal128& other,
350                    std::uint32_t* signalingFlags,
351                    RoundingMode roundMode = kRoundTiesToEven) const;
352     Decimal128 subtract(const Decimal128& other, RoundingMode roundMode = kRoundTiesToEven) const;
353     Decimal128 subtract(const Decimal128& other,
354                         std::uint32_t* signalingFlags,
355                         RoundingMode roundMode = kRoundTiesToEven) const;
356     Decimal128 multiply(const Decimal128& other, RoundingMode roundMode = kRoundTiesToEven) const;
357     Decimal128 multiply(const Decimal128& other,
358                         std::uint32_t* signalingFlags,
359                         RoundingMode roundMode = kRoundTiesToEven) const;
360     Decimal128 divide(const Decimal128& other, RoundingMode roundMode = kRoundTiesToEven) const;
361     Decimal128 divide(const Decimal128& other,
362                       std::uint32_t* signalingFlags,
363                       RoundingMode roundMode = kRoundTiesToEven) const;
364     Decimal128 exponential(RoundingMode roundMode = kRoundTiesToEven) const;
365     Decimal128 exponential(std::uint32_t* signalingFlags,
366                            RoundingMode roundMode = kRoundTiesToEven) const;
367     Decimal128 logarithm(RoundingMode roundMode = kRoundTiesToEven) const;
368     Decimal128 logarithm(std::uint32_t* signalingFlags,
369                          RoundingMode roundMode = kRoundTiesToEven) const;
370     Decimal128 logarithm(const Decimal128& other, RoundingMode roundMode = kRoundTiesToEven) const;
371     Decimal128 logarithm(const Decimal128& other,
372                          std::uint32_t* signalingFlags,
373                          RoundingMode roundMode = kRoundTiesToEven) const;
374     Decimal128 modulo(const Decimal128& other) const;
375     Decimal128 modulo(const Decimal128& other, std::uint32_t* signalingFlags) const;
376 
377     Decimal128 power(const Decimal128& other, RoundingMode roundMode = kRoundTiesToEven) const;
378     Decimal128 power(const Decimal128& other,
379                      std::uint32_t* signalingFlags,
380                      RoundingMode roundMode = kRoundTiesToEven) const;
381 
382     Decimal128 squareRoot(RoundingMode roundMode = kRoundTiesToEven) const;
383     Decimal128 squareRoot(std::uint32_t* signalingFlags,
384                           RoundingMode roundMode = kRoundTiesToEven) const;
385 
386     /**
387      * This function quantizes the current decimal given a quantum reference
388      */
389     Decimal128 quantize(const Decimal128& reference,
390                         RoundingMode roundMode = kRoundTiesToEven) const;
391     Decimal128 quantize(const Decimal128& reference,
392                         std::uint32_t* signalingFlags,
393                         RoundingMode roundMode = kRoundTiesToEven) const;
394 
395     /**
396      * This function normalizes the cohort of a Decimal128 by forcing it to maximum
397      * precision (34 decimal digits). This normalization is important when it is desirable
398      * to force equal decimals of different representations (i.e. 5.0 and 5.00) to equal
399      * decimals with the same representation (5000000000000000000000000000000000E-33).
400      * Hashing equal decimals to equal hashes becomes possible with such normalization.
401      */
normalize()402     Decimal128 normalize() const {
403         // Normalize by adding 0E-6176 which forces a decimal to maximum precision (34 digits)
404         return add(kLargestNegativeExponentZero);
405     }
406 
407     /**
408      * This set of comparison operations takes a single Decimal128 and returns a boolean
409      * noting the value of the comparison. These comparisons are not total ordered, but
410      * comply with the IEEE 754-2008 spec. The comparison returns true if the caller
411      * is <equal, notequal, greater, greaterequal, less, lessequal> the argument (other).
412      */
413     bool isEqual(const Decimal128& other) const;
414     bool isNotEqual(const Decimal128& other) const;
415     bool isGreater(const Decimal128& other) const;
416     bool isGreaterEqual(const Decimal128& other) const;
417     bool isLess(const Decimal128& other) const;
418     bool isLessEqual(const Decimal128& other) const;
419 
420     /**
421      * Returns true iff 'this' and 'other' are bitwise identical. Note that this returns false
422      * even for values that may convert to identical strings, such as different NaNs or
423      * non-canonical representations that represent bit-patterns never generated by any conforming
424      * implementation, but should be treated as 0. Mostly for testing.
425      */
isBinaryEqual(const Decimal128 & other)426     bool isBinaryEqual(const Decimal128& other) const {
427         return _value.high64 == other._value.high64 && _value.low64 == other._value.low64;
428     }
429 
430 private:
431     static const uint8_t kSignFieldPos = 64 - 1;
432     static const uint8_t kCombinationFieldPos = kSignFieldPos - 17;
433     static const uint64_t kCombinationFieldMask = (1 << 17) - 1;
434     static const uint64_t kExponentFieldPos = kCombinationFieldPos + 3;
435     static const uint64_t kCoefficientContinuationFieldMask = (1ull << kCombinationFieldPos) - 1;
436     static const uint64_t kCombinationNonCanonical = 3 << 15;
437     static const uint64_t kCombinationInfinity = 0x1e << 12;
438     static const uint64_t kCombinationNaN = 0x1f << 12;
439     static const uint64_t kCanonicalCoefficientHighFieldMask = (1ull << 49) - 1;
440 
441     std::string _convertToScientificNotation(StringData coefficient, int adjustedExponent) const;
442     std::string _convertToStandardDecimalNotation(StringData coefficient, int exponent) const;
443 
_getCombinationField()444     uint64_t _getCombinationField() const {
445         return (_value.high64 >> kCombinationFieldPos) & kCombinationFieldMask;
446     }
447 
448     Value _value;
449 };
450 }  // namespace mongo
451