(root)/
gcc-13.2.0/
libgcc/
dfp-bit.c
       1  /* This is a software decimal floating point library.
       2     Copyright (C) 2005-2023 Free Software Foundation, Inc.
       3  
       4  This file is part of GCC.
       5  
       6  GCC is free software; you can redistribute it and/or modify it under
       7  the terms of the GNU General Public License as published by the Free
       8  Software Foundation; either version 3, or (at your option) any later
       9  version.
      10  
      11  GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      12  WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14  for more details.
      15  
      16  Under Section 7 of GPL version 3, you are granted additional
      17  permissions described in the GCC Runtime Library Exception, version
      18  3.1, as published by the Free Software Foundation.
      19  
      20  You should have received a copy of the GNU General Public License and
      21  a copy of the GCC Runtime Library Exception along with this program;
      22  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      23  <http://www.gnu.org/licenses/>.  */
      24  
      25  /* This implements IEEE 754 decimal floating point arithmetic, but
      26     does not provide a mechanism for setting the rounding mode, or for
      27     generating or handling exceptions.  Conversions between decimal
      28     floating point types and other types depend on C library functions.
      29  
      30     Contributed by Ben Elliston  <bje@au.ibm.com>.  */
      31  
      32  #include <stdio.h>
      33  #include <stdlib.h>
      34  /* FIXME: compile with -std=gnu99 to get these from stdlib.h */
      35  extern float strtof (const char *, char **);
      36  extern long double strtold (const char *, char **);
      37  #include <string.h>
      38  #include <limits.h>
      39  
      40  #include "dfp-bit.h"
      41  
      42  /* Forward declarations.  */
      43  #if WIDTH == 32 || WIDTH_TO == 32
      44  void __host_to_ieee_32 (_Decimal32 in, decimal32 *out);
      45  void __ieee_to_host_32 (decimal32 in, _Decimal32 *out);
      46  #endif
      47  #if WIDTH == 64 || WIDTH_TO == 64
      48  void __host_to_ieee_64 (_Decimal64 in, decimal64 *out);
      49  void __ieee_to_host_64 (decimal64 in, _Decimal64 *out);
      50  #endif
      51  #if WIDTH == 128 || WIDTH_TO == 128
      52  void __host_to_ieee_128 (_Decimal128 in, decimal128 *out);
      53  void __ieee_to_host_128 (decimal128 in, _Decimal128 *out);
      54  #endif
      55  
      56  /* A pointer to a binary decFloat operation.  */
      57  typedef decFloat* (*dfp_binary_func)
      58       (decFloat *, const decFloat *, const decFloat *, decContext *);
      59  
      60  /* Binary operations.  */
      61  
      62  /* Use a decFloat (decDouble or decQuad) function to perform a DFP
      63     binary operation.  */
      64  static inline decFloat
      65  dfp_binary_op (dfp_binary_func op, decFloat arg_a, decFloat arg_b)
      66  {
      67    decFloat result;
      68    decContext context;
      69  
      70    decContextDefault (&context, CONTEXT_INIT);
      71    DFP_INIT_ROUNDMODE (context.round);
      72  
      73    /* Perform the operation.  */
      74    op (&result, &arg_a, &arg_b, &context);
      75  
      76    if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
      77      {
      78        /* decNumber exception flags we care about here.  */
      79        int ieee_flags;
      80        int dec_flags = DEC_IEEE_854_Division_by_zero | DEC_IEEE_854_Inexact
      81  		      | DEC_IEEE_854_Invalid_operation | DEC_IEEE_854_Overflow
      82  		      | DEC_IEEE_854_Underflow;
      83        dec_flags &= context.status;
      84        ieee_flags = DFP_IEEE_FLAGS (dec_flags);
      85        if (ieee_flags != 0)
      86          DFP_HANDLE_EXCEPTIONS (ieee_flags);
      87      }
      88  
      89    return result;
      90  }
      91  
      92  #if WIDTH == 32
      93  /* The decNumber package doesn't provide arithmetic for decSingle (32 bits);
      94     convert to decDouble, use the operation for that, and convert back.  */
      95  static inline _Decimal32
      96  d32_binary_op (dfp_binary_func op, _Decimal32 arg_a, _Decimal32 arg_b)
      97  {
      98    union { _Decimal32 c; decSingle f; } a32, b32, res32;
      99    decDouble a, b, res;
     100    decContext context;
     101  
     102    /* Widen the operands and perform the operation.  */
     103    a32.c = arg_a;
     104    b32.c = arg_b;
     105    decSingleToWider (&a32.f, &a);
     106    decSingleToWider (&b32.f, &b);
     107    res = dfp_binary_op (op, a, b);
     108  
     109    /* Narrow the result, which might result in an underflow or overflow.  */
     110    decContextDefault (&context, CONTEXT_INIT);
     111    DFP_INIT_ROUNDMODE (context.round);
     112    decSingleFromWider (&res32.f, &res, &context);
     113    if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
     114      {
     115        /* decNumber exception flags we care about here.  */
     116        int ieee_flags;
     117        int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Overflow
     118  		      | DEC_IEEE_854_Underflow;
     119        dec_flags &= context.status;
     120        ieee_flags = DFP_IEEE_FLAGS (dec_flags);
     121        if (ieee_flags != 0)
     122          DFP_HANDLE_EXCEPTIONS (ieee_flags);
     123      }
     124  
     125    return res32.c;
     126  }
     127  #else
     128  /* decFloat operations are supported for decDouble (64 bits) and
     129     decQuad (128 bits).  The bit patterns for the types are the same.  */
     130  static inline DFP_C_TYPE
     131  dnn_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
     132  {
     133    union { DFP_C_TYPE c; decFloat f; } a, b, result;
     134  
     135    a.c = arg_a;
     136    b.c = arg_b;
     137    result.f = dfp_binary_op (op, a.f, b.f);
     138    return result.c;
     139  }
     140  #endif
     141  
     142  /* Comparison operations.  */
     143  
     144  /* Use a decFloat (decDouble or decQuad) function to perform a DFP
     145     comparison.  */
     146  static inline CMPtype
     147  dfp_compare_op (dfp_binary_func op, decFloat arg_a, decFloat arg_b)
     148  {
     149    decContext context;
     150    decFloat res;
     151    int result;
     152  
     153    decContextDefault (&context, CONTEXT_INIT);
     154    DFP_INIT_ROUNDMODE (context.round);
     155  
     156    /* Perform the comparison.  */
     157    op (&res, &arg_a, &arg_b, &context);
     158  
     159    if (DEC_FLOAT_IS_SIGNED (&res))
     160      result = -1;
     161    else if (DEC_FLOAT_IS_ZERO (&res))
     162      result = 0;
     163    else if (DEC_FLOAT_IS_NAN (&res))
     164      result = -2;
     165    else
     166      result = 1;
     167  
     168    return (CMPtype) result;
     169  }
     170  
     171  #if WIDTH == 32
     172  /* The decNumber package doesn't provide comparisons for decSingle (32 bits);
     173     convert to decDouble, use the operation for that, and convert back.  */
     174  static inline CMPtype
     175  d32_compare_op (dfp_binary_func op, _Decimal32 arg_a, _Decimal32 arg_b)
     176  {
     177    union { _Decimal32 c; decSingle f; } a32, b32;
     178    decDouble a, b;
     179  
     180    a32.c = arg_a;
     181    b32.c = arg_b;
     182    decSingleToWider (&a32.f, &a);
     183    decSingleToWider (&b32.f, &b);
     184    return dfp_compare_op (op, a, b);  
     185  }
     186  #else
     187  /* decFloat comparisons are supported for decDouble (64 bits) and
     188     decQuad (128 bits).  The bit patterns for the types are the same.  */
     189  static inline CMPtype
     190  dnn_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
     191  {
     192    union { DFP_C_TYPE c; decFloat f; } a, b;
     193  
     194    a.c = arg_a;
     195    b.c = arg_b;
     196    return dfp_compare_op (op, a.f, b.f);  
     197  }
     198  #endif
     199  
     200  #if defined(L_conv_sd)
     201  void
     202  __host_to_ieee_32 (_Decimal32 in, decimal32 *out)
     203  {
     204    memcpy (out, &in, 4);
     205  }
     206  
     207  void
     208  __ieee_to_host_32 (decimal32 in, _Decimal32 *out)
     209  {
     210    memcpy (out, &in, 4);
     211  }
     212  #endif /* L_conv_sd */
     213  
     214  #if defined(L_conv_dd)
     215  void
     216  __host_to_ieee_64 (_Decimal64 in, decimal64 *out)
     217  {
     218    memcpy (out, &in, 8);
     219  }
     220  
     221  void
     222  __ieee_to_host_64 (decimal64 in, _Decimal64 *out)
     223  {
     224    memcpy (out, &in, 8);
     225  }
     226  #endif /* L_conv_dd */
     227  
     228  #if defined(L_conv_td)
     229  void
     230  __host_to_ieee_128 (_Decimal128 in, decimal128 *out)
     231  {
     232    memcpy (out, &in, 16);
     233  }
     234  
     235  void
     236  __ieee_to_host_128 (decimal128 in, _Decimal128 *out)
     237  {
     238    memcpy (out, &in, 16);
     239  }
     240  #endif /* L_conv_td */
     241  
     242  #if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td)
     243  DFP_C_TYPE
     244  DFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
     245  {
     246    return DFP_BINARY_OP (DEC_FLOAT_ADD, arg_a, arg_b);
     247  }
     248  
     249  DFP_C_TYPE
     250  DFP_SUB (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
     251  {
     252    return DFP_BINARY_OP (DEC_FLOAT_SUBTRACT, arg_a, arg_b);
     253  }
     254  #endif /* L_addsub */
     255  
     256  #if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td)
     257  DFP_C_TYPE
     258  DFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
     259  {
     260    return DFP_BINARY_OP (DEC_FLOAT_MULTIPLY, arg_a, arg_b);
     261  }
     262  #endif /* L_mul */
     263  
     264  #if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
     265  DFP_C_TYPE
     266  DFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
     267  {
     268    return DFP_BINARY_OP (DEC_FLOAT_DIVIDE, arg_a, arg_b);
     269  }
     270  #endif /* L_div */
     271  
     272  #if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
     273  CMPtype
     274  DFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
     275  {
     276    CMPtype stat;
     277    stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
     278    /* For EQ return zero for true, nonzero for false.  */
     279    return stat != 0;
     280  }
     281  #endif /* L_eq */
     282  
     283  #if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
     284  CMPtype
     285  DFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
     286  {
     287    int stat;
     288    stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
     289    /* For NE return zero for true, nonzero for false.  */
     290    if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
     291      return 1;
     292    return stat != 0;
     293  }
     294  #endif /* L_ne */
     295  
     296  #if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
     297  CMPtype
     298  DFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
     299  {
     300    int stat;
     301    stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
     302    /* For LT return -1 (<0) for true, 1 for false.  */
     303    return (stat == -1) ? -1 : 1;
     304  }
     305  #endif /* L_lt */
     306  
     307  #if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
     308  CMPtype
     309  DFP_GT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
     310  {
     311    int stat;
     312    stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
     313    /* For GT return 1 (>0) for true, -1 for false.  */
     314    return (stat == 1) ? 1 : -1;
     315  }
     316  #endif
     317  
     318  #if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
     319  CMPtype
     320  DFP_LE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
     321  {
     322    int stat;
     323    stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
     324    /* For LE return 0 (<= 0) for true, 1 for false.  */
     325    if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
     326      return 1;
     327    return stat == 1;
     328  }
     329  #endif /* L_le */
     330  
     331  #if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
     332  CMPtype
     333  DFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
     334  {
     335    int stat;
     336    stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
     337    /* For GE return 1 (>=0) for true, -1 for false.  */
     338    if (__builtin_expect (stat == -2, 0))  /* An operand is NaN.  */
     339      return -1;
     340    return (stat != -1) ? 1 : -1;
     341  }
     342  #endif /* L_ge */
     343  
     344  #define BUFMAX 128
     345  
     346  /* Check for floating point exceptions that are relevant for conversions
     347     between decimal float values and handle them.  */
     348  static inline void
     349  dfp_conversion_exceptions (const int status)
     350  {
     351    /* decNumber exception flags we care about here.  */
     352    int ieee_flags;
     353    int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Invalid_operation
     354  		  | DEC_IEEE_854_Overflow;
     355    dec_flags &= status;
     356    ieee_flags = DFP_IEEE_FLAGS (dec_flags);
     357    if (ieee_flags != 0)
     358      DFP_HANDLE_EXCEPTIONS (ieee_flags);
     359  }
     360  
     361  #if defined (L_sd_to_dd)
     362  /* Use decNumber to convert directly from _Decimal32 to _Decimal64.  */
     363  _Decimal64
     364  DFP_TO_DFP (_Decimal32 f_from)
     365  {
     366    union { _Decimal32 c; decSingle f; } from;
     367    union { _Decimal64 c; decDouble f; } to;
     368  
     369    from.c = f_from;
     370    to.f = *decSingleToWider (&from.f, &to.f);
     371    return to.c;
     372  }
     373  #endif
     374  
     375  #if defined (L_sd_to_td)
     376  /* Use decNumber to convert directly from _Decimal32 to _Decimal128.  */
     377  _Decimal128
     378  DFP_TO_DFP (_Decimal32 f_from)
     379  {
     380    union { _Decimal32 c; decSingle f; } from;
     381    union { _Decimal128 c; decQuad f; } to;
     382    decDouble temp;
     383  
     384    from.c = f_from;
     385    temp = *decSingleToWider (&from.f, &temp);
     386    to.f = *decDoubleToWider (&temp, &to.f);
     387    return to.c;
     388  }
     389  #endif
     390  
     391  #if defined (L_dd_to_td)
     392  /* Use decNumber to convert directly from _Decimal64 to _Decimal128.  */
     393  _Decimal128
     394  DFP_TO_DFP (_Decimal64 f_from)
     395  {
     396    union { _Decimal64 c; decDouble f; } from;
     397    union { _Decimal128 c; decQuad f; } to;
     398  
     399    from.c = f_from;
     400    to.f = *decDoubleToWider (&from.f, &to.f);
     401    return to.c;
     402  }
     403  #endif
     404  
     405  #if defined (L_dd_to_sd)
     406  /* Use decNumber to convert directly from _Decimal64 to _Decimal32.  */
     407  _Decimal32
     408  DFP_TO_DFP (_Decimal64 f_from)
     409  {
     410    union { _Decimal32 c; decSingle f; } to;
     411    union { _Decimal64 c; decDouble f; } from;
     412    decContext context;
     413  
     414    decContextDefault (&context, CONTEXT_INIT);
     415    DFP_INIT_ROUNDMODE (context.round);
     416    from.c = f_from;
     417    to.f = *decSingleFromWider (&to.f, &from.f, &context);
     418    if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
     419      dfp_conversion_exceptions (context.status);
     420    return to.c;
     421  }
     422  #endif
     423  
     424  #if defined (L_td_to_sd)
     425  /* Use decNumber to convert directly from _Decimal128 to _Decimal32.  */
     426  _Decimal32
     427  DFP_TO_DFP (_Decimal128 f_from)
     428  {
     429    union { _Decimal32 c; decSingle f; } to;
     430    union { _Decimal128 c; decQuad f; } from;
     431    decDouble temp;
     432    decContext context;
     433  
     434    decContextDefault (&context, CONTEXT_INIT);
     435    DFP_INIT_ROUNDMODE (context.round);
     436    from.c = f_from;
     437    temp = *decDoubleFromWider (&temp, &from.f, &context);
     438    to.f = *decSingleFromWider (&to.f, &temp, &context);
     439    if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
     440      dfp_conversion_exceptions (context.status);
     441    return to.c;
     442  }
     443  #endif
     444  
     445  #if defined (L_td_to_dd)
     446  /* Use decNumber to convert directly from _Decimal128 to _Decimal64.  */
     447  _Decimal64
     448  DFP_TO_DFP (_Decimal128 f_from)
     449  {
     450    union { _Decimal64 c; decDouble f; } to;
     451    union { _Decimal128 c; decQuad f; } from;
     452    decContext context;
     453  
     454    decContextDefault (&context, CONTEXT_INIT);
     455    DFP_INIT_ROUNDMODE (context.round);
     456    from.c = f_from;
     457    to.f = *decDoubleFromWider (&to.f, &from.f, &context);
     458    if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
     459      dfp_conversion_exceptions (context.status);
     460    return to.c;
     461  }
     462  #endif
     463  
     464  #if defined (L_dd_to_si) || defined (L_td_to_si) \
     465    || defined (L_dd_to_usi) || defined (L_td_to_usi)
     466  /* Use decNumber to convert directly from decimal float to integer types.  */
     467  INT_TYPE
     468  DFP_TO_INT (DFP_C_TYPE x)
     469  {
     470    union { DFP_C_TYPE c; decFloat f; } u;
     471    decContext context;
     472    INT_TYPE i;
     473  
     474    decContextDefault (&context, DEC_INIT_DECIMAL128);
     475    context.round = DEC_ROUND_DOWN;
     476    u.c = x;
     477    i = DEC_FLOAT_TO_INT (&u.f, &context, context.round);
     478    if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
     479      dfp_conversion_exceptions (context.status);
     480    return i;
     481  }
     482  #endif
     483  
     484  #if defined (L_sd_to_si) || (L_sd_to_usi)
     485  /* Use decNumber to convert directly from decimal float to integer types.  */
     486  INT_TYPE
     487  DFP_TO_INT (_Decimal32 x)
     488  {
     489    union { _Decimal32 c; decSingle f; } u32;
     490    decDouble f64;
     491    decContext context;
     492    INT_TYPE i;
     493  
     494    decContextDefault (&context, DEC_INIT_DECIMAL128);
     495    context.round = DEC_ROUND_DOWN;
     496    u32.c = x;
     497    f64 = *decSingleToWider (&u32.f, &f64);
     498    i = DEC_FLOAT_TO_INT (&f64, &context, context.round);
     499    if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
     500      dfp_conversion_exceptions (context.status);
     501    return i;
     502  }
     503  #endif
     504  
     505  #if defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) \
     506    || defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi)
     507  /* decNumber doesn't provide support for conversions to 64-bit integer
     508     types, so do it the hard way.  */
     509  INT_TYPE
     510  DFP_TO_INT (DFP_C_TYPE x)
     511  {
     512    /* decNumber's decimal* types have the same format as C's _Decimal*
     513       types, but they have different calling conventions.  */
     514  
     515    /* TODO: Decimal float to integer conversions should raise FE_INVALID
     516       if the result value does not fit into the result type.  */
     517  
     518    IEEE_TYPE s;
     519    char buf[BUFMAX];
     520    char *pos;
     521    decNumber qval, n1, n2;
     522    decContext context;
     523  
     524    /* Use a large context to avoid losing precision.  */
     525    decContextDefault (&context, DEC_INIT_DECIMAL128);
     526    /* Need non-default rounding mode here.  */
     527    context.round = DEC_ROUND_DOWN;
     528  
     529    HOST_TO_IEEE (x, &s);
     530    TO_INTERNAL (&s, &n1);
     531    /* Rescale if the exponent is less than zero.  */
     532    decNumberToIntegralValue (&n2, &n1, &context);
     533    /* Get a value to use for the quantize call.  */
     534    decNumberFromString (&qval, "1.", &context);
     535    /* Force the exponent to zero.  */
     536    decNumberQuantize (&n1, &n2, &qval, &context);
     537    /* Get a string, which at this point will not include an exponent.  */
     538    decNumberToString (&n1, buf);
     539    /* Ignore the fractional part.  */
     540    pos = strchr (buf, '.');
     541    if (pos)
     542      *pos = 0;
     543    /* Use a C library function to convert to the integral type.  */
     544    return STR_TO_INT (buf, NULL, 10);
     545  }
     546  #endif
     547  
     548  #if defined (L_si_to_dd) || defined (L_si_to_td) \
     549    || defined (L_usi_to_dd) || defined (L_usi_to_td)
     550  /* Use decNumber to convert directly from integer to decimal float types.  */
     551  DFP_C_TYPE
     552  INT_TO_DFP (INT_TYPE i)
     553  {
     554    union { DFP_C_TYPE c; decFloat f; } u;
     555  
     556    u.f = *DEC_FLOAT_FROM_INT (&u.f, i);
     557    return u.c;
     558  }
     559  #endif
     560  
     561  #if defined (L_si_to_sd) || defined (L_usi_to_sd)
     562  _Decimal32
     563  /* Use decNumber to convert directly from integer to decimal float types.  */
     564  INT_TO_DFP (INT_TYPE i)
     565  {
     566    union { _Decimal32 c; decSingle f; } u32;
     567    decDouble f64;
     568    decContext context;
     569  
     570    decContextDefault (&context, DEC_INIT_DECIMAL128);
     571    f64 = *DEC_FLOAT_FROM_INT (&f64, i);
     572    u32.f = *decSingleFromWider (&u32.f, &f64, &context);
     573    if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
     574      dfp_conversion_exceptions (context.status);
     575    return u32.c;
     576  }
     577  #endif
     578  
     579  #if defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \
     580    || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td)
     581  /* decNumber doesn't provide support for conversions from 64-bit integer
     582     types, so do it the hard way.  */
     583  DFP_C_TYPE
     584  INT_TO_DFP (INT_TYPE i)
     585  {
     586    DFP_C_TYPE f;
     587    IEEE_TYPE s;
     588    char buf[BUFMAX];
     589    decContext context;
     590  
     591    decContextDefault (&context, CONTEXT_INIT);
     592    DFP_INIT_ROUNDMODE (context.round);
     593  
     594    /* Use a C library function to get a floating point string.  */
     595    sprintf (buf, INT_FMT ".", CAST_FOR_FMT(i));
     596    /* Convert from the floating point string to a decimal* type.  */
     597    FROM_STRING (&s, buf, &context);
     598    IEEE_TO_HOST (s, &f);
     599  
     600    if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
     601      dfp_conversion_exceptions (context.status);
     602  
     603    return f;
     604  }
     605  #endif
     606  
     607  #if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \
     608   || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \
     609   || defined (L_sd_to_kf) || defined (L_dd_to_kf) || defined (L_td_to_kf) \
     610   || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \
     611       && LONG_DOUBLE_HAS_XF_MODE) \
     612   || ((defined (L_sd_to_tf) || defined (L_dd_to_tf) || defined (L_td_to_tf)) \
     613       && LONG_DOUBLE_HAS_TF_MODE)
     614  BFP_TYPE
     615  DFP_TO_BFP (DFP_C_TYPE f)
     616  {
     617    IEEE_TYPE s;
     618    char buf[BUFMAX];
     619  
     620    HOST_TO_IEEE (f, &s);
     621    /* Write the value to a string.  */
     622    TO_STRING (&s, buf);
     623    /* Read it as the binary floating point type and return that.  */
     624    return STR_TO_BFP (buf, NULL);
     625  }
     626  #endif
     627                                                                                  
     628  #if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \
     629   || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \
     630   || defined (L_kf_to_sd) || defined (L_kf_to_dd) || defined (L_kf_to_td) \
     631   || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \
     632       && LONG_DOUBLE_HAS_XF_MODE) \
     633   || ((defined (L_tf_to_sd) || defined (L_tf_to_dd) || defined (L_tf_to_td)) \
     634       && LONG_DOUBLE_HAS_TF_MODE)
     635  DFP_C_TYPE
     636  BFP_TO_DFP (BFP_TYPE x)
     637  {
     638    DFP_C_TYPE f;
     639    IEEE_TYPE s;
     640    char buf[BUFMAX];
     641    decContext context;
     642  
     643    decContextDefault (&context, CONTEXT_INIT);
     644    DFP_INIT_ROUNDMODE (context.round);
     645  
     646    /* Use the sprintf library function to write the floating point value to a
     647       string.
     648  
     649       If we are handling the IEEE 128-bit floating point on PowerPC, use the
     650       special function __sprintfkf instead of sprintf.  This function allows us
     651       to use __sprintfieee128 if we have a new enough GLIBC, and it can fall back
     652       to using the traditional sprintf via conversion to IBM 128-bit if the glibc
     653       is older.  */
     654    BFP_SPRINTF (buf, BFP_FMT, (BFP_VIA_TYPE) x);
     655  
     656    /* Convert from the floating point string to a decimal* type.  */
     657    FROM_STRING (&s, buf, &context);
     658    IEEE_TO_HOST (s, &f);
     659  
     660    if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
     661      {
     662        /* decNumber exception flags we care about here.  */
     663        int ieee_flags;
     664        int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Invalid_operation
     665  		      | DEC_IEEE_854_Overflow | DEC_IEEE_854_Underflow;
     666        dec_flags &= context.status;
     667        ieee_flags = DFP_IEEE_FLAGS (dec_flags);
     668        if (ieee_flags != 0)
     669          DFP_HANDLE_EXCEPTIONS (ieee_flags);
     670      }
     671  
     672    return f;
     673  }
     674  #endif
     675  
     676  #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
     677  CMPtype
     678  DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
     679  {
     680    decNumber arg1, arg2;
     681    IEEE_TYPE a, b;
     682  
     683    HOST_TO_IEEE (arg_a, &a);
     684    HOST_TO_IEEE (arg_b, &b);
     685    TO_INTERNAL (&a, &arg1);
     686    TO_INTERNAL (&b, &arg2);
     687    return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2));
     688  }
     689  #endif /* L_unord_sd || L_unord_dd || L_unord_td */