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 // Include the header that declares the DFP functions, which may be macros that
11 // expand to renamed symbols:
12 #include <bid_conf.h>
13 #include <bid_functions.h>
14 
15 #include <inttypes.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include <float.h>
19 
20 MLIB_C_LINKAGE_BEGIN
21 
23 typedef enum mc_dec128_rounding_mode {
24  MC_DEC128_ROUND_NEAREST_EVEN = 0,
25  MC_DEC128_ROUND_DOWNWARD = 1,
26  MC_DEC128_ROUND_UPWARD = 2,
27  MC_DEC128_ROUND_TOWARD_ZERO = 3,
28  MC_DEC128_ROUND_NEAREST_AWAY = 4,
29  MC_DEC128_ROUND_DEFAULT = MC_DEC128_ROUND_NEAREST_EVEN,
30 } mc_dec128_rounding_mode;
31 
32 typedef struct mc_dec128_flagset {
33  _IDEC_flags bits;
35 
36 // This alignment conditional is the same conditions used in Intel's DFP
37 // library, ensuring we match the ABI of the library without pulling the header
38 #if defined _MSC_VER
39 #if defined _M_IX86 && !defined __INTEL_COMPILER
40 #define _mcDec128Align(n)
41 #else
42 #define _mcDec128Align(n) __declspec(align (n))
43 #endif
44 #else
45 #if !defined HPUX_OS
46 #define _mcDec128Align(n) __attribute__ ((aligned (n)))
47 #else
48 #define _mcDec128Align(n)
49 #endif
50 #endif
51 
52 typedef union _mcDec128Align (16)
53 {
54  uint64_t _words[2];
55 #if !defined(__INTELLISENSE__) && defined(__GNUC__) && defined(__amd64) && \
56  !defined(__APPLE__) && !defined(__clang__)
57  // If supported by the compiler, emit a field that can be used to visualize
58  // the value in a debugger.
59  float value_ __attribute__ ((mode (TD)));
60 #endif
61 }
62 mc_dec128;
63 
64 #undef _mcDec128Align
65 
67 #ifdef __cplusplus
68 #define MC_DEC128_C(N) \
69  mc_dec128 _mcDec128Const (((N) < 0 ? -(N) : (N)), ((N) < 0 ? 1 : 0))
70 #else
71 #define MC_DEC128_C(N) \
72  _mcDec128Const (((N) < 0 ? -(N) : (N)), ((N) < 0 ? 1 : 0))
73 #endif
74 
75 #define MC_DEC128(N) MLIB_INIT (mc_dec128) MC_DEC128_C (N)
76 
77 #define _mcDec128Combination(Bits) ((uint64_t) (Bits) << (47))
78 #define _mcDec128ZeroExpCombo _mcDec128Combination (1 << 7 | 1 << 13 | 1 << 14)
79 #define _mcDec128Const(N, Negate) \
80  _mcDec128ConstFromParts ( \
81  N, (_mcDec128ZeroExpCombo | ((uint64_t) (Negate) << 63)))
82 #define _mcDec128ConstFromParts(CoeffLow, HighWord) \
83  { \
84  { \
85  MLIB_IS_LITTLE_ENDIAN ? (uint64_t) (CoeffLow) \
86  : (uint64_t) (HighWord), \
87  MLIB_IS_LITTLE_ENDIAN ? (uint64_t) (HighWord) \
88  : (uint64_t) (CoeffLow), \
89  }, \
90  }
91 
92 static const mc_dec128 MC_DEC128_ZERO = MC_DEC128_C (0);
93 static const mc_dec128 MC_DEC128_ONE = MC_DEC128_C (1);
94 static const mc_dec128 MC_DEC128_MINUSONE = MC_DEC128_C (-1);
95 
97 #define MC_DEC128_LARGEST_NEGATIVE \
98  mc_dec128_from_string ("-9999999999999999999999999999999999E6111")
100 #define MC_DEC128_SMALLEST_NEGATIVE mc_dec128_from_string ("-1E-6176")
102 #define MC_DEC128_LARGEST_POSITIVE \
103  mc_dec128_from_string ("9999999999999999999999999999999999E6111")
105 #define MC_DEC128_SMALLEST_POSITIVE mc_dec128_from_string ("1E-6176")
107 #define MC_DEC128_NORMALIZED_ZERO MC_DEC128_C (0)
109 #define MC_DEC128_NEGATIVE_EXPONENT_ZERO mc_dec128_from_string ("0E-6176")
110 #define _mcDec128InfCombo \
111  _mcDec128Combination (1 << 15 | 1 << 14 | 1 << 13 | 1 << 12)
112 #define _mcDec128QuietNaNCombo \
113  _mcDec128Combination (1 << 15 | 1 << 14 | 1 << 13 | 1 << 12 | 1 << 11)
114 
116 #define MC_DEC128_POSITIVE_INFINITY \
117  _mcDec128ConstFromParts (0, _mcDec128InfCombo)
119 #define MC_DEC128_NEGATIVE_INFINITY \
120  _mcDec128ConstFromParts (0, _mcDec128InfCombo | 1ull << 63)
122 #define MC_DEC128_POSITIVE_NAN \
123  _mcDec128ConstFromParts (0, _mcDec128QuietNaNCombo)
125 #define MC_DEC128_NEGATIVE_NAN \
126  _mcDec128ConstFromParts (0, _mcDec128QuietNaNCombo | 1ull << 63)
127 
129 static inline BID_UINT128
130 _mc_to_bid128 (mc_dec128 d)
131 {
132  BID_UINT128 r;
133  memcpy (&r, &d, sizeof d);
134  return r;
135 }
136 
138 static inline mc_dec128
139 _bid128_to_mc (BID_UINT128 d)
140 {
141  mc_dec128 r;
142  memcpy (&r, &d, sizeof d);
143  return r;
144 }
145 
154 static inline mc_dec128
155 mc_dec128_from_double_ex (double d,
156  mc_dec128_rounding_mode rnd,
157  mc_dec128_flagset *flags)
158 {
159  mc_dec128_flagset zero_flags = {0};
160  return _bid128_to_mc (
161  binary64_to_bid128 (d, rnd, flags ? &flags->bits : &zero_flags.bits));
162 }
163 
168 static inline mc_dec128
169 mc_dec128_from_double (double d)
170 {
171  return mc_dec128_from_double_ex (d, MC_DEC128_ROUND_DEFAULT, NULL);
172 }
173 
182 static inline mc_dec128
183 mc_dec128_from_string_ex (const char *s,
184  mc_dec128_rounding_mode rnd,
185  mc_dec128_flagset *flags)
186 {
187  mc_dec128_flagset zero_flags = {0};
188  return _bid128_to_mc (bid128_from_string (
189  (char *) s, rnd, flags ? &flags->bits : &zero_flags.bits));
190 }
191 
196 static inline mc_dec128
197 mc_dec128_from_string (const char *s)
198 {
199  return mc_dec128_from_string_ex (s, MC_DEC128_ROUND_DEFAULT, NULL);
200 }
201 
206 typedef struct mc_dec128_string {
208  char str[48];
210 
217 static inline mc_dec128_string
218 mc_dec128_to_string_ex (mc_dec128 d, mc_dec128_flagset *flags)
219 {
220  mc_dec128_flagset zero_flags = {0};
221  mc_dec128_string out = {{0}};
222  bid128_to_string (
223  out.str, _mc_to_bid128 (d), flags ? &flags->bits : &zero_flags.bits);
224  return out;
225 }
226 
230 static inline mc_dec128_string
231 mc_dec128_to_string (mc_dec128 d)
232 {
233  return mc_dec128_to_string_ex (d, NULL);
234 }
235 
237 #define DECL_IDF_COMPARE_1(Oper) \
238  static inline bool mc_dec128_##Oper##_ex ( \
239  mc_dec128 left, mc_dec128 right, mc_dec128_flagset *flags) \
240  { \
241  mc_dec128_flagset zero_flags = {0}; \
242  return 0 != \
243  bid128_quiet_##Oper (_mc_to_bid128 (left), \
244  _mc_to_bid128 (right), \
245  flags ? &flags->bits : &zero_flags.bits); \
246  } \
247  \
248  static inline bool mc_dec128_##Oper (mc_dec128 left, mc_dec128 right) \
249  { \
250  return mc_dec128_##Oper##_ex (left, right, NULL); \
251  }
252 
253 #define DECL_IDF_COMPARE(Op) DECL_IDF_COMPARE_1 (Op)
254 
255 DECL_IDF_COMPARE (equal)
256 DECL_IDF_COMPARE (not_equal)
257 DECL_IDF_COMPARE (greater)
258 DECL_IDF_COMPARE (greater_equal)
259 DECL_IDF_COMPARE (less)
260 DECL_IDF_COMPARE (less_equal)
261 
262 #undef DECL_IDF_COMPARE
263 #undef DECL_IDF_COMPARE_1
264 
266 #define DECL_PREDICATE(Name, BIDName) \
267  static inline bool mc_dec128_##Name (mc_dec128 d) \
268  { \
269  return 0 != bid128_##BIDName (_mc_to_bid128 (d)); \
270  }
271 
272 DECL_PREDICATE (is_zero, isZero)
273 DECL_PREDICATE (is_negative, isSigned)
274 DECL_PREDICATE (is_inf, isInf)
275 DECL_PREDICATE (is_finite, isFinite)
276 DECL_PREDICATE (is_nan, isNaN)
277 
278 #undef DECL_PREDICATE
279 
281 #define DECL_IDF_BINOP_WRAPPER(Oper) \
282  static inline mc_dec128 mc_dec128_##Oper##_ex ( \
283  mc_dec128 left, \
284  mc_dec128 right, \
285  mc_dec128_rounding_mode mode, \
286  mc_dec128_flagset *flags) \
287  { \
288  mc_dec128_flagset zero_flags = {0}; \
289  return _bid128_to_mc ( \
290  bid128_##Oper (_mc_to_bid128 (left), \
291  _mc_to_bid128 (right), \
292  mode, \
293  flags ? &flags->bits : &zero_flags.bits)); \
294  } \
295  \
296  static inline mc_dec128 mc_dec128_##Oper (mc_dec128 left, mc_dec128 right) \
297  { \
298  return mc_dec128_##Oper##_ex ( \
299  left, right, MC_DEC128_ROUND_DEFAULT, NULL); \
300  }
301 
302 DECL_IDF_BINOP_WRAPPER (add)
303 DECL_IDF_BINOP_WRAPPER (mul)
304 DECL_IDF_BINOP_WRAPPER (div)
305 DECL_IDF_BINOP_WRAPPER (sub)
306 DECL_IDF_BINOP_WRAPPER (pow)
307 
308 #undef DECL_IDF_BINOP_WRAPPER
309 
311 #define DECL_IDF_UNOP_WRAPPER(Oper) \
312  static inline mc_dec128 mc_dec128_##Oper##_ex (mc_dec128 operand, \
313  mc_dec128_flagset *flags) \
314  { \
315  mc_dec128_flagset zero_flags = {0}; \
316  return _bid128_to_mc ( \
317  bid128_##Oper (_mc_to_bid128 (operand), \
318  MC_DEC128_ROUND_DEFAULT, \
319  flags ? &flags->bits : &zero_flags.bits)); \
320  } \
321  \
322  static inline mc_dec128 mc_dec128_##Oper (mc_dec128 operand) \
323  { \
324  return mc_dec128_##Oper##_ex (operand, NULL); \
325  }
326 
327 DECL_IDF_UNOP_WRAPPER (log2)
328 DECL_IDF_UNOP_WRAPPER (log10)
329 #undef DECL_IDF_UNOP_WRAPPER
330 
331 static inline mc_dec128
332 mc_dec128_round_integral_ex (mc_dec128 value,
333  mc_dec128_rounding_mode direction,
334  mc_dec128_flagset *flags)
335 {
336  BID_UINT128 bid = _mc_to_bid128 (value);
337  mc_dec128_flagset zero_flags = {0};
338  _IDEC_flags *fl = flags ? &flags->bits : &zero_flags.bits;
339  switch (direction) {
340  case MC_DEC128_ROUND_TOWARD_ZERO:
341  return _bid128_to_mc (bid128_round_integral_zero (bid, fl));
342  case MC_DEC128_ROUND_NEAREST_AWAY:
343  return _bid128_to_mc (bid128_round_integral_nearest_away (bid, fl));
344  case MC_DEC128_ROUND_NEAREST_EVEN:
345  return _bid128_to_mc (bid128_round_integral_nearest_even (bid, fl));
346  case MC_DEC128_ROUND_DOWNWARD:
347  return _bid128_to_mc (bid128_round_integral_negative (bid, fl));
348  case MC_DEC128_ROUND_UPWARD:
349  return _bid128_to_mc (bid128_round_integral_positive (bid, fl));
350  default:
351  abort ();
352  }
353 }
354 
355 static inline mc_dec128
356 mc_dec128_negate (mc_dec128 operand)
357 {
358  return _bid128_to_mc (bid128_negate (_mc_to_bid128 (operand)));
359 }
360 
361 static inline mc_dec128
362 mc_dec128_abs (mc_dec128 operand)
363 {
364  return _bid128_to_mc (bid128_abs (_mc_to_bid128 (operand)));
365 }
366 
376 static inline mc_dec128
377 mc_dec128_scale_ex (mc_dec128 fac,
378  long int exp,
379  mc_dec128_rounding_mode rounding,
380  mc_dec128_flagset *flags)
381 {
382  mc_dec128_flagset zero_flags = {0};
383  return _bid128_to_mc (
384  bid128_scalbln (_mc_to_bid128 (fac),
385  exp,
386  rounding,
387  flags ? &flags->bits : &zero_flags.bits));
388 }
389 
397 static inline mc_dec128
398 mc_dec128_scale (mc_dec128 fac, long int exp)
399 {
400  return mc_dec128_scale_ex (fac, exp, MC_DEC128_ROUND_DEFAULT, NULL);
401 }
402 
404 typedef struct mc_dec128_modf_result {
406  mc_dec128 whole;
408  mc_dec128 frac;
410 
420 static inline mc_dec128_modf_result
421 mc_dec128_modf_ex (mc_dec128 d, mc_dec128_flagset *flags)
422 {
423  mc_dec128_flagset zero_flags = {0};
425  BID_UINT128 whole;
426  res.frac = _bid128_to_mc (bid128_modf (
427  _mc_to_bid128 (d), &whole, flags ? &flags->bits : &zero_flags.bits));
428  res.whole = _bid128_to_mc (whole);
429  return res;
430 }
431 
440 static inline mc_dec128_modf_result
441 mc_dec128_modf (mc_dec128 d)
442 {
443  return mc_dec128_modf_ex (d, NULL);
444 }
445 
454 static inline mc_dec128
455 mc_dec128_fmod_ex (mc_dec128 numer, mc_dec128 denom, mc_dec128_flagset *flags)
456 {
457  mc_dec128_flagset zero_flags = {0};
458  return _bid128_to_mc (bid128_fmod (_mc_to_bid128 (numer),
459  _mc_to_bid128 (denom),
460  flags ? &flags->bits : &zero_flags.bits));
461 }
462 
470 static inline mc_dec128
471 mc_dec128_fmod (mc_dec128 numer, mc_dec128 denom)
472 {
473  return mc_dec128_fmod_ex (numer, denom, NULL);
474 }
475 
483 static inline int64_t
484 mc_dec128_to_int64_ex (mc_dec128 d, mc_dec128_flagset *flags)
485 {
486  mc_dec128_flagset zero_flags = {0};
487  return bid128_to_int64_int (_mc_to_bid128 (d),
488  flags ? &flags->bits : &zero_flags.bits);
489 }
490 
497 static inline int64_t
498 mc_dec128_to_int64 (mc_dec128 d)
499 {
500  return mc_dec128_to_int64_ex (d, NULL);
501 }
502 
504 enum {
506  MC_DEC128_COMBO_NONCANONICAL = 3 << 15,
508  MC_DEC128_COMBO_INFINITY = 0x1e << 12,
510  MC_DEC128_MAX_BIASED_EXPONENT = 6143 + 6144,
512  MC_DEC128_EXPONENT_BIAS = 6143 + 33, // +33 to include the 34 decimal digits
514  MC_DEC_MIN_EXPONENT = -6143,
516  MC_DEC_MAX_EXPONENT = 6144,
517 };
518 
520 static inline uint32_t
521 mc_dec128_combination (mc_dec128 d)
522 {
523  // Grab the high 64 bits:
524  uint64_t hi = d._words[MLIB_IS_LITTLE_ENDIAN ? 1 : 0];
525  // Sign is the 64th bit:
526  int signpos = 64 - 1;
527  // Combo is the next 16 bits:
528  int fieldpos = signpos - 17;
529  int fieldmask = (1 << 17) - 1;
530  return (uint32_t) ((hi >> fieldpos) & (uint32_t) fieldmask);
531 }
532 
536 static inline uint64_t
537 mc_dec128_coeff_high (mc_dec128 d)
538 {
539  uint64_t hi_field_mask = (1ull << 49) - 1;
540  uint32_t combo = mc_dec128_combination (d);
541  if (combo < MC_DEC128_COMBO_NONCANONICAL) {
542  uint64_t hi = d._words[MLIB_IS_LITTLE_ENDIAN ? 1 : 0];
543  return hi & hi_field_mask;
544  } else {
545  return 0;
546  }
547 }
548 
552 static inline uint64_t
553 mc_dec128_coeff_low (mc_dec128 d)
554 {
555  uint32_t combo = mc_dec128_combination (d);
556  if (combo < MC_DEC128_COMBO_NONCANONICAL) {
557  uint64_t lo = d._words[MLIB_IS_LITTLE_ENDIAN ? 0 : 1];
558  return lo;
559  } else {
560  return 0;
561  }
562 }
563 
568 static inline mlib_int128
569 mc_dec128_coeff (mc_dec128 d)
570 {
571  // Hi bits
572  uint64_t hi = mc_dec128_coeff_high (d);
573  // Lo bits
574  uint64_t lo = mc_dec128_coeff_low (d);
575  // Shift and add
576  mlib_int128 hi_128 = mlib_int128_lshift (MLIB_INT128_CAST (hi), 64);
577  return mlib_int128_add (hi_128, MLIB_INT128_CAST (lo));
578 }
579 
588 static inline uint32_t
589 mc_dec128_get_biased_exp (mc_dec128 d)
590 {
591  uint32_t combo = mc_dec128_combination (d);
592  if (combo < MC_DEC128_COMBO_NONCANONICAL) {
593  return combo >> 3;
594  }
595  if (combo >= MC_DEC128_COMBO_INFINITY) {
596  return MC_DEC128_MAX_BIASED_EXPONENT + 1;
597  } else {
598  return (combo >> 1) & ((1 << 14) - 1);
599  }
600 }
601 
603 static inline char *
604 mc_dec128_to_new_decimal_string (mc_dec128 d)
605 {
606  if (mc_dec128_is_zero (d)) {
607  // Just return "0"
608  char *s = (char *) calloc (2, 1);
609  if (s) {
610  s[0] = '0';
611  }
612  return s;
613  }
614 
615  if (mc_dec128_is_negative (d)) {
616  // Negate the result, return a string with a '-' prefix
617  d = mc_dec128_negate (d);
618  char *s = mc_dec128_to_new_decimal_string (d);
619  if (!s) {
620  return NULL;
621  }
622  char *s1 = (char *) calloc (strlen (s) + 2, 1);
623  if (s1) {
624  s1[0] = '-';
625  strcpy (s1 + 1, s);
626  }
627  free (s);
628  return s1;
629  }
630 
631  if (mc_dec128_is_inf (d) || mc_dec128_is_nan (d)) {
632  const char *r = mc_dec128_is_inf (d) ? "Infinity" : "NaN";
633  char *c = (char *) calloc (strlen (r) + 1, 1);
634  if (c) {
635  strcpy (c, r);
636  }
637  return c;
638  }
639 
640  const char DIGITS[] = "0123456789";
641  const mc_dec128 TEN = MC_DEC128_C (10);
642 
643  // Format the whole and fractional part separately.
644  mc_dec128_modf_result modf = mc_dec128_modf (d);
645 
646  if (mc_dec128_is_zero (modf.frac)) {
647  // This is a non-zero integer
648  // Allocate enough digits:
649  mc_dec128 log10 = mc_dec128_modf (mc_dec128_log10 (d)).whole;
650  int64_t ndigits = mc_dec128_to_int64 (log10) + 1;
651  // +1 for null
652  char *strbuf = (char *) calloc ((size_t) (ndigits + 1), 1);
653  if (strbuf) {
654  // Write the string backwards:
655  char *optr = strbuf + ndigits - 1;
656  while (!mc_dec128_is_zero (modf.whole)) {
657  mc_dec128 rem = mc_dec128_fmod (modf.whole, TEN);
658  int64_t remi = mc_dec128_to_int64 (rem);
659  *optr-- = DIGITS[remi];
660  // Divide ten
661  modf = mc_dec128_modf (mc_dec128_div (modf.whole, TEN));
662  }
663  }
664  return strbuf;
665  } else if (mc_dec128_is_zero (modf.whole)) {
666  // This is only a fraction (less than one, but more than zero)
667  while (!mc_dec128_is_zero (mc_dec128_modf (d).frac)) {
668  d = mc_dec128_mul (d, TEN);
669  }
670  // 'd' is now a whole number
671  char *part = mc_dec128_to_new_decimal_string (d);
672  if (!part) {
673  return NULL;
674  }
675  char *buf = (char *) calloc (strlen (part) + 3, 1);
676  if (buf) {
677  buf[0] = '0';
678  buf[1] = '.';
679  strcpy (buf + 2, part);
680  }
681  free (part);
682  return buf;
683  } else {
684  // We have both a whole part and a fractional part
685  char *whole = mc_dec128_to_new_decimal_string (modf.whole);
686  if (!whole) {
687  return NULL;
688  }
689  char *frac = mc_dec128_to_new_decimal_string (modf.frac);
690  if (!frac) {
691  free (whole);
692  return NULL;
693  }
694  char *ret = (char *) calloc (strlen (whole) + strlen (frac) + 1, 1);
695  if (ret) {
696  char *out = ret;
697  strcpy (out, whole);
698  out += strlen (whole);
699  // "frac" contains a leading zero, which we don't want
700  strcpy (out, frac + 1);
701  }
702  free (whole);
703  free (frac);
704  return ret;
705  }
706 }
707 
708 static inline mc_dec128
709 mc_dec128_from_bson_iter (bson_iter_t *it)
710 {
711  bson_decimal128_t b;
712  if (!bson_iter_decimal128 (it, &b)) {
713  mc_dec128 nan = MC_DEC128_POSITIVE_NAN;
714  return nan;
715  }
716  mc_dec128 ret;
717  memcpy (&ret, &b, sizeof b);
718  return ret;
719 }
720 
721 static inline bson_decimal128_t
722 mc_dec128_to_bson_decimal128 (mc_dec128 v)
723 {
724  bson_decimal128_t ret;
725  memcpy (&ret, &v, sizeof ret);
726  return ret;
727 }
728 
729 MLIB_C_LINKAGE_END
730 
731 #endif // MC_DEC128_H_INCLUDED
Definition: mc-dec128.h:32
The result of a dec_128 modf operation.
Definition: mc-dec128.h:404
mc_dec128 whole
The whole part of the result.
Definition: mc-dec128.h:406
mc_dec128 frac
The fractional part of the result.
Definition: mc-dec128.h:408
A type capable of holding a string rendering of a Decimal128 in engineering notation.
Definition: mc-dec128.h:206
char str[48]
The character array of the rendered value. Null-terminated.
Definition: mc-dec128.h:208