1169689Skan/* This is a software decimal floating point library. 2169689Skan Copyright (C) 2005, 2006 Free Software Foundation, Inc. 3169689Skan 4169689SkanThis file is part of GCC. 5169689Skan 6169689SkanGCC is free software; you can redistribute it and/or modify it under 7169689Skanthe terms of the GNU General Public License as published by the Free 8169689SkanSoftware Foundation; either version 2, or (at your option) any later 9169689Skanversion. 10169689Skan 11169689SkanIn addition to the permissions in the GNU General Public License, the 12169689SkanFree Software Foundation gives you unlimited permission to link the 13169689Skancompiled version of this file into combinations with other programs, 14169689Skanand to distribute those combinations without any restriction coming 15169689Skanfrom the use of this file. (The General Public License restrictions 16169689Skando apply in other respects; for example, they cover modification of 17169689Skanthe file, and distribution when not linked into a combine 18169689Skanexecutable.) 19169689Skan 20169689SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY 21169689SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or 22169689SkanFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 23169689Skanfor more details. 24169689Skan 25169689SkanYou should have received a copy of the GNU General Public License 26169689Skanalong with GCC; see the file COPYING. If not, write to the Free 27169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 28169689Skan02110-1301, USA. */ 29169689Skan 30169689Skan/* This implements IEEE 754R decimal floating point arithmetic, but 31169689Skan does not provide a mechanism for setting the rounding mode, or for 32169689Skan generating or handling exceptions. Conversions between decimal 33169689Skan floating point types and other types depend on C library functions. 34169689Skan 35169689Skan Contributed by Ben Elliston <bje@au.ibm.com>. */ 36169689Skan 37169689Skan/* The intended way to use this file is to make two copies, add `#define ' 38169689Skan to one copy, then compile both copies and add them to libgcc.a. */ 39169689Skan 40169689Skan#include <stdio.h> 41169689Skan#include <stdlib.h> 42169689Skan#include <string.h> 43169689Skan#include <limits.h> 44169689Skan 45169689Skan#include "config/dfp-bit.h" 46169689Skan 47169689Skan/* Forward declarations. */ 48169689Skan#if WIDTH == 32 || WIDTH_TO == 32 49169689Skanvoid __host_to_ieee_32 (_Decimal32 in, decimal32 *out); 50169689Skanvoid __ieee_to_host_32 (decimal32 in, _Decimal32 *out); 51169689Skan#endif 52169689Skan#if WIDTH == 64 || WIDTH_TO == 64 53169689Skanvoid __host_to_ieee_64 (_Decimal64 in, decimal64 *out); 54169689Skanvoid __ieee_to_host_64 (decimal64 in, _Decimal64 *out); 55169689Skan#endif 56169689Skan#if WIDTH == 128 || WIDTH_TO == 128 57169689Skanvoid __host_to_ieee_128 (_Decimal128 in, decimal128 *out); 58169689Skanvoid __ieee_to_host_128 (decimal128 in, _Decimal128 *out); 59169689Skan#endif 60169689Skan 61169689Skan/* A pointer to a unary decNumber operation. */ 62169689Skantypedef decNumber* (*dfp_unary_func) 63169689Skan (decNumber *, decNumber *, decContext *); 64169689Skan 65169689Skan/* A pointer to a binary decNumber operation. */ 66169689Skantypedef decNumber* (*dfp_binary_func) 67169689Skan (decNumber *, decNumber *, decNumber *, decContext *); 68169689Skan 69169689Skanextern unsigned long __dec_byte_swap (unsigned long); 70169689Skan 71169689Skan/* Unary operations. */ 72169689Skan 73169689Skanstatic inline DFP_C_TYPE 74169689Skandfp_unary_op (dfp_unary_func op, DFP_C_TYPE arg) 75169689Skan{ 76169689Skan DFP_C_TYPE result; 77169689Skan decContext context; 78169689Skan decNumber arg1, res; 79169689Skan IEEE_TYPE a, encoded_result; 80169689Skan 81169689Skan HOST_TO_IEEE (arg, &a); 82169689Skan 83169689Skan decContextDefault (&context, CONTEXT_INIT); 84169689Skan context.round = CONTEXT_ROUND; 85169689Skan 86169689Skan TO_INTERNAL (&a, &arg1); 87169689Skan 88169689Skan /* Perform the operation. */ 89169689Skan op (&res, &arg1, &context); 90169689Skan 91169689Skan if (CONTEXT_TRAPS && CONTEXT_ERRORS (context)) 92169689Skan DFP_RAISE (0); 93169689Skan 94169689Skan TO_ENCODED (&encoded_result, &res, &context); 95169689Skan IEEE_TO_HOST (encoded_result, &result); 96169689Skan return result; 97169689Skan} 98169689Skan 99169689Skan/* Binary operations. */ 100169689Skan 101169689Skanstatic inline DFP_C_TYPE 102169689Skandfp_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) 103169689Skan{ 104169689Skan DFP_C_TYPE result; 105169689Skan decContext context; 106169689Skan decNumber arg1, arg2, res; 107169689Skan IEEE_TYPE a, b, encoded_result; 108169689Skan 109169689Skan HOST_TO_IEEE (arg_a, &a); 110169689Skan HOST_TO_IEEE (arg_b, &b); 111169689Skan 112169689Skan decContextDefault (&context, CONTEXT_INIT); 113169689Skan context.round = CONTEXT_ROUND; 114169689Skan 115169689Skan TO_INTERNAL (&a, &arg1); 116169689Skan TO_INTERNAL (&b, &arg2); 117169689Skan 118169689Skan /* Perform the operation. */ 119169689Skan op (&res, &arg1, &arg2, &context); 120169689Skan 121169689Skan if (CONTEXT_TRAPS && CONTEXT_ERRORS (context)) 122169689Skan DFP_RAISE (0); 123169689Skan 124169689Skan TO_ENCODED (&encoded_result, &res, &context); 125169689Skan IEEE_TO_HOST (encoded_result, &result); 126169689Skan return result; 127169689Skan} 128169689Skan 129169689Skan/* Comparison operations. */ 130169689Skan 131169689Skanstatic inline int 132169689Skandfp_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) 133169689Skan{ 134169689Skan IEEE_TYPE a, b; 135169689Skan decContext context; 136169689Skan decNumber arg1, arg2, res; 137169689Skan int result; 138169689Skan 139169689Skan HOST_TO_IEEE (arg_a, &a); 140169689Skan HOST_TO_IEEE (arg_b, &b); 141169689Skan 142169689Skan decContextDefault (&context, CONTEXT_INIT); 143169689Skan context.round = CONTEXT_ROUND; 144169689Skan 145169689Skan TO_INTERNAL (&a, &arg1); 146169689Skan TO_INTERNAL (&b, &arg2); 147169689Skan 148169689Skan /* Perform the comparison. */ 149169689Skan op (&res, &arg1, &arg2, &context); 150169689Skan 151169689Skan if (CONTEXT_TRAPS && CONTEXT_ERRORS (context)) 152169689Skan DFP_RAISE (0); 153169689Skan 154169689Skan if (decNumberIsNegative (&res)) 155169689Skan result = -1; 156169689Skan else if (decNumberIsZero (&res)) 157169689Skan result = 0; 158169689Skan else 159169689Skan result = 1; 160169689Skan 161169689Skan return result; 162169689Skan} 163169689Skan 164169689Skan 165169689Skan#if defined(L_conv_sd) 166169689Skanvoid 167169689Skan__host_to_ieee_32 (_Decimal32 in, decimal32 *out) 168169689Skan{ 169169689Skan uint32_t t; 170169689Skan 171169689Skan if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN) 172169689Skan { 173169689Skan memcpy (&t, &in, 4); 174169689Skan t = __dec_byte_swap (t); 175169689Skan memcpy (out, &t, 4); 176169689Skan } 177169689Skan else 178169689Skan memcpy (out, &in, 4); 179169689Skan} 180169689Skan 181169689Skanvoid 182169689Skan__ieee_to_host_32 (decimal32 in, _Decimal32 *out) 183169689Skan{ 184169689Skan uint32_t t; 185169689Skan 186169689Skan if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN) 187169689Skan { 188169689Skan memcpy (&t, &in, 4); 189169689Skan t = __dec_byte_swap (t); 190169689Skan memcpy (out, &t, 4); 191169689Skan } 192169689Skan else 193169689Skan memcpy (out, &in, 4); 194169689Skan} 195169689Skan#endif /* L_conv_sd */ 196169689Skan 197169689Skan#if defined(L_conv_dd) 198169689Skanstatic void 199169689Skan__swap64 (char *src, char *dst) 200169689Skan{ 201169689Skan uint32_t t1, t2; 202169689Skan 203169689Skan if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN) 204169689Skan { 205169689Skan memcpy (&t1, src, 4); 206169689Skan memcpy (&t2, src + 4, 4); 207169689Skan t1 = __dec_byte_swap (t1); 208169689Skan t2 = __dec_byte_swap (t2); 209169689Skan memcpy (dst, &t2, 4); 210169689Skan memcpy (dst + 4, &t1, 4); 211169689Skan } 212169689Skan else 213169689Skan memcpy (dst, src, 8); 214169689Skan} 215169689Skan 216169689Skanvoid 217169689Skan__host_to_ieee_64 (_Decimal64 in, decimal64 *out) 218169689Skan{ 219169689Skan __swap64 ((char *) &in, (char *) out); 220169689Skan} 221169689Skan 222169689Skanvoid 223169689Skan__ieee_to_host_64 (decimal64 in, _Decimal64 *out) 224169689Skan{ 225169689Skan __swap64 ((char *) &in, (char *) out); 226169689Skan} 227169689Skan#endif /* L_conv_dd */ 228169689Skan 229169689Skan#if defined(L_conv_td) 230169689Skanstatic void 231169689Skan__swap128 (char *src, char *dst) 232169689Skan{ 233169689Skan uint32_t t1, t2, t3, t4; 234169689Skan 235169689Skan if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN) 236169689Skan { 237169689Skan memcpy (&t1, src, 4); 238169689Skan memcpy (&t2, src + 4, 4); 239169689Skan memcpy (&t3, src + 8, 4); 240169689Skan memcpy (&t4, src + 12, 4); 241169689Skan t1 = __dec_byte_swap (t1); 242169689Skan t2 = __dec_byte_swap (t2); 243169689Skan t3 = __dec_byte_swap (t3); 244169689Skan t4 = __dec_byte_swap (t4); 245169689Skan memcpy (dst, &t4, 4); 246169689Skan memcpy (dst + 4, &t3, 4); 247169689Skan memcpy (dst + 8, &t2, 4); 248169689Skan memcpy (dst + 12, &t1, 4); 249169689Skan } 250169689Skan else 251169689Skan memcpy (dst, src, 16); 252169689Skan} 253169689Skan 254169689Skanvoid 255169689Skan__host_to_ieee_128 (_Decimal128 in, decimal128 *out) 256169689Skan{ 257169689Skan __swap128 ((char *) &in, (char *) out); 258169689Skan} 259169689Skan 260169689Skanvoid 261169689Skan__ieee_to_host_128 (decimal128 in, _Decimal128 *out) 262169689Skan{ 263169689Skan __swap128 ((char *) &in, (char *) out); 264169689Skan} 265169689Skan#endif /* L_conv_td */ 266169689Skan 267169689Skan#if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td) 268169689SkanDFP_C_TYPE 269169689SkanDFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) 270169689Skan{ 271169689Skan return dfp_binary_op (decNumberAdd, arg_a, arg_b); 272169689Skan} 273169689Skan 274169689SkanDFP_C_TYPE 275169689SkanDFP_SUB (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) 276169689Skan{ 277169689Skan return dfp_binary_op (decNumberSubtract, arg_a, arg_b); 278169689Skan} 279169689Skan#endif /* L_addsub */ 280169689Skan 281169689Skan#if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td) 282169689SkanDFP_C_TYPE 283169689SkanDFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) 284169689Skan{ 285169689Skan return dfp_binary_op (decNumberMultiply, arg_a, arg_b); 286169689Skan} 287169689Skan#endif /* L_mul */ 288169689Skan 289169689Skan#if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td) 290169689SkanDFP_C_TYPE 291169689SkanDFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) 292169689Skan{ 293169689Skan return dfp_binary_op (decNumberDivide, arg_a, arg_b); 294169689Skan} 295169689Skan#endif /* L_div */ 296169689Skan 297169689Skan#if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td) 298169689SkanCMPtype 299169689SkanDFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) 300169689Skan{ 301169689Skan int stat; 302169689Skan stat = dfp_compare_op (decNumberCompare, arg_a, arg_b); 303169689Skan /* For EQ return zero for true, nonzero for false. */ 304169689Skan return stat != 0; 305169689Skan} 306169689Skan#endif /* L_eq */ 307169689Skan 308169689Skan#if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td) 309169689SkanCMPtype 310169689SkanDFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) 311169689Skan{ 312169689Skan int stat; 313169689Skan stat = dfp_compare_op (decNumberCompare, arg_a, arg_b); 314169689Skan /* For NE return nonzero for true, zero for false. */ 315169689Skan return stat != 0; 316169689Skan} 317169689Skan#endif /* L_ne */ 318169689Skan 319169689Skan#if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td) 320169689SkanCMPtype 321169689SkanDFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) 322169689Skan{ 323169689Skan int stat; 324169689Skan stat = dfp_compare_op (decNumberCompare, arg_a, arg_b); 325169689Skan /* For LT return -1 (<0) for true, 1 for false. */ 326169689Skan return (stat == -1) ? -1 : 1; 327169689Skan} 328169689Skan#endif /* L_lt */ 329169689Skan 330169689Skan#if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td) 331169689SkanCMPtype 332169689SkanDFP_GT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) 333169689Skan{ 334169689Skan int stat; 335169689Skan stat = dfp_compare_op (decNumberCompare, arg_a, arg_b); 336169689Skan /* For GT return 1 (>0) for true, -1 for false. */ 337169689Skan return (stat == 1) ? 1 : -1; 338169689Skan} 339169689Skan#endif 340169689Skan 341169689Skan#if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td) 342169689SkanCMPtype 343169689SkanDFP_LE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) 344169689Skan{ 345169689Skan int stat; 346169689Skan stat = dfp_compare_op (decNumberCompare, arg_a, arg_b); 347169689Skan /* For LE return 0 (<= 0) for true, 1 for false. */ 348169689Skan return stat == 1; 349169689Skan} 350169689Skan#endif /* L_le */ 351169689Skan 352169689Skan#if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td) 353169689SkanCMPtype 354169689SkanDFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) 355169689Skan{ 356169689Skan int stat; 357169689Skan stat = dfp_compare_op (decNumberCompare, arg_a, arg_b); 358169689Skan /* For GE return 1 (>=0) for true, -1 for false. */ 359169689Skan return (stat != -1) ? 1 : -1; 360169689Skan} 361169689Skan#endif /* L_ge */ 362169689Skan 363169689Skan#define BUFMAX 128 364169689Skan 365169689Skan#if defined (L_sd_to_dd) || defined (L_sd_to_td) || defined (L_dd_to_sd) \ 366169689Skan || defined (L_dd_to_td) || defined (L_td_to_sd) || defined (L_td_to_dd) 367169689SkanDFP_C_TYPE_TO 368169689SkanDFP_TO_DFP (DFP_C_TYPE f_from) 369169689Skan{ 370169689Skan DFP_C_TYPE_TO f_to; 371169689Skan IEEE_TYPE s_from; 372169689Skan IEEE_TYPE_TO s_to; 373169689Skan decNumber d; 374169689Skan decContext context; 375169689Skan 376169689Skan decContextDefault (&context, CONTEXT_INIT); 377169689Skan context.round = CONTEXT_ROUND; 378169689Skan 379169689Skan HOST_TO_IEEE (f_from, &s_from); 380169689Skan TO_INTERNAL (&s_from, &d); 381169689Skan TO_ENCODED_TO (&s_to, &d, &context); 382169689Skan if (CONTEXT_TRAPS && (context.status & DEC_Inexact) != 0) 383169689Skan DFP_RAISE (DEC_Inexact); 384169689Skan 385169689Skan IEEE_TO_HOST_TO (s_to, &f_to); 386169689Skan return f_to; 387169689Skan} 388169689Skan#endif 389169689Skan 390169689Skan#if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si) \ 391169689Skan || defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) \ 392169689Skan || defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi) \ 393169689Skan || defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi) 394169689SkanINT_TYPE 395169689SkanDFP_TO_INT (DFP_C_TYPE x) 396169689Skan{ 397169689Skan /* decNumber's decimal* types have the same format as C's _Decimal* 398169689Skan types, but they have different calling conventions. */ 399169689Skan 400169689Skan IEEE_TYPE s; 401169689Skan char buf[BUFMAX]; 402169689Skan char *pos; 403169689Skan decNumber qval, n1, n2; 404169689Skan decContext context; 405169689Skan 406169689Skan decContextDefault (&context, CONTEXT_INIT); 407169689Skan /* Need non-default rounding mode here. */ 408169689Skan context.round = DEC_ROUND_DOWN; 409169689Skan 410169689Skan HOST_TO_IEEE (x, &s); 411169689Skan TO_INTERNAL (&s, &n1); 412169689Skan /* Rescale if the exponent is less than zero. */ 413169689Skan decNumberToIntegralValue (&n2, &n1, &context); 414169689Skan /* Get a value to use for the quantize call. */ 415169689Skan decNumberFromString (&qval, (char *) "1.0", &context); 416169689Skan /* Force the exponent to zero. */ 417169689Skan decNumberQuantize (&n1, &n2, &qval, &context); 418169689Skan /* This is based on text in N1107 section 5.1; it might turn out to be 419169689Skan undefined behavior instead. */ 420169689Skan if (context.status & DEC_Invalid_operation) 421169689Skan { 422169689Skan#if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si) 423169689Skan if (decNumberIsNegative(&n2)) 424169689Skan return INT_MIN; 425169689Skan else 426169689Skan return INT_MAX; 427169689Skan#elif defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) 428169689Skan if (decNumberIsNegative(&n2)) 429169689Skan /* Find a defined constant that will work here. */ 430169689Skan return (-9223372036854775807LL - 1LL); 431169689Skan else 432169689Skan /* Find a defined constant that will work here. */ 433169689Skan return 9223372036854775807LL; 434169689Skan#elif defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi) 435169689Skan return UINT_MAX; 436169689Skan#elif defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi) 437169689Skan /* Find a defined constant that will work here. */ 438169689Skan return 18446744073709551615ULL; 439169689Skan#endif 440169689Skan } 441169689Skan /* Get a string, which at this point will not include an exponent. */ 442169689Skan decNumberToString (&n1, buf); 443169689Skan /* Ignore the fractional part. */ 444169689Skan pos = strchr (buf, '.'); 445169689Skan if (pos) 446169689Skan *pos = 0; 447169689Skan /* Use a C library function to convert to the integral type. */ 448169689Skan return STR_TO_INT (buf, NULL, 10); 449169689Skan} 450169689Skan#endif 451169689Skan 452169689Skan#if defined (L_si_to_sd) || defined (L_si_to_dd) || defined (L_si_to_td) \ 453169689Skan || defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \ 454169689Skan || defined (L_usi_to_sd) || defined (L_usi_to_dd) || defined (L_usi_to_td) \ 455169689Skan || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td) 456169689SkanDFP_C_TYPE 457169689SkanINT_TO_DFP (INT_TYPE i) 458169689Skan{ 459169689Skan DFP_C_TYPE f; 460169689Skan IEEE_TYPE s; 461169689Skan char buf[BUFMAX]; 462169689Skan decContext context; 463169689Skan 464169689Skan decContextDefault (&context, CONTEXT_INIT); 465169689Skan context.round = CONTEXT_ROUND; 466169689Skan 467169689Skan /* Use a C library function to get a floating point string. */ 468169689Skan sprintf (buf, INT_FMT ".0", CAST_FOR_FMT(i)); 469169689Skan /* Convert from the floating point string to a decimal* type. */ 470169689Skan FROM_STRING (&s, buf, &context); 471169689Skan IEEE_TO_HOST (s, &f); 472169689Skan if (CONTEXT_TRAPS && (context.status & DEC_Inexact) != 0) 473169689Skan DFP_RAISE (DEC_Inexact); 474169689Skan return f; 475169689Skan} 476169689Skan#endif 477169689Skan 478169689Skan#if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \ 479169689Skan || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \ 480169689Skan || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \ 481169689Skan && LIBGCC2_HAS_XF_MODE) 482169689SkanBFP_TYPE 483169689SkanDFP_TO_BFP (DFP_C_TYPE f) 484169689Skan{ 485169689Skan IEEE_TYPE s; 486169689Skan char buf[BUFMAX]; 487169689Skan 488169689Skan HOST_TO_IEEE (f, &s); 489169689Skan /* Write the value to a string. */ 490169689Skan TO_STRING (&s, buf); 491169689Skan /* Read it as the binary floating point type and return that. */ 492169689Skan return STR_TO_BFP (buf, NULL); 493169689Skan} 494169689Skan#endif 495169689Skan 496169689Skan#if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \ 497169689Skan || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \ 498169689Skan || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \ 499169689Skan && LIBGCC2_HAS_XF_MODE) 500169689SkanDFP_C_TYPE 501169689SkanBFP_TO_DFP (BFP_TYPE x) 502169689Skan{ 503169689Skan DFP_C_TYPE f; 504169689Skan IEEE_TYPE s; 505169689Skan char buf[BUFMAX]; 506169689Skan decContext context; 507169689Skan 508169689Skan decContextDefault (&context, CONTEXT_INIT); 509169689Skan context.round = CONTEXT_ROUND; 510169689Skan 511169689Skan /* Use a C library function to write the floating point value to a string. */ 512169689Skan#ifdef BFP_VIA_TYPE 513169689Skan /* FIXME: Is there a better way to output an XFmode variable in C? */ 514169689Skan sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x); 515169689Skan#else 516169689Skan sprintf (buf, BFP_FMT, x); 517169689Skan#endif 518169689Skan 519169689Skan /* Convert from the floating point string to a decimal* type. */ 520169689Skan FROM_STRING (&s, buf, &context); 521169689Skan IEEE_TO_HOST (s, &f); 522169689Skan if (CONTEXT_TRAPS && (context.status & DEC_Inexact) != 0) 523169689Skan DFP_RAISE (DEC_Inexact); 524169689Skan return f; 525169689Skan} 526169689Skan#endif 527169689Skan 528169689Skan#if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td) 529169689SkanCMPtype 530169689SkanDFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) 531169689Skan{ 532169689Skan decNumber arg1, arg2; 533169689Skan IEEE_TYPE a, b; 534169689Skan 535169689Skan HOST_TO_IEEE (arg_a, &a); 536169689Skan HOST_TO_IEEE (arg_b, &b); 537169689Skan TO_INTERNAL (&a, &arg1); 538169689Skan TO_INTERNAL (&b, &arg2); 539169689Skan return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2)); 540169689Skan} 541169689Skan#endif /* L_unord_sd || L_unord_dd || L_unord_td */ 542