libmongocrypt
mc-dec128.h
1 #ifndef MC_DEC128_H_INCLUDED
2 #define MC_DEC128_H_INCLUDED
3 
4 #include <bson/bson.h>
5 
6 #include <mlib/macros.h>
7 #include <mlib/int128.h>
8 #include <mlib/endian.h>
9 
10 // Conditional preprocessor definition set by the usage of an intel_dfp from
11 // the ImportDFP.cmake script:
12 #ifndef MONGOCRYPT_INTELDFP
13 // Notify includers that Decimal128 is not available:
14 #define MONGOCRYPT_HAVE_DECIMAL128_SUPPORT 0
15 
16 #else // With IntelDFP:
17 // Tell includers that Decimal128 is okay:
18 #define MONGOCRYPT_HAVE_DECIMAL128_SUPPORT 1
19 
20 // Include the header that declares the DFP functions, which may be macros that
21 // expand to renamed symbols:
22 #include <bid_conf.h>
23 #include <bid_functions.h>
24 
25 #include <inttypes.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <float.h>
29 
30 MLIB_C_LINKAGE_BEGIN
31 
33 typedef enum mc_dec128_rounding_mode {
34  MC_DEC128_ROUND_NEAREST_EVEN = 0,
35  MC_DEC128_ROUND_DOWNWARD = 1,
36  MC_DEC128_ROUND_UPWARD = 2,
37  MC_DEC128_ROUND_TOWARD_ZERO = 3,
38  MC_DEC128_ROUND_NEAREST_AWAY = 4,
39  MC_DEC128_ROUND_DEFAULT = MC_DEC128_ROUND_NEAREST_EVEN,
40 } mc_dec128_rounding_mode;
41 
42 typedef struct mc_dec128_flagset {
43  _IDEC_flags bits;
44 } mc_dec128_flagset;
45 
46 // This alignment conditional is the same conditions used in Intel's DFP
47 // library, ensuring we match the ABI of the library without pulling the header
48 #if defined _MSC_VER
49 #if defined _M_IX86 && !defined __INTEL_COMPILER
50 #define _mcDec128Align(n)
51 #else
52 #define _mcDec128Align(n) __declspec(align (n))
53 #endif
54 #else
55 #if !defined HPUX_OS
56 #define _mcDec128Align(n) __attribute__ ((aligned (n)))
57 #else
58 #define _mcDec128Align(n)
59 #endif
60 #endif
61 
62 typedef union _mcDec128Align (16)
63 {
64  uint64_t _words[2];
65 #if !defined(__INTELLISENSE__) && defined(__GNUC__) && defined(__amd64) && \
66  !defined(__APPLE__) && !defined(__clang__)
67  // If supported by the compiler, emit a field that can be used to visualize
68  // the value in a debugger.
69  float value_ __attribute__ ((mode (TD)));
70 #endif
71 }
72 mc_dec128;
73 
74 #undef _mcDec128Align
75 
77 #ifdef __cplusplus
78 #define MC_DEC128_C(N) \
79  mc_dec128 _mcDec128Const (((N) < 0 ? -(N) : (N)), ((N) < 0 ? 1 : 0))
80 #else
81 #define MC_DEC128_C(N) \
82  _mcDec128Const (((N) < 0 ? -(N) : (N)), ((N) < 0 ? 1 : 0))
83 #endif
84 
85 #define MC_DEC128(N) MLIB_INIT (mc_dec128) MC_DEC128_C (N)
86 
87 #define _mcDec128Combination(Bits) ((uint64_t) (Bits) << (47))
88 #define _mcDec128ZeroExpCombo _mcDec128Combination (1 << 7 | 1 << 13 | 1 << 14)
89 #define _mcDec128Const(N, Negate) \
90  _mcDec128ConstFromParts ( \
91  N, (_mcDec128ZeroExpCombo | ((uint64_t) (Negate) << 63)))
92 #define _mcDec128ConstFromParts(CoeffLow, HighWord) \
93  { \
94  { \
95  MLIB_IS_LITTLE_ENDIAN ? (uint64_t) (CoeffLow) \
96  : (uint64_t) (HighWord), \
97  MLIB_IS_LITTLE_ENDIAN ? (uint64_t) (HighWord) \
98  : (uint64_t) (CoeffLow), \
99  }, \
100  }
101 
102 static const mc_dec128 MC_DEC128_ZERO = MC_DEC128_C (0);
103 static const mc_dec128 MC_DEC128_ONE = MC_DEC128_C (1);
104 static const mc_dec128 MC_DEC128_MINUSONE = MC_DEC128_C (-1);
105 
107 #define MC_DEC128_LARGEST_NEGATIVE \
108  mc_dec128_from_string ("-9999999999999999999999999999999999E6111")
109 #define MC_DEC128_SMALLEST_NEGATIVE mc_dec128_from_string ("-1E-6176")
111 #define MC_DEC128_LARGEST_POSITIVE \
113  mc_dec128_from_string ("9999999999999999999999999999999999E6111")
114 #define MC_DEC128_SMALLEST_POSITIVE mc_dec128_from_string ("1E-6176")
116 #define MC_DEC128_NORMALIZED_ZERO MC_DEC128_C (0)
118 #define MC_DEC128_NEGATIVE_EXPONENT_ZERO mc_dec128_from_string ("0E-6176")
120 #define _mcDec128InfCombo \
121  _mcDec128Combination (1 << 15 | 1 << 14 | 1 << 13 | 1 << 12)
122 #define _mcDec128QuietNaNCombo \
123  _mcDec128Combination (1 << 15 | 1 << 14 | 1 << 13 | 1 << 12 | 1 << 11)
124 
126 #define MC_DEC128_POSITIVE_INFINITY \
127  _mcDec128ConstFromParts (0, _mcDec128InfCombo)
128 #define MC_DEC128_NEGATIVE_INFINITY \
130  _mcDec128ConstFromParts (0, _mcDec128InfCombo | 1ull << 63)
131 #define MC_DEC128_POSITIVE_NAN \
133  _mcDec128ConstFromParts (0, _mcDec128QuietNaNCombo)
134 #define MC_DEC128_NEGATIVE_NAN \
136  _mcDec128ConstFromParts (0, _mcDec128QuietNaNCombo | 1ull << 63)
137 
139 static inline BID_UINT128
140 _mc_to_bid128 (mc_dec128 d)
141 {
142  BID_UINT128 r;
143  memcpy (&r, &d, sizeof d);
144  return r;
145 }
146 
148 static inline mc_dec128
149 _bid128_to_mc (BID_UINT128 d)
150 {
151  mc_dec128 r;
152  memcpy (&r, &d, sizeof d);
153  return r;
154 }
155 
164 static inline mc_dec128
165 mc_dec128_from_double_ex (double d,
166  mc_dec128_rounding_mode rnd,
167  mc_dec128_flagset *flags)
168 {
169  mc_dec128_flagset zero_flags = {0};
170  return _bid128_to_mc (
171  binary64_to_bid128 (d, rnd, flags ? &flags->bits : &zero_flags.bits));
172 }
173 
178 static inline mc_dec128
179 mc_dec128_from_double (double d)
180 {
181  return mc_dec128_from_double_ex (d, MC_DEC128_ROUND_DEFAULT, NULL);
182 }
183 
192 static inline mc_dec128
193 mc_dec128_from_string_ex (const char *s,
194  mc_dec128_rounding_mode rnd,
195  mc_dec128_flagset *flags)
196 {
197  mc_dec128_flagset zero_flags = {0};
198  return _bid128_to_mc (bid128_from_string (
199  (char *) s, rnd, flags ? &flags->bits : &zero_flags.bits));
200 }
201 
206 static inline mc_dec128
207 mc_dec128_from_string (const char *s)
208 {
209  return mc_dec128_from_string_ex (s, MC_DEC128_ROUND_DEFAULT, NULL);
210 }
211 
216 typedef struct mc_dec128_string {
218  char str[48];
219 } mc_dec128_string;
220 
227 static inline mc_dec128_string
228 mc_dec128_to_string_ex (mc_dec128 d, mc_dec128_flagset *flags)
229 {
230  mc_dec128_flagset zero_flags = {0};
231  mc_dec128_string out = {{0}};
232  bid128_to_string (
233  out.str, _mc_to_bid128 (d), flags ? &flags->bits : &zero_flags.bits);
234  return out;
235 }
236 
240 static inline mc_dec128_string
241 mc_dec128_to_string (mc_dec128 d)
242 {
243  return mc_dec128_to_string_ex (d, NULL);
244 }
245 
247 #define DECL_IDF_COMPARE_1(Oper) \
248  static inline bool mc_dec128_##Oper##_ex ( \
249  mc_dec128 left, mc_dec128 right, mc_dec128_flagset *flags) \
250  { \
251  mc_dec128_flagset zero_flags = {0}; \
252  return 0 != \
253  bid128_quiet_##Oper (_mc_to_bid128 (left), \
254  _mc_to_bid128 (right), \
255  flags ? &flags->bits : &zero_flags.bits); \
256  } \
257  \
258  static inline bool mc_dec128_##Oper (mc_dec128 left, mc_dec128 right) \
259  { \
260  return mc_dec128_##Oper##_ex (left, right, NULL); \
261  }
262 
263 #define DECL_IDF_COMPARE(Op) DECL_IDF_COMPARE_1 (Op)
264 
265 DECL_IDF_COMPARE (equal)
266 DECL_IDF_COMPARE (not_equal)
267 DECL_IDF_COMPARE (greater)
268 DECL_IDF_COMPARE (greater_equal)
269 DECL_IDF_COMPARE (less)
270 DECL_IDF_COMPARE (less_equal)
271 
272 #undef DECL_IDF_COMPARE
273 #undef DECL_IDF_COMPARE_1
274 
276 #define DECL_PREDICATE(Name, BIDName) \
277  static inline bool mc_dec128_##Name (mc_dec128 d) \
278  { \
279  return 0 != bid128_##BIDName (_mc_to_bid128 (d)); \
280  }
281 
282 DECL_PREDICATE (is_zero, isZero)
283 DECL_PREDICATE (is_negative, isSigned)
284 DECL_PREDICATE (is_inf, isInf)
285 DECL_PREDICATE (is_finite, isFinite)
286 DECL_PREDICATE (is_nan, isNaN)
287 
288 #undef DECL_PREDICATE
289 
291 #define DECL_IDF_BINOP_WRAPPER(Oper) \
292  static inline mc_dec128 mc_dec128_##Oper##_ex ( \
293  mc_dec128 left, \
294  mc_dec128 right, \
295  mc_dec128_rounding_mode mode, \
296  mc_dec128_flagset *flags) \
297  { \
298  mc_dec128_flagset zero_flags = {0}; \
299  return _bid128_to_mc ( \
300  bid128_##Oper (_mc_to_bid128 (left), \
301  _mc_to_bid128 (right), \
302  mode, \
303  flags ? &flags->bits : &zero_flags.bits)); \
304  } \
305  \
306  static inline mc_dec128 mc_dec128_##Oper (mc_dec128 left, mc_dec128 right) \
307  { \
308  return mc_dec128_##Oper##_ex ( \
309  left, right, MC_DEC128_ROUND_DEFAULT, NULL); \
310  }
311 
312 DECL_IDF_BINOP_WRAPPER (add)
313 DECL_IDF_BINOP_WRAPPER (mul)
314 DECL_IDF_BINOP_WRAPPER (div)
315 DECL_IDF_BINOP_WRAPPER (sub)
316 DECL_IDF_BINOP_WRAPPER (pow)
317 
318 #undef DECL_IDF_BINOP_WRAPPER
319 
321 #define DECL_IDF_UNOP_WRAPPER(Oper) \
322  static inline mc_dec128 mc_dec128_##Oper##_ex (mc_dec128 operand, \
323  mc_dec128_flagset *flags) \
324  { \
325  mc_dec128_flagset zero_flags = {0}; \
326  return _bid128_to_mc ( \
327  bid128_##Oper (_mc_to_bid128 (operand), \
328  MC_DEC128_ROUND_DEFAULT, \
329  flags ? &flags->bits : &zero_flags.bits)); \
330  } \
331  \
332  static inline mc_dec128 mc_dec128_##Oper (mc_dec128 operand) \
333  { \
334  return mc_dec128_##Oper##_ex (operand, NULL); \
335  }
336 
337 DECL_IDF_UNOP_WRAPPER (log2)
338 DECL_IDF_UNOP_WRAPPER (log10)
339 #undef DECL_IDF_UNOP_WRAPPER
340 
341 static inline mc_dec128
342 mc_dec128_round_integral_ex (mc_dec128 value,
343  mc_dec128_rounding_mode direction,
344  mc_dec128_flagset *flags)
345 {
346  BID_UINT128 bid = _mc_to_bid128 (value);
347  mc_dec128_flagset zero_flags = {0};
348  _IDEC_flags *fl = flags ? &flags->bits : &zero_flags.bits;
349  switch (direction) {
350  case MC_DEC128_ROUND_TOWARD_ZERO:
351  return _bid128_to_mc (bid128_round_integral_zero (bid, fl));
352  case MC_DEC128_ROUND_NEAREST_AWAY:
353  return _bid128_to_mc (bid128_round_integral_nearest_away (bid, fl));
354  case MC_DEC128_ROUND_NEAREST_EVEN:
355  return _bid128_to_mc (bid128_round_integral_nearest_even (bid, fl));
356  case MC_DEC128_ROUND_DOWNWARD:
357  return _bid128_to_mc (bid128_round_integral_negative (bid, fl));
358  case MC_DEC128_ROUND_UPWARD:
359  return _bid128_to_mc (bid128_round_integral_positive (bid, fl));
360  default:
361  abort ();
362  }
363 }
364 
365 static inline mc_dec128
366 mc_dec128_negate (mc_dec128 operand)
367 {
368  return _bid128_to_mc (bid128_negate (_mc_to_bid128 (operand)));
369 }
370 
371 static inline mc_dec128
372 mc_dec128_abs (mc_dec128 operand)
373 {
374  return _bid128_to_mc (bid128_abs (_mc_to_bid128 (operand)));
375 }
376 
386 static inline mc_dec128
387 mc_dec128_scale_ex (mc_dec128 fac,
388  long int exp,
389  mc_dec128_rounding_mode rounding,
390  mc_dec128_flagset *flags)
391 {
392  mc_dec128_flagset zero_flags = {0};
393  return _bid128_to_mc (
394  bid128_scalbln (_mc_to_bid128 (fac),
395  exp,
396  rounding,
397  flags ? &flags->bits : &zero_flags.bits));
398 }
399 
407 static inline mc_dec128
408 mc_dec128_scale (mc_dec128 fac, long int exp)
409 {
410  return mc_dec128_scale_ex (fac, exp, MC_DEC128_ROUND_DEFAULT, NULL);
411 }
412 
414 typedef struct mc_dec128_modf_result {
416  mc_dec128 whole;
418  mc_dec128 frac;
419 } mc_dec128_modf_result;
420 
430 static inline mc_dec128_modf_result
431 mc_dec128_modf_ex (mc_dec128 d, mc_dec128_flagset *flags)
432 {
433  mc_dec128_flagset zero_flags = {0};
434  mc_dec128_modf_result res;
435  BID_UINT128 whole;
436  res.frac = _bid128_to_mc (bid128_modf (
437  _mc_to_bid128 (d), &whole, flags ? &flags->bits : &zero_flags.bits));
438  res.whole = _bid128_to_mc (whole);
439  return res;
440 }
441 
450 static inline mc_dec128_modf_result
451 mc_dec128_modf (mc_dec128 d)
452 {
453  return mc_dec128_modf_ex (d, NULL);
454 }
455 
464 static inline mc_dec128
465 mc_dec128_fmod_ex (mc_dec128 numer, mc_dec128 denom, mc_dec128_flagset *flags)
466 {
467  mc_dec128_flagset zero_flags = {0};
468  return _bid128_to_mc (bid128_fmod (_mc_to_bid128 (numer),
469  _mc_to_bid128 (denom),
470  flags ? &flags->bits : &zero_flags.bits));
471 }
472 
480 static inline mc_dec128
481 mc_dec128_fmod (mc_dec128 numer, mc_dec128 denom)
482 {
483  return mc_dec128_fmod_ex (numer, denom, NULL);
484 }
485 
493 static inline int64_t
494 mc_dec128_to_int64_ex (mc_dec128 d, mc_dec128_flagset *flags)
495 {
496  mc_dec128_flagset zero_flags = {0};
497  return bid128_to_int64_int (_mc_to_bid128 (d),
498  flags ? &flags->bits : &zero_flags.bits);
499 }
500 
507 static inline int64_t
508 mc_dec128_to_int64 (mc_dec128 d)
509 {
510  return mc_dec128_to_int64_ex (d, NULL);
511 }
512 
514 enum {
516  MC_DEC128_COMBO_NONCANONICAL = 3 << 15,
518  MC_DEC128_COMBO_INFINITY = 0x1e << 12,
520  MC_DEC128_MAX_BIASED_EXPONENT = 6143 + 6144,
522  MC_DEC128_EXPONENT_BIAS = 6143 + 33, // +33 to include the 34 decimal digits
524  MC_DEC_MIN_EXPONENT = -6143,
526  MC_DEC_MAX_EXPONENT = 6144,
527 };
528 
530 static inline uint32_t
531 mc_dec128_combination (mc_dec128 d)
532 {
533  // Grab the high 64 bits:
534  uint64_t hi = d._words[MLIB_IS_LITTLE_ENDIAN ? 1 : 0];
535  // Sign is the 64th bit:
536  int signpos = 64 - 1;
537  // Combo is the next 16 bits:
538  int fieldpos = signpos - 17;
539  int fieldmask = (1 << 17) - 1;
540  return (uint32_t) ((hi >> fieldpos) & (uint32_t) fieldmask);
541 }
542 
546 static inline uint64_t
547 mc_dec128_coeff_high (mc_dec128 d)
548 {
549  uint64_t hi_field_mask = (1ull << 49) - 1;
550  uint32_t combo = mc_dec128_combination (d);
551  if (combo < MC_DEC128_COMBO_NONCANONICAL) {
552  uint64_t hi = d._words[MLIB_IS_LITTLE_ENDIAN ? 1 : 0];
553  return hi & hi_field_mask;
554  } else {
555  return 0;
556  }
557 }
558 
562 static inline uint64_t
563 mc_dec128_coeff_low (mc_dec128 d)
564 {
565  uint32_t combo = mc_dec128_combination (d);
566  if (combo < MC_DEC128_COMBO_NONCANONICAL) {
567  uint64_t lo = d._words[MLIB_IS_LITTLE_ENDIAN ? 0 : 1];
568  return lo;
569  } else {
570  return 0;
571  }
572 }
573 
578 static inline mlib_int128
579 mc_dec128_coeff (mc_dec128 d)
580 {
581  // Hi bits
582  uint64_t hi = mc_dec128_coeff_high (d);
583  // Lo bits
584  uint64_t lo = mc_dec128_coeff_low (d);
585  // Shift and add
586  mlib_int128 hi_128 = mlib_int128_lshift (MLIB_INT128_CAST (hi), 64);
587  return mlib_int128_add (hi_128, MLIB_INT128_CAST (lo));
588 }
589 
598 static inline uint32_t
599 mc_dec128_get_biased_exp (mc_dec128 d)
600 {
601  uint32_t combo = mc_dec128_combination (d);
602  if (combo < MC_DEC128_COMBO_NONCANONICAL) {
603  return combo >> 3;
604  }
605  if (combo >= MC_DEC128_COMBO_INFINITY) {
606  return MC_DEC128_MAX_BIASED_EXPONENT + 1;
607  } else {
608  return (combo >> 1) & ((1 << 14) - 1);
609  }
610 }
611 
613 static inline char *
614 mc_dec128_to_new_decimal_string (mc_dec128 d)
615 {
616  if (mc_dec128_is_zero (d)) {
617  // Just return "0"
618  char *s = (char *) calloc (2, 1);
619  if (s) {
620  s[0] = '0';
621  }
622  return s;
623  }
624 
625  if (mc_dec128_is_negative (d)) {
626  // Negate the result, return a string with a '-' prefix
627  d = mc_dec128_negate (d);
628  char *s = mc_dec128_to_new_decimal_string (d);
629  if (!s) {
630  return NULL;
631  }
632  char *s1 = (char *) calloc (strlen (s) + 2, 1);
633  if (s1) {
634  s1[0] = '-';
635  strcpy (s1 + 1, s);
636  }
637  free (s);
638  return s1;
639  }
640 
641  if (mc_dec128_is_inf (d) || mc_dec128_is_nan (d)) {
642  const char *r = mc_dec128_is_inf (d) ? "Infinity" : "NaN";
643  char *c = (char *) calloc (strlen (r) + 1, 1);
644  if (c) {
645  strcpy (c, r);
646  }
647  return c;
648  }
649 
650  const char DIGITS[] = "0123456789";
651  const mc_dec128 TEN = MC_DEC128_C (10);
652 
653  // Format the whole and fractional part separately.
654  mc_dec128_modf_result modf = mc_dec128_modf (d);
655 
656  if (mc_dec128_is_zero (modf.frac)) {
657  // This is a non-zero integer
658  // Allocate enough digits:
659  mc_dec128 log10 = mc_dec128_modf (mc_dec128_log10 (d)).whole;
660  int64_t ndigits = mc_dec128_to_int64 (log10) + 1;
661  // +1 for null
662  char *strbuf = (char *) calloc ((size_t) (ndigits + 1), 1);
663  if (strbuf) {
664  // Write the string backwards:
665  char *optr = strbuf + ndigits - 1;
666  while (!mc_dec128_is_zero (modf.whole)) {
667  mc_dec128 rem = mc_dec128_fmod (modf.whole, TEN);
668  int64_t remi = mc_dec128_to_int64 (rem);
669  *optr-- = DIGITS[remi];
670  // Divide ten
671  modf = mc_dec128_modf (mc_dec128_div (modf.whole, TEN));
672  }
673  }
674  return strbuf;
675  } else if (mc_dec128_is_zero (modf.whole)) {
676  // This is only a fraction (less than one, but more than zero)
677  while (!mc_dec128_is_zero (mc_dec128_modf (d).frac)) {
678  d = mc_dec128_mul (d, TEN);
679  }
680  // 'd' is now a whole number
681  char *part = mc_dec128_to_new_decimal_string (d);
682  if (!part) {
683  return NULL;
684  }
685  char *buf = (char *) calloc (strlen (part) + 3, 1);
686  if (buf) {
687  buf[0] = '0';
688  buf[1] = '.';
689  strcpy (buf + 2, part);
690  }
691  free (part);
692  return buf;
693  } else {
694  // We have both a whole part and a fractional part
695  char *whole = mc_dec128_to_new_decimal_string (modf.whole);
696  if (!whole) {
697  return NULL;
698  }
699  char *frac = mc_dec128_to_new_decimal_string (modf.frac);
700  if (!frac) {
701  free (whole);
702  return NULL;
703  }
704  char *ret = (char *) calloc (strlen (whole) + strlen (frac) + 1, 1);
705  if (ret) {
706  char *out = ret;
707  strcpy (out, whole);
708  out += strlen (whole);
709  // "frac" contains a leading zero, which we don't want
710  strcpy (out, frac + 1);
711  }
712  free (whole);
713  free (frac);
714  return ret;
715  }
716 }
717 
718 static inline mc_dec128
719 mc_dec128_from_bson_iter (bson_iter_t *it)
720 {
721  bson_decimal128_t b;
722  if (!bson_iter_decimal128 (it, &b)) {
723  mc_dec128 nan = MC_DEC128_POSITIVE_NAN;
724  return nan;
725  }
726  mc_dec128 ret;
727  memcpy (&ret, &b, sizeof b);
728  return ret;
729 }
730 
731 static inline bson_decimal128_t
732 mc_dec128_to_bson_decimal128 (mc_dec128 v)
733 {
734  bson_decimal128_t ret;
735  memcpy (&ret, &v, sizeof ret);
736  return ret;
737 }
738 
739 MLIB_C_LINKAGE_END
740 
741 #endif
742 
743 #endif // MC_DEC128_H_INCLUDED