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); }
/* 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); }
static int_t value_from_string(const char *s) { return strcmp(s,".") ? STR_TO_INT(s,0) : NOT_A_NUMBER; }