static inline int dfp_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) { IEEE_TYPE a, b; decContext context; decNumber arg1, arg2, res; int result; HOST_TO_IEEE (arg_a, &a); HOST_TO_IEEE (arg_b, &b); decContextDefault (&context, CONTEXT_INIT); context.round = CONTEXT_ROUND; TO_INTERNAL (&a, &arg1); TO_INTERNAL (&b, &arg2); /* Perform the comparison. */ op (&res, &arg1, &arg2, &context); if (CONTEXT_TRAPS && CONTEXT_ERRORS (context)) DFP_RAISE (0); if (decNumberIsNegative (&res)) result = -1; else if (decNumberIsZero (&res)) result = 0; else result = 1; return result; }
static inline DFP_C_TYPE dfp_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) { DFP_C_TYPE result; decContext context; decNumber arg1, arg2, res; IEEE_TYPE a, b, encoded_result; HOST_TO_IEEE (arg_a, &a); HOST_TO_IEEE (arg_b, &b); decContextDefault (&context, CONTEXT_INIT); context.round = CONTEXT_ROUND; TO_INTERNAL (&a, &arg1); TO_INTERNAL (&b, &arg2); /* Perform the operation. */ op (&res, &arg1, &arg2, &context); if (CONTEXT_TRAPS && CONTEXT_ERRORS (context)) DFP_RAISE (0); TO_ENCODED (&encoded_result, &res, &context); IEEE_TO_HOST (encoded_result, &result); return result; }
CMPtype DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) { decNumber arg1, arg2; IEEE_TYPE a, b; HOST_TO_IEEE (arg_a, &a); HOST_TO_IEEE (arg_b, &b); TO_INTERNAL (&a, &arg1); TO_INTERNAL (&b, &arg2); return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2)); }
INT_TYPE DFP_TO_INT (DFP_C_TYPE x) { /* decNumber's decimal* types have the same format as C's _Decimal* types, but they have different calling conventions. */ IEEE_TYPE s; char buf[BUFMAX]; char *pos; decNumber qval, n1, n2; decContext context; decContextDefault (&context, CONTEXT_INIT); /* Need non-default rounding mode here. */ context.round = DEC_ROUND_DOWN; HOST_TO_IEEE (x, &s); TO_INTERNAL (&s, &n1); /* Rescale if the exponent is less than zero. */ decNumberToIntegralValue (&n2, &n1, &context); /* Get a value to use for the quantize call. */ decNumberFromString (&qval, (char *) "1.0", &context); /* Force the exponent to zero. */ decNumberQuantize (&n1, &n2, &qval, &context); /* This is based on text in N1107 section 5.1; it might turn out to be undefined behavior instead. */ if (context.status & DEC_Invalid_operation) { #if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si) if (decNumberIsNegative(&n2)) return INT_MIN; else return INT_MAX; #elif defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) if (decNumberIsNegative(&n2)) /* Find a defined constant that will work here. */ return (-9223372036854775807LL - 1LL); else /* Find a defined constant that will work here. */ return 9223372036854775807LL; #elif defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi) return UINT_MAX; #elif defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi) /* Find a defined constant that will work here. */ return 18446744073709551615ULL; #endif } /* Get a string, which at this point will not include an exponent. */ decNumberToString (&n1, buf); /* Ignore the fractional part. */ pos = strchr (buf, '.'); if (pos) *pos = 0; /* Use a C library function to convert to the integral type. */ return STR_TO_INT (buf, NULL, 10); }
DFP_C_TYPE_TO DFP_TO_DFP (DFP_C_TYPE f_from) { DFP_C_TYPE_TO f_to; IEEE_TYPE s_from; IEEE_TYPE_TO s_to; decNumber d; decContext context; decContextDefault (&context, CONTEXT_INIT); context.round = CONTEXT_ROUND; HOST_TO_IEEE (f_from, &s_from); TO_INTERNAL (&s_from, &d); TO_ENCODED_TO (&s_to, &d, &context); if (CONTEXT_TRAPS && (context.status & DEC_Inexact) != 0) DFP_RAISE (DEC_Inexact); IEEE_TO_HOST_TO (s_to, &f_to); return f_to; }
/* decNumber doesn't provide support for conversions to 64-bit integer types, so do it the hard way. */ INT_TYPE DFP_TO_INT (DFP_C_TYPE x) { /* decNumber's decimal* types have the same format as C's _Decimal* types, but they have different calling conventions. */ /* TODO: Decimal float to integer conversions should raise FE_INVALID if the result value does not fit into the result type. */ IEEE_TYPE s; char buf[BUFMAX]; char *pos; decNumber qval, n1, n2; decContext context; /* Use a large context to avoid losing precision. */ decContextDefault (&context, DEC_INIT_DECIMAL128); /* Need non-default rounding mode here. */ context.round = DEC_ROUND_DOWN; HOST_TO_IEEE (x, &s); TO_INTERNAL (&s, &n1); /* Rescale if the exponent is less than zero. */ decNumberToIntegralValue (&n2, &n1, &context); /* Get a value to use for the quantize call. */ decNumberFromString (&qval, (char *) "1.", &context); /* Force the exponent to zero. */ decNumberQuantize (&n1, &n2, &qval, &context); /* Get a string, which at this point will not include an exponent. */ decNumberToString (&n1, buf); /* Ignore the fractional part. */ pos = strchr (buf, '.'); if (pos) *pos = 0; /* Use a C library function to convert to the integral type. */ return STR_TO_INT (buf, NULL, 10); }