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/endian.h>
7 #include <mlib/int128.h>
8 #include <mlib/macros.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 <float.h>
26 #include <inttypes.h>
27 #include <stdlib.h>
28 #include <string.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  uint64_t _words[2];
64 #if !defined(__INTELLISENSE__) && defined(__GNUC__) && defined(__amd64) && !defined(__APPLE__) && !defined(__clang__)
65  // If supported by the compiler, emit a field that can be used to visualize
66  // the value in a debugger.
67  float value_ __attribute__((mode(TD)));
68 #endif
69 }
70 
71 mc_dec128;
72 
73 #undef _mcDec128Align
74 
76 #ifdef __cplusplus
77 #define MC_DEC128_C(N) mc_dec128 _mcDec128Const(((N) < 0 ? -(N) : (N)), ((N) < 0 ? 1 : 0))
78 #else
79 #define MC_DEC128_C(N) _mcDec128Const(((N) < 0 ? -(N) : (N)), ((N) < 0 ? 1 : 0))
80 #endif
81 
82 #define MC_DEC128(N) MLIB_INIT(mc_dec128) MC_DEC128_C(N)
83 
84 #define _mcDec128Combination(Bits) ((uint64_t)(Bits) << (47))
85 #define _mcDec128ZeroExpCombo _mcDec128Combination(1 << 7 | 1 << 13 | 1 << 14)
86 #define _mcDec128Const(N, Negate) _mcDec128ConstFromParts(N, (_mcDec128ZeroExpCombo | ((uint64_t)(Negate) << 63)))
87 #define _mcDec128ConstFromParts(CoeffLow, HighWord) \
88  { \
89  { \
90  MLIB_IS_LITTLE_ENDIAN ? (uint64_t)(CoeffLow) : (uint64_t)(HighWord), \
91  MLIB_IS_LITTLE_ENDIAN ? (uint64_t)(HighWord) : (uint64_t)(CoeffLow), \
92  }, \
93  }
94 
95 static const mc_dec128 MC_DEC128_ZERO = MC_DEC128_C(0);
96 static const mc_dec128 MC_DEC128_ONE = MC_DEC128_C(1);
97 static const mc_dec128 MC_DEC128_MINUSONE = MC_DEC128_C(-1);
98 
100 #define MC_DEC128_LARGEST_NEGATIVE mc_dec128_from_string("-9999999999999999999999999999999999E6111")
102 #define MC_DEC128_SMALLEST_NEGATIVE mc_dec128_from_string("-1E-6176")
104 #define MC_DEC128_LARGEST_POSITIVE mc_dec128_from_string("9999999999999999999999999999999999E6111")
106 #define MC_DEC128_SMALLEST_POSITIVE mc_dec128_from_string("1E-6176")
108 #define MC_DEC128_NORMALIZED_ZERO MC_DEC128_C(0)
110 #define MC_DEC128_NEGATIVE_EXPONENT_ZERO mc_dec128_from_string("0E-6176")
111 #define _mcDec128InfCombo _mcDec128Combination(1 << 15 | 1 << 14 | 1 << 13 | 1 << 12)
112 #define _mcDec128QuietNaNCombo _mcDec128Combination(1 << 15 | 1 << 14 | 1 << 13 | 1 << 12 | 1 << 11)
113 
115 #define MC_DEC128_POSITIVE_INFINITY _mcDec128ConstFromParts(0, _mcDec128InfCombo)
117 #define MC_DEC128_NEGATIVE_INFINITY _mcDec128ConstFromParts(0, _mcDec128InfCombo | 1ull << 63)
119 #define MC_DEC128_POSITIVE_NAN _mcDec128ConstFromParts(0, _mcDec128QuietNaNCombo)
121 #define MC_DEC128_NEGATIVE_NAN _mcDec128ConstFromParts(0, _mcDec128QuietNaNCombo | 1ull << 63)
122 
124 static inline BID_UINT128 _mc_to_bid128(mc_dec128 d) {
125  BID_UINT128 r;
126  memcpy(&r, &d, sizeof d);
127  return r;
128 }
129 
131 static inline mc_dec128 _bid128_to_mc(BID_UINT128 d) {
132  mc_dec128 r;
133  memcpy(&r, &d, sizeof d);
134  return r;
135 }
136 
145 static inline mc_dec128 mc_dec128_from_double_ex(double d, mc_dec128_rounding_mode rnd, mc_dec128_flagset *flags) {
146  mc_dec128_flagset zero_flags = {0};
147  return _bid128_to_mc(binary64_to_bid128(d, rnd, flags ? &flags->bits : &zero_flags.bits));
148 }
149 
154 static inline mc_dec128 mc_dec128_from_double(double d) {
155  return mc_dec128_from_double_ex(d, MC_DEC128_ROUND_DEFAULT, NULL);
156 }
157 
166 static inline mc_dec128 mc_dec128_from_string_ex(const char *s, mc_dec128_rounding_mode rnd, mc_dec128_flagset *flags) {
167  mc_dec128_flagset zero_flags = {0};
168  return _bid128_to_mc(bid128_from_string((char *)s, rnd, flags ? &flags->bits : &zero_flags.bits));
169 }
170 
175 static inline mc_dec128 mc_dec128_from_string(const char *s) {
176  return mc_dec128_from_string_ex(s, MC_DEC128_ROUND_DEFAULT, NULL);
177 }
178 
183 typedef struct mc_dec128_string {
185  char str[48];
186 } mc_dec128_string;
187 
194 static inline mc_dec128_string mc_dec128_to_string_ex(mc_dec128 d, mc_dec128_flagset *flags) {
195  mc_dec128_flagset zero_flags = {0};
196  mc_dec128_string out = {{0}};
197  bid128_to_string(out.str, _mc_to_bid128(d), flags ? &flags->bits : &zero_flags.bits);
198  return out;
199 }
200 
204 static inline mc_dec128_string mc_dec128_to_string(mc_dec128 d) {
205  return mc_dec128_to_string_ex(d, NULL);
206 }
207 
209 #define DECL_IDF_COMPARE_1(Oper) \
210  static inline bool mc_dec128_##Oper##_ex(mc_dec128 left, mc_dec128 right, mc_dec128_flagset *flags) { \
211  mc_dec128_flagset zero_flags = {0}; \
212  return 0 \
213  != bid128_quiet_##Oper(_mc_to_bid128(left), \
214  _mc_to_bid128(right), \
215  flags ? &flags->bits : &zero_flags.bits); \
216  } \
217  \
218  static inline bool mc_dec128_##Oper(mc_dec128 left, mc_dec128 right) { \
219  return mc_dec128_##Oper##_ex(left, right, NULL); \
220  }
221 
222 #define DECL_IDF_COMPARE(Op) DECL_IDF_COMPARE_1(Op)
223 
224 DECL_IDF_COMPARE(equal)
225 DECL_IDF_COMPARE(not_equal)
226 DECL_IDF_COMPARE(greater)
227 DECL_IDF_COMPARE(greater_equal)
228 DECL_IDF_COMPARE(less)
229 DECL_IDF_COMPARE(less_equal)
230 
231 #undef DECL_IDF_COMPARE
232 #undef DECL_IDF_COMPARE_1
233 
235 #define DECL_PREDICATE(Name, BIDName) \
236  static inline bool mc_dec128_##Name(mc_dec128 d) { return 0 != bid128_##BIDName(_mc_to_bid128(d)); }
237 
238 DECL_PREDICATE(is_zero, isZero)
239 DECL_PREDICATE(is_negative, isSigned)
240 DECL_PREDICATE(is_inf, isInf)
241 DECL_PREDICATE(is_finite, isFinite)
242 DECL_PREDICATE(is_nan, isNaN)
243 
244 #undef DECL_PREDICATE
245 
247 #define DECL_IDF_BINOP_WRAPPER(Oper) \
248  static inline mc_dec128 mc_dec128_##Oper##_ex(mc_dec128 left, \
249  mc_dec128 right, \
250  mc_dec128_rounding_mode mode, \
251  mc_dec128_flagset *flags) { \
252  mc_dec128_flagset zero_flags = {0}; \
253  return _bid128_to_mc( \
254  bid128_##Oper(_mc_to_bid128(left), _mc_to_bid128(right), mode, flags ? &flags->bits : &zero_flags.bits)); \
255  } \
256  \
257  static inline mc_dec128 mc_dec128_##Oper(mc_dec128 left, mc_dec128 right) { \
258  return mc_dec128_##Oper##_ex(left, right, MC_DEC128_ROUND_DEFAULT, NULL); \
259  }
260 
261 DECL_IDF_BINOP_WRAPPER(add)
262 DECL_IDF_BINOP_WRAPPER(mul)
263 DECL_IDF_BINOP_WRAPPER(div)
264 DECL_IDF_BINOP_WRAPPER(sub)
265 DECL_IDF_BINOP_WRAPPER(pow)
266 
267 #undef DECL_IDF_BINOP_WRAPPER
268 
270 #define DECL_IDF_UNOP_WRAPPER(Oper) \
271  static inline mc_dec128 mc_dec128_##Oper##_ex(mc_dec128 operand, mc_dec128_flagset *flags) { \
272  mc_dec128_flagset zero_flags = {0}; \
273  return _bid128_to_mc( \
274  bid128_##Oper(_mc_to_bid128(operand), MC_DEC128_ROUND_DEFAULT, flags ? &flags->bits : &zero_flags.bits)); \
275  } \
276  \
277  static inline mc_dec128 mc_dec128_##Oper(mc_dec128 operand) { return mc_dec128_##Oper##_ex(operand, NULL); }
278 
279 DECL_IDF_UNOP_WRAPPER(log2)
280 DECL_IDF_UNOP_WRAPPER(log10)
281 #undef DECL_IDF_UNOP_WRAPPER
282 
283 static inline mc_dec128
284 mc_dec128_round_integral_ex(mc_dec128 value, mc_dec128_rounding_mode direction, mc_dec128_flagset *flags) {
285  BID_UINT128 bid = _mc_to_bid128(value);
286  mc_dec128_flagset zero_flags = {0};
287  _IDEC_flags *fl = flags ? &flags->bits : &zero_flags.bits;
288  switch (direction) {
289  case MC_DEC128_ROUND_TOWARD_ZERO: return _bid128_to_mc(bid128_round_integral_zero(bid, fl));
290  case MC_DEC128_ROUND_NEAREST_AWAY: return _bid128_to_mc(bid128_round_integral_nearest_away(bid, fl));
291  case MC_DEC128_ROUND_NEAREST_EVEN: return _bid128_to_mc(bid128_round_integral_nearest_even(bid, fl));
292  case MC_DEC128_ROUND_DOWNWARD: return _bid128_to_mc(bid128_round_integral_negative(bid, fl));
293  case MC_DEC128_ROUND_UPWARD: return _bid128_to_mc(bid128_round_integral_positive(bid, fl));
294  default: abort();
295  }
296 }
297 
298 static inline mc_dec128 mc_dec128_negate(mc_dec128 operand) {
299  return _bid128_to_mc(bid128_negate(_mc_to_bid128(operand)));
300 }
301 
302 static inline mc_dec128 mc_dec128_abs(mc_dec128 operand) {
303  return _bid128_to_mc(bid128_abs(_mc_to_bid128(operand)));
304 }
305 
315 static inline mc_dec128
316 mc_dec128_scale_ex(mc_dec128 fac, long int exp, mc_dec128_rounding_mode rounding, mc_dec128_flagset *flags) {
317  mc_dec128_flagset zero_flags = {0};
318  return _bid128_to_mc(bid128_scalbln(_mc_to_bid128(fac), exp, rounding, flags ? &flags->bits : &zero_flags.bits));
319 }
320 
328 static inline mc_dec128 mc_dec128_scale(mc_dec128 fac, long int exp) {
329  return mc_dec128_scale_ex(fac, exp, MC_DEC128_ROUND_DEFAULT, NULL);
330 }
331 
333 typedef struct mc_dec128_modf_result {
335  mc_dec128 whole;
337  mc_dec128 frac;
338 } mc_dec128_modf_result;
339 
349 static inline mc_dec128_modf_result mc_dec128_modf_ex(mc_dec128 d, mc_dec128_flagset *flags) {
350  mc_dec128_flagset zero_flags = {0};
351  mc_dec128_modf_result res;
352  BID_UINT128 whole;
353  res.frac = _bid128_to_mc(bid128_modf(_mc_to_bid128(d), &whole, flags ? &flags->bits : &zero_flags.bits));
354  res.whole = _bid128_to_mc(whole);
355  return res;
356 }
357 
366 static inline mc_dec128_modf_result mc_dec128_modf(mc_dec128 d) {
367  return mc_dec128_modf_ex(d, NULL);
368 }
369 
378 static inline mc_dec128 mc_dec128_fmod_ex(mc_dec128 numer, mc_dec128 denom, mc_dec128_flagset *flags) {
379  mc_dec128_flagset zero_flags = {0};
380  return _bid128_to_mc(
381  bid128_fmod(_mc_to_bid128(numer), _mc_to_bid128(denom), flags ? &flags->bits : &zero_flags.bits));
382 }
383 
391 static inline mc_dec128 mc_dec128_fmod(mc_dec128 numer, mc_dec128 denom) {
392  return mc_dec128_fmod_ex(numer, denom, NULL);
393 }
394 
402 static inline int64_t mc_dec128_to_int64_ex(mc_dec128 d, mc_dec128_flagset *flags) {
403  mc_dec128_flagset zero_flags = {0};
404  return bid128_to_int64_int(_mc_to_bid128(d), flags ? &flags->bits : &zero_flags.bits);
405 }
406 
413 static inline int64_t mc_dec128_to_int64(mc_dec128 d) {
414  return mc_dec128_to_int64_ex(d, NULL);
415 }
416 
418 enum {
420  MC_DEC128_COMBO_NONCANONICAL = 3 << 15,
422  MC_DEC128_COMBO_INFINITY = 0x1e << 12,
424  MC_DEC128_MAX_BIASED_EXPONENT = 6143 + 6144,
426  MC_DEC128_EXPONENT_BIAS = 6143 + 33, // +33 to include the 34 decimal digits
428  MC_DEC_MIN_EXPONENT = -6143,
430  MC_DEC_MAX_EXPONENT = 6144,
431 };
432 
434 static inline uint32_t mc_dec128_combination(mc_dec128 d) {
435  // Grab the high 64 bits:
436  uint64_t hi = d._words[MLIB_IS_LITTLE_ENDIAN ? 1 : 0];
437  // Sign is the 64th bit:
438  int signpos = 64 - 1;
439  // Combo is the next 16 bits:
440  int fieldpos = signpos - 17;
441  int fieldmask = (1 << 17) - 1;
442  return (uint32_t)((hi >> fieldpos) & (uint32_t)fieldmask);
443 }
444 
448 static inline uint64_t mc_dec128_coeff_high(mc_dec128 d) {
449  uint64_t hi_field_mask = (1ull << 49) - 1;
450  uint32_t combo = mc_dec128_combination(d);
451  if (combo < MC_DEC128_COMBO_NONCANONICAL) {
452  uint64_t hi = d._words[MLIB_IS_LITTLE_ENDIAN ? 1 : 0];
453  return hi & hi_field_mask;
454  } else {
455  return 0;
456  }
457 }
458 
462 static inline uint64_t mc_dec128_coeff_low(mc_dec128 d) {
463  uint32_t combo = mc_dec128_combination(d);
464  if (combo < MC_DEC128_COMBO_NONCANONICAL) {
465  uint64_t lo = d._words[MLIB_IS_LITTLE_ENDIAN ? 0 : 1];
466  return lo;
467  } else {
468  return 0;
469  }
470 }
471 
476 static inline mlib_int128 mc_dec128_coeff(mc_dec128 d) {
477  // Hi bits
478  uint64_t hi = mc_dec128_coeff_high(d);
479  // Lo bits
480  uint64_t lo = mc_dec128_coeff_low(d);
481  // Shift and add
482  mlib_int128 hi_128 = mlib_int128_lshift(MLIB_INT128_CAST(hi), 64);
483  return mlib_int128_add(hi_128, MLIB_INT128_CAST(lo));
484 }
485 
494 static inline uint32_t mc_dec128_get_biased_exp(mc_dec128 d) {
495  uint32_t combo = mc_dec128_combination(d);
496  if (combo < MC_DEC128_COMBO_NONCANONICAL) {
497  return combo >> 3;
498  }
499  if (combo >= MC_DEC128_COMBO_INFINITY) {
500  return MC_DEC128_MAX_BIASED_EXPONENT + 1;
501  } else {
502  return (combo >> 1) & ((1 << 14) - 1);
503  }
504 }
505 
507 static inline char *mc_dec128_to_new_decimal_string(mc_dec128 d) {
508  if (mc_dec128_is_zero(d)) {
509  // Just return "0"
510  char *s = (char *)calloc(2, 1);
511  if (s) {
512  s[0] = '0';
513  }
514  return s;
515  }
516 
517  if (mc_dec128_is_negative(d)) {
518  // Negate the result, return a string with a '-' prefix
519  d = mc_dec128_negate(d);
520  char *s = mc_dec128_to_new_decimal_string(d);
521  if (!s) {
522  return NULL;
523  }
524  char *s1 = (char *)calloc(strlen(s) + 2, 1);
525  if (s1) {
526  s1[0] = '-';
527  strcpy(s1 + 1, s);
528  }
529  free(s);
530  return s1;
531  }
532 
533  if (mc_dec128_is_inf(d) || mc_dec128_is_nan(d)) {
534  const char *r = mc_dec128_is_inf(d) ? "Infinity" : "NaN";
535  char *c = (char *)calloc(strlen(r) + 1, 1);
536  if (c) {
537  strcpy(c, r);
538  }
539  return c;
540  }
541 
542  const char DIGITS[] = "0123456789";
543  const mc_dec128 TEN = MC_DEC128_C(10);
544 
545  // Format the whole and fractional part separately.
546  mc_dec128_modf_result modf = mc_dec128_modf(d);
547 
548  if (mc_dec128_is_zero(modf.frac)) {
549  // This is a non-zero integer
550  // Allocate enough digits:
551  mc_dec128 log10 = mc_dec128_modf(mc_dec128_log10(d)).whole;
552  int64_t ndigits = mc_dec128_to_int64(log10) + 1;
553  // +1 for null
554  char *strbuf = (char *)calloc((size_t)(ndigits + 1), 1);
555  if (strbuf) {
556  // Write the string backwards:
557  char *optr = strbuf + ndigits - 1;
558  while (!mc_dec128_is_zero(modf.whole)) {
559  mc_dec128 rem = mc_dec128_fmod(modf.whole, TEN);
560  int64_t remi = mc_dec128_to_int64(rem);
561  *optr-- = DIGITS[remi];
562  // Divide ten
563  modf = mc_dec128_modf(mc_dec128_div(modf.whole, TEN));
564  }
565  }
566  return strbuf;
567  } else if (mc_dec128_is_zero(modf.whole)) {
568  // This is only a fraction (less than one, but more than zero)
569  while (!mc_dec128_is_zero(mc_dec128_modf(d).frac)) {
570  d = mc_dec128_mul(d, TEN);
571  }
572  // 'd' is now a whole number
573  char *part = mc_dec128_to_new_decimal_string(d);
574  if (!part) {
575  return NULL;
576  }
577  char *buf = (char *)calloc(strlen(part) + 3, 1);
578  if (buf) {
579  buf[0] = '0';
580  buf[1] = '.';
581  strcpy(buf + 2, part);
582  }
583  free(part);
584  return buf;
585  } else {
586  // We have both a whole part and a fractional part
587  char *whole = mc_dec128_to_new_decimal_string(modf.whole);
588  if (!whole) {
589  return NULL;
590  }
591  char *frac = mc_dec128_to_new_decimal_string(modf.frac);
592  if (!frac) {
593  free(whole);
594  return NULL;
595  }
596  char *ret = (char *)calloc(strlen(whole) + strlen(frac) + 1, 1);
597  if (ret) {
598  char *out = ret;
599  strcpy(out, whole);
600  out += strlen(whole);
601  // "frac" contains a leading zero, which we don't want
602  strcpy(out, frac + 1);
603  }
604  free(whole);
605  free(frac);
606  return ret;
607  }
608 }
609 
610 static inline mc_dec128 mc_dec128_from_bson_iter(const bson_iter_t *it) {
611  bson_decimal128_t b;
612  if (!bson_iter_decimal128(it, &b)) {
613  mc_dec128 nan = MC_DEC128_POSITIVE_NAN;
614  return nan;
615  }
616  mc_dec128 ret;
617  memcpy(&ret, &b, sizeof b);
618  return ret;
619 }
620 
621 static inline bson_decimal128_t mc_dec128_to_bson_decimal128(mc_dec128 v) {
622  bson_decimal128_t ret;
623  memcpy(&ret, &v, sizeof ret);
624  return ret;
625 }
626 
627 MLIB_C_LINKAGE_END
628 
629 #endif
630 
631 #endif // MC_DEC128_H_INCLUDED