11debfc3dSmrg /* This is a software decimal floating point library.
2*8feb0f0bSmrg Copyright (C) 2005-2020 Free Software Foundation, Inc.
31debfc3dSmrg
41debfc3dSmrg This file is part of GCC.
51debfc3dSmrg
61debfc3dSmrg GCC is free software; you can redistribute it and/or modify it under
71debfc3dSmrg the terms of the GNU General Public License as published by the Free
81debfc3dSmrg Software Foundation; either version 3, or (at your option) any later
91debfc3dSmrg version.
101debfc3dSmrg
111debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
121debfc3dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
131debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
141debfc3dSmrg for more details.
151debfc3dSmrg
161debfc3dSmrg Under Section 7 of GPL version 3, you are granted additional
171debfc3dSmrg permissions described in the GCC Runtime Library Exception, version
181debfc3dSmrg 3.1, as published by the Free Software Foundation.
191debfc3dSmrg
201debfc3dSmrg You should have received a copy of the GNU General Public License and
211debfc3dSmrg a copy of the GCC Runtime Library Exception along with this program;
221debfc3dSmrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
231debfc3dSmrg <http://www.gnu.org/licenses/>. */
241debfc3dSmrg
251debfc3dSmrg /* This implements IEEE 754 decimal floating point arithmetic, but
261debfc3dSmrg does not provide a mechanism for setting the rounding mode, or for
271debfc3dSmrg generating or handling exceptions. Conversions between decimal
281debfc3dSmrg floating point types and other types depend on C library functions.
291debfc3dSmrg
301debfc3dSmrg Contributed by Ben Elliston <bje@au.ibm.com>. */
311debfc3dSmrg
321debfc3dSmrg #include <stdio.h>
331debfc3dSmrg #include <stdlib.h>
341debfc3dSmrg /* FIXME: compile with -std=gnu99 to get these from stdlib.h */
351debfc3dSmrg extern float strtof (const char *, char **);
361debfc3dSmrg extern long double strtold (const char *, char **);
371debfc3dSmrg #include <string.h>
381debfc3dSmrg #include <limits.h>
391debfc3dSmrg
401debfc3dSmrg #include "dfp-bit.h"
411debfc3dSmrg
421debfc3dSmrg /* Forward declarations. */
431debfc3dSmrg #if WIDTH == 32 || WIDTH_TO == 32
441debfc3dSmrg void __host_to_ieee_32 (_Decimal32 in, decimal32 *out);
451debfc3dSmrg void __ieee_to_host_32 (decimal32 in, _Decimal32 *out);
461debfc3dSmrg #endif
471debfc3dSmrg #if WIDTH == 64 || WIDTH_TO == 64
481debfc3dSmrg void __host_to_ieee_64 (_Decimal64 in, decimal64 *out);
491debfc3dSmrg void __ieee_to_host_64 (decimal64 in, _Decimal64 *out);
501debfc3dSmrg #endif
511debfc3dSmrg #if WIDTH == 128 || WIDTH_TO == 128
521debfc3dSmrg void __host_to_ieee_128 (_Decimal128 in, decimal128 *out);
531debfc3dSmrg void __ieee_to_host_128 (decimal128 in, _Decimal128 *out);
541debfc3dSmrg #endif
551debfc3dSmrg
561debfc3dSmrg /* A pointer to a binary decFloat operation. */
571debfc3dSmrg typedef decFloat* (*dfp_binary_func)
581debfc3dSmrg (decFloat *, const decFloat *, const decFloat *, decContext *);
591debfc3dSmrg
601debfc3dSmrg /* Binary operations. */
611debfc3dSmrg
621debfc3dSmrg /* Use a decFloat (decDouble or decQuad) function to perform a DFP
631debfc3dSmrg binary operation. */
641debfc3dSmrg static inline decFloat
dfp_binary_op(dfp_binary_func op,decFloat arg_a,decFloat arg_b)651debfc3dSmrg dfp_binary_op (dfp_binary_func op, decFloat arg_a, decFloat arg_b)
661debfc3dSmrg {
671debfc3dSmrg decFloat result;
681debfc3dSmrg decContext context;
691debfc3dSmrg
701debfc3dSmrg decContextDefault (&context, CONTEXT_INIT);
711debfc3dSmrg DFP_INIT_ROUNDMODE (context.round);
721debfc3dSmrg
731debfc3dSmrg /* Perform the operation. */
741debfc3dSmrg op (&result, &arg_a, &arg_b, &context);
751debfc3dSmrg
761debfc3dSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
771debfc3dSmrg {
781debfc3dSmrg /* decNumber exception flags we care about here. */
791debfc3dSmrg int ieee_flags;
801debfc3dSmrg int dec_flags = DEC_IEEE_854_Division_by_zero | DEC_IEEE_854_Inexact
811debfc3dSmrg | DEC_IEEE_854_Invalid_operation | DEC_IEEE_854_Overflow
821debfc3dSmrg | DEC_IEEE_854_Underflow;
831debfc3dSmrg dec_flags &= context.status;
841debfc3dSmrg ieee_flags = DFP_IEEE_FLAGS (dec_flags);
851debfc3dSmrg if (ieee_flags != 0)
861debfc3dSmrg DFP_HANDLE_EXCEPTIONS (ieee_flags);
871debfc3dSmrg }
881debfc3dSmrg
891debfc3dSmrg return result;
901debfc3dSmrg }
911debfc3dSmrg
921debfc3dSmrg #if WIDTH == 32
931debfc3dSmrg /* The decNumber package doesn't provide arithmetic for decSingle (32 bits);
941debfc3dSmrg convert to decDouble, use the operation for that, and convert back. */
951debfc3dSmrg static inline _Decimal32
d32_binary_op(dfp_binary_func op,_Decimal32 arg_a,_Decimal32 arg_b)961debfc3dSmrg d32_binary_op (dfp_binary_func op, _Decimal32 arg_a, _Decimal32 arg_b)
971debfc3dSmrg {
981debfc3dSmrg union { _Decimal32 c; decSingle f; } a32, b32, res32;
991debfc3dSmrg decDouble a, b, res;
1001debfc3dSmrg decContext context;
1011debfc3dSmrg
1021debfc3dSmrg /* Widen the operands and perform the operation. */
1031debfc3dSmrg a32.c = arg_a;
1041debfc3dSmrg b32.c = arg_b;
1051debfc3dSmrg decSingleToWider (&a32.f, &a);
1061debfc3dSmrg decSingleToWider (&b32.f, &b);
1071debfc3dSmrg res = dfp_binary_op (op, a, b);
1081debfc3dSmrg
1091debfc3dSmrg /* Narrow the result, which might result in an underflow or overflow. */
1101debfc3dSmrg decContextDefault (&context, CONTEXT_INIT);
1111debfc3dSmrg DFP_INIT_ROUNDMODE (context.round);
1121debfc3dSmrg decSingleFromWider (&res32.f, &res, &context);
1131debfc3dSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
1141debfc3dSmrg {
1151debfc3dSmrg /* decNumber exception flags we care about here. */
1161debfc3dSmrg int ieee_flags;
1171debfc3dSmrg int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Overflow
1181debfc3dSmrg | DEC_IEEE_854_Underflow;
1191debfc3dSmrg dec_flags &= context.status;
1201debfc3dSmrg ieee_flags = DFP_IEEE_FLAGS (dec_flags);
1211debfc3dSmrg if (ieee_flags != 0)
1221debfc3dSmrg DFP_HANDLE_EXCEPTIONS (ieee_flags);
1231debfc3dSmrg }
1241debfc3dSmrg
1251debfc3dSmrg return res32.c;
1261debfc3dSmrg }
1271debfc3dSmrg #else
1281debfc3dSmrg /* decFloat operations are supported for decDouble (64 bits) and
1291debfc3dSmrg decQuad (128 bits). The bit patterns for the types are the same. */
1301debfc3dSmrg static inline DFP_C_TYPE
dnn_binary_op(dfp_binary_func op,DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)1311debfc3dSmrg dnn_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
1321debfc3dSmrg {
1331debfc3dSmrg union { DFP_C_TYPE c; decFloat f; } a, b, result;
1341debfc3dSmrg
1351debfc3dSmrg a.c = arg_a;
1361debfc3dSmrg b.c = arg_b;
1371debfc3dSmrg result.f = dfp_binary_op (op, a.f, b.f);
1381debfc3dSmrg return result.c;
1391debfc3dSmrg }
1401debfc3dSmrg #endif
1411debfc3dSmrg
1421debfc3dSmrg /* Comparison operations. */
1431debfc3dSmrg
1441debfc3dSmrg /* Use a decFloat (decDouble or decQuad) function to perform a DFP
1451debfc3dSmrg comparison. */
1461debfc3dSmrg static inline CMPtype
dfp_compare_op(dfp_binary_func op,decFloat arg_a,decFloat arg_b)1471debfc3dSmrg dfp_compare_op (dfp_binary_func op, decFloat arg_a, decFloat arg_b)
1481debfc3dSmrg {
1491debfc3dSmrg decContext context;
1501debfc3dSmrg decFloat res;
1511debfc3dSmrg int result;
1521debfc3dSmrg
1531debfc3dSmrg decContextDefault (&context, CONTEXT_INIT);
1541debfc3dSmrg DFP_INIT_ROUNDMODE (context.round);
1551debfc3dSmrg
1561debfc3dSmrg /* Perform the comparison. */
1571debfc3dSmrg op (&res, &arg_a, &arg_b, &context);
1581debfc3dSmrg
1591debfc3dSmrg if (DEC_FLOAT_IS_SIGNED (&res))
1601debfc3dSmrg result = -1;
1611debfc3dSmrg else if (DEC_FLOAT_IS_ZERO (&res))
1621debfc3dSmrg result = 0;
1631debfc3dSmrg else if (DEC_FLOAT_IS_NAN (&res))
1641debfc3dSmrg result = -2;
1651debfc3dSmrg else
1661debfc3dSmrg result = 1;
1671debfc3dSmrg
1681debfc3dSmrg return (CMPtype) result;
1691debfc3dSmrg }
1701debfc3dSmrg
1711debfc3dSmrg #if WIDTH == 32
1721debfc3dSmrg /* The decNumber package doesn't provide comparisons for decSingle (32 bits);
1731debfc3dSmrg convert to decDouble, use the operation for that, and convert back. */
1741debfc3dSmrg static inline CMPtype
d32_compare_op(dfp_binary_func op,_Decimal32 arg_a,_Decimal32 arg_b)1751debfc3dSmrg d32_compare_op (dfp_binary_func op, _Decimal32 arg_a, _Decimal32 arg_b)
1761debfc3dSmrg {
1771debfc3dSmrg union { _Decimal32 c; decSingle f; } a32, b32;
1781debfc3dSmrg decDouble a, b;
1791debfc3dSmrg
1801debfc3dSmrg a32.c = arg_a;
1811debfc3dSmrg b32.c = arg_b;
1821debfc3dSmrg decSingleToWider (&a32.f, &a);
1831debfc3dSmrg decSingleToWider (&b32.f, &b);
1841debfc3dSmrg return dfp_compare_op (op, a, b);
1851debfc3dSmrg }
1861debfc3dSmrg #else
1871debfc3dSmrg /* decFloat comparisons are supported for decDouble (64 bits) and
1881debfc3dSmrg decQuad (128 bits). The bit patterns for the types are the same. */
1891debfc3dSmrg static inline CMPtype
dnn_compare_op(dfp_binary_func op,DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)1901debfc3dSmrg dnn_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
1911debfc3dSmrg {
1921debfc3dSmrg union { DFP_C_TYPE c; decFloat f; } a, b;
1931debfc3dSmrg
1941debfc3dSmrg a.c = arg_a;
1951debfc3dSmrg b.c = arg_b;
1961debfc3dSmrg return dfp_compare_op (op, a.f, b.f);
1971debfc3dSmrg }
1981debfc3dSmrg #endif
1991debfc3dSmrg
2001debfc3dSmrg #if defined(L_conv_sd)
2011debfc3dSmrg void
__host_to_ieee_32(_Decimal32 in,decimal32 * out)2021debfc3dSmrg __host_to_ieee_32 (_Decimal32 in, decimal32 *out)
2031debfc3dSmrg {
2041debfc3dSmrg memcpy (out, &in, 4);
2051debfc3dSmrg }
2061debfc3dSmrg
2071debfc3dSmrg void
__ieee_to_host_32(decimal32 in,_Decimal32 * out)2081debfc3dSmrg __ieee_to_host_32 (decimal32 in, _Decimal32 *out)
2091debfc3dSmrg {
2101debfc3dSmrg memcpy (out, &in, 4);
2111debfc3dSmrg }
2121debfc3dSmrg #endif /* L_conv_sd */
2131debfc3dSmrg
2141debfc3dSmrg #if defined(L_conv_dd)
2151debfc3dSmrg void
__host_to_ieee_64(_Decimal64 in,decimal64 * out)2161debfc3dSmrg __host_to_ieee_64 (_Decimal64 in, decimal64 *out)
2171debfc3dSmrg {
2181debfc3dSmrg memcpy (out, &in, 8);
2191debfc3dSmrg }
2201debfc3dSmrg
2211debfc3dSmrg void
__ieee_to_host_64(decimal64 in,_Decimal64 * out)2221debfc3dSmrg __ieee_to_host_64 (decimal64 in, _Decimal64 *out)
2231debfc3dSmrg {
2241debfc3dSmrg memcpy (out, &in, 8);
2251debfc3dSmrg }
2261debfc3dSmrg #endif /* L_conv_dd */
2271debfc3dSmrg
2281debfc3dSmrg #if defined(L_conv_td)
2291debfc3dSmrg void
__host_to_ieee_128(_Decimal128 in,decimal128 * out)2301debfc3dSmrg __host_to_ieee_128 (_Decimal128 in, decimal128 *out)
2311debfc3dSmrg {
2321debfc3dSmrg memcpy (out, &in, 16);
2331debfc3dSmrg }
2341debfc3dSmrg
2351debfc3dSmrg void
__ieee_to_host_128(decimal128 in,_Decimal128 * out)2361debfc3dSmrg __ieee_to_host_128 (decimal128 in, _Decimal128 *out)
2371debfc3dSmrg {
2381debfc3dSmrg memcpy (out, &in, 16);
2391debfc3dSmrg }
2401debfc3dSmrg #endif /* L_conv_td */
2411debfc3dSmrg
2421debfc3dSmrg #if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td)
2431debfc3dSmrg DFP_C_TYPE
DFP_ADD(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)2441debfc3dSmrg DFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
2451debfc3dSmrg {
2461debfc3dSmrg return DFP_BINARY_OP (DEC_FLOAT_ADD, arg_a, arg_b);
2471debfc3dSmrg }
2481debfc3dSmrg
2491debfc3dSmrg DFP_C_TYPE
DFP_SUB(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)2501debfc3dSmrg DFP_SUB (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
2511debfc3dSmrg {
2521debfc3dSmrg return DFP_BINARY_OP (DEC_FLOAT_SUBTRACT, arg_a, arg_b);
2531debfc3dSmrg }
2541debfc3dSmrg #endif /* L_addsub */
2551debfc3dSmrg
2561debfc3dSmrg #if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td)
2571debfc3dSmrg DFP_C_TYPE
DFP_MULTIPLY(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)2581debfc3dSmrg DFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
2591debfc3dSmrg {
2601debfc3dSmrg return DFP_BINARY_OP (DEC_FLOAT_MULTIPLY, arg_a, arg_b);
2611debfc3dSmrg }
2621debfc3dSmrg #endif /* L_mul */
2631debfc3dSmrg
2641debfc3dSmrg #if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
2651debfc3dSmrg DFP_C_TYPE
DFP_DIVIDE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)2661debfc3dSmrg DFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
2671debfc3dSmrg {
2681debfc3dSmrg return DFP_BINARY_OP (DEC_FLOAT_DIVIDE, arg_a, arg_b);
2691debfc3dSmrg }
2701debfc3dSmrg #endif /* L_div */
2711debfc3dSmrg
2721debfc3dSmrg #if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
2731debfc3dSmrg CMPtype
DFP_EQ(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)2741debfc3dSmrg DFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
2751debfc3dSmrg {
2761debfc3dSmrg CMPtype stat;
2771debfc3dSmrg stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
2781debfc3dSmrg /* For EQ return zero for true, nonzero for false. */
2791debfc3dSmrg return stat != 0;
2801debfc3dSmrg }
2811debfc3dSmrg #endif /* L_eq */
2821debfc3dSmrg
2831debfc3dSmrg #if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
2841debfc3dSmrg CMPtype
DFP_NE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)2851debfc3dSmrg DFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
2861debfc3dSmrg {
2871debfc3dSmrg int stat;
2881debfc3dSmrg stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
2891debfc3dSmrg /* For NE return zero for true, nonzero for false. */
2901debfc3dSmrg if (__builtin_expect (stat == -2, 0)) /* An operand is NaN. */
2911debfc3dSmrg return 1;
2921debfc3dSmrg return stat != 0;
2931debfc3dSmrg }
2941debfc3dSmrg #endif /* L_ne */
2951debfc3dSmrg
2961debfc3dSmrg #if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
2971debfc3dSmrg CMPtype
DFP_LT(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)2981debfc3dSmrg DFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
2991debfc3dSmrg {
3001debfc3dSmrg int stat;
3011debfc3dSmrg stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
3021debfc3dSmrg /* For LT return -1 (<0) for true, 1 for false. */
3031debfc3dSmrg return (stat == -1) ? -1 : 1;
3041debfc3dSmrg }
3051debfc3dSmrg #endif /* L_lt */
3061debfc3dSmrg
3071debfc3dSmrg #if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
3081debfc3dSmrg CMPtype
DFP_GT(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)3091debfc3dSmrg DFP_GT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
3101debfc3dSmrg {
3111debfc3dSmrg int stat;
3121debfc3dSmrg stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
3131debfc3dSmrg /* For GT return 1 (>0) for true, -1 for false. */
3141debfc3dSmrg return (stat == 1) ? 1 : -1;
3151debfc3dSmrg }
3161debfc3dSmrg #endif
3171debfc3dSmrg
3181debfc3dSmrg #if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
3191debfc3dSmrg CMPtype
DFP_LE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)3201debfc3dSmrg DFP_LE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
3211debfc3dSmrg {
3221debfc3dSmrg int stat;
3231debfc3dSmrg stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
3241debfc3dSmrg /* For LE return 0 (<= 0) for true, 1 for false. */
3251debfc3dSmrg if (__builtin_expect (stat == -2, 0)) /* An operand is NaN. */
3261debfc3dSmrg return 1;
3271debfc3dSmrg return stat == 1;
3281debfc3dSmrg }
3291debfc3dSmrg #endif /* L_le */
3301debfc3dSmrg
3311debfc3dSmrg #if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
3321debfc3dSmrg CMPtype
DFP_GE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)3331debfc3dSmrg DFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
3341debfc3dSmrg {
3351debfc3dSmrg int stat;
3361debfc3dSmrg stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
3371debfc3dSmrg /* For GE return 1 (>=0) for true, -1 for false. */
3381debfc3dSmrg if (__builtin_expect (stat == -2, 0)) /* An operand is NaN. */
3391debfc3dSmrg return -1;
3401debfc3dSmrg return (stat != -1) ? 1 : -1;
3411debfc3dSmrg }
3421debfc3dSmrg #endif /* L_ge */
3431debfc3dSmrg
3441debfc3dSmrg #define BUFMAX 128
3451debfc3dSmrg
3461debfc3dSmrg /* Check for floating point exceptions that are relevant for conversions
3471debfc3dSmrg between decimal float values and handle them. */
3481debfc3dSmrg static inline void
dfp_conversion_exceptions(const int status)3491debfc3dSmrg dfp_conversion_exceptions (const int status)
3501debfc3dSmrg {
3511debfc3dSmrg /* decNumber exception flags we care about here. */
3521debfc3dSmrg int ieee_flags;
3531debfc3dSmrg int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Invalid_operation
3541debfc3dSmrg | DEC_IEEE_854_Overflow;
3551debfc3dSmrg dec_flags &= status;
3561debfc3dSmrg ieee_flags = DFP_IEEE_FLAGS (dec_flags);
3571debfc3dSmrg if (ieee_flags != 0)
3581debfc3dSmrg DFP_HANDLE_EXCEPTIONS (ieee_flags);
3591debfc3dSmrg }
3601debfc3dSmrg
3611debfc3dSmrg #if defined (L_sd_to_dd)
3621debfc3dSmrg /* Use decNumber to convert directly from _Decimal32 to _Decimal64. */
3631debfc3dSmrg _Decimal64
DFP_TO_DFP(_Decimal32 f_from)3641debfc3dSmrg DFP_TO_DFP (_Decimal32 f_from)
3651debfc3dSmrg {
3661debfc3dSmrg union { _Decimal32 c; decSingle f; } from;
3671debfc3dSmrg union { _Decimal64 c; decDouble f; } to;
3681debfc3dSmrg
3691debfc3dSmrg from.c = f_from;
3701debfc3dSmrg to.f = *decSingleToWider (&from.f, &to.f);
3711debfc3dSmrg return to.c;
3721debfc3dSmrg }
3731debfc3dSmrg #endif
3741debfc3dSmrg
3751debfc3dSmrg #if defined (L_sd_to_td)
3761debfc3dSmrg /* Use decNumber to convert directly from _Decimal32 to _Decimal128. */
3771debfc3dSmrg _Decimal128
DFP_TO_DFP(_Decimal32 f_from)3781debfc3dSmrg DFP_TO_DFP (_Decimal32 f_from)
3791debfc3dSmrg {
3801debfc3dSmrg union { _Decimal32 c; decSingle f; } from;
3811debfc3dSmrg union { _Decimal128 c; decQuad f; } to;
3821debfc3dSmrg decDouble temp;
3831debfc3dSmrg
3841debfc3dSmrg from.c = f_from;
3851debfc3dSmrg temp = *decSingleToWider (&from.f, &temp);
3861debfc3dSmrg to.f = *decDoubleToWider (&temp, &to.f);
3871debfc3dSmrg return to.c;
3881debfc3dSmrg }
3891debfc3dSmrg #endif
3901debfc3dSmrg
3911debfc3dSmrg #if defined (L_dd_to_td)
3921debfc3dSmrg /* Use decNumber to convert directly from _Decimal64 to _Decimal128. */
3931debfc3dSmrg _Decimal128
DFP_TO_DFP(_Decimal64 f_from)3941debfc3dSmrg DFP_TO_DFP (_Decimal64 f_from)
3951debfc3dSmrg {
3961debfc3dSmrg union { _Decimal64 c; decDouble f; } from;
3971debfc3dSmrg union { _Decimal128 c; decQuad f; } to;
3981debfc3dSmrg
3991debfc3dSmrg from.c = f_from;
4001debfc3dSmrg to.f = *decDoubleToWider (&from.f, &to.f);
4011debfc3dSmrg return to.c;
4021debfc3dSmrg }
4031debfc3dSmrg #endif
4041debfc3dSmrg
4051debfc3dSmrg #if defined (L_dd_to_sd)
4061debfc3dSmrg /* Use decNumber to convert directly from _Decimal64 to _Decimal32. */
4071debfc3dSmrg _Decimal32
DFP_TO_DFP(_Decimal64 f_from)4081debfc3dSmrg DFP_TO_DFP (_Decimal64 f_from)
4091debfc3dSmrg {
4101debfc3dSmrg union { _Decimal32 c; decSingle f; } to;
4111debfc3dSmrg union { _Decimal64 c; decDouble f; } from;
4121debfc3dSmrg decContext context;
4131debfc3dSmrg
4141debfc3dSmrg decContextDefault (&context, CONTEXT_INIT);
4151debfc3dSmrg DFP_INIT_ROUNDMODE (context.round);
4161debfc3dSmrg from.c = f_from;
4171debfc3dSmrg to.f = *decSingleFromWider (&to.f, &from.f, &context);
4181debfc3dSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
4191debfc3dSmrg dfp_conversion_exceptions (context.status);
4201debfc3dSmrg return to.c;
4211debfc3dSmrg }
4221debfc3dSmrg #endif
4231debfc3dSmrg
4241debfc3dSmrg #if defined (L_td_to_sd)
4251debfc3dSmrg /* Use decNumber to convert directly from _Decimal128 to _Decimal32. */
4261debfc3dSmrg _Decimal32
DFP_TO_DFP(_Decimal128 f_from)4271debfc3dSmrg DFP_TO_DFP (_Decimal128 f_from)
4281debfc3dSmrg {
4291debfc3dSmrg union { _Decimal32 c; decSingle f; } to;
4301debfc3dSmrg union { _Decimal128 c; decQuad f; } from;
4311debfc3dSmrg decDouble temp;
4321debfc3dSmrg decContext context;
4331debfc3dSmrg
4341debfc3dSmrg decContextDefault (&context, CONTEXT_INIT);
4351debfc3dSmrg DFP_INIT_ROUNDMODE (context.round);
4361debfc3dSmrg from.c = f_from;
4371debfc3dSmrg temp = *decDoubleFromWider (&temp, &from.f, &context);
4381debfc3dSmrg to.f = *decSingleFromWider (&to.f, &temp, &context);
4391debfc3dSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
4401debfc3dSmrg dfp_conversion_exceptions (context.status);
4411debfc3dSmrg return to.c;
4421debfc3dSmrg }
4431debfc3dSmrg #endif
4441debfc3dSmrg
4451debfc3dSmrg #if defined (L_td_to_dd)
4461debfc3dSmrg /* Use decNumber to convert directly from _Decimal128 to _Decimal64. */
4471debfc3dSmrg _Decimal64
DFP_TO_DFP(_Decimal128 f_from)4481debfc3dSmrg DFP_TO_DFP (_Decimal128 f_from)
4491debfc3dSmrg {
4501debfc3dSmrg union { _Decimal64 c; decDouble f; } to;
4511debfc3dSmrg union { _Decimal128 c; decQuad f; } from;
4521debfc3dSmrg decContext context;
4531debfc3dSmrg
4541debfc3dSmrg decContextDefault (&context, CONTEXT_INIT);
4551debfc3dSmrg DFP_INIT_ROUNDMODE (context.round);
4561debfc3dSmrg from.c = f_from;
4571debfc3dSmrg to.f = *decDoubleFromWider (&to.f, &from.f, &context);
4581debfc3dSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
4591debfc3dSmrg dfp_conversion_exceptions (context.status);
4601debfc3dSmrg return to.c;
4611debfc3dSmrg }
4621debfc3dSmrg #endif
4631debfc3dSmrg
4641debfc3dSmrg #if defined (L_dd_to_si) || defined (L_td_to_si) \
4651debfc3dSmrg || defined (L_dd_to_usi) || defined (L_td_to_usi)
4661debfc3dSmrg /* Use decNumber to convert directly from decimal float to integer types. */
4671debfc3dSmrg INT_TYPE
DFP_TO_INT(DFP_C_TYPE x)4681debfc3dSmrg DFP_TO_INT (DFP_C_TYPE x)
4691debfc3dSmrg {
4701debfc3dSmrg union { DFP_C_TYPE c; decFloat f; } u;
4711debfc3dSmrg decContext context;
4721debfc3dSmrg INT_TYPE i;
4731debfc3dSmrg
4741debfc3dSmrg decContextDefault (&context, DEC_INIT_DECIMAL128);
4751debfc3dSmrg context.round = DEC_ROUND_DOWN;
4761debfc3dSmrg u.c = x;
4771debfc3dSmrg i = DEC_FLOAT_TO_INT (&u.f, &context, context.round);
4781debfc3dSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
4791debfc3dSmrg dfp_conversion_exceptions (context.status);
4801debfc3dSmrg return i;
4811debfc3dSmrg }
4821debfc3dSmrg #endif
4831debfc3dSmrg
4841debfc3dSmrg #if defined (L_sd_to_si) || (L_sd_to_usi)
4851debfc3dSmrg /* Use decNumber to convert directly from decimal float to integer types. */
4861debfc3dSmrg INT_TYPE
DFP_TO_INT(_Decimal32 x)4871debfc3dSmrg DFP_TO_INT (_Decimal32 x)
4881debfc3dSmrg {
4891debfc3dSmrg union { _Decimal32 c; decSingle f; } u32;
4901debfc3dSmrg decDouble f64;
4911debfc3dSmrg decContext context;
4921debfc3dSmrg INT_TYPE i;
4931debfc3dSmrg
4941debfc3dSmrg decContextDefault (&context, DEC_INIT_DECIMAL128);
4951debfc3dSmrg context.round = DEC_ROUND_DOWN;
4961debfc3dSmrg u32.c = x;
4971debfc3dSmrg f64 = *decSingleToWider (&u32.f, &f64);
4981debfc3dSmrg i = DEC_FLOAT_TO_INT (&f64, &context, context.round);
4991debfc3dSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
5001debfc3dSmrg dfp_conversion_exceptions (context.status);
5011debfc3dSmrg return i;
5021debfc3dSmrg }
5031debfc3dSmrg #endif
5041debfc3dSmrg
5051debfc3dSmrg #if defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) \
5061debfc3dSmrg || defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi)
5071debfc3dSmrg /* decNumber doesn't provide support for conversions to 64-bit integer
5081debfc3dSmrg types, so do it the hard way. */
5091debfc3dSmrg INT_TYPE
DFP_TO_INT(DFP_C_TYPE x)5101debfc3dSmrg DFP_TO_INT (DFP_C_TYPE x)
5111debfc3dSmrg {
5121debfc3dSmrg /* decNumber's decimal* types have the same format as C's _Decimal*
5131debfc3dSmrg types, but they have different calling conventions. */
5141debfc3dSmrg
5151debfc3dSmrg /* TODO: Decimal float to integer conversions should raise FE_INVALID
5161debfc3dSmrg if the result value does not fit into the result type. */
5171debfc3dSmrg
5181debfc3dSmrg IEEE_TYPE s;
5191debfc3dSmrg char buf[BUFMAX];
5201debfc3dSmrg char *pos;
5211debfc3dSmrg decNumber qval, n1, n2;
5221debfc3dSmrg decContext context;
5231debfc3dSmrg
5241debfc3dSmrg /* Use a large context to avoid losing precision. */
5251debfc3dSmrg decContextDefault (&context, DEC_INIT_DECIMAL128);
5261debfc3dSmrg /* Need non-default rounding mode here. */
5271debfc3dSmrg context.round = DEC_ROUND_DOWN;
5281debfc3dSmrg
5291debfc3dSmrg HOST_TO_IEEE (x, &s);
5301debfc3dSmrg TO_INTERNAL (&s, &n1);
5311debfc3dSmrg /* Rescale if the exponent is less than zero. */
5321debfc3dSmrg decNumberToIntegralValue (&n2, &n1, &context);
5331debfc3dSmrg /* Get a value to use for the quantize call. */
5341debfc3dSmrg decNumberFromString (&qval, "1.", &context);
5351debfc3dSmrg /* Force the exponent to zero. */
5361debfc3dSmrg decNumberQuantize (&n1, &n2, &qval, &context);
5371debfc3dSmrg /* Get a string, which at this point will not include an exponent. */
5381debfc3dSmrg decNumberToString (&n1, buf);
5391debfc3dSmrg /* Ignore the fractional part. */
5401debfc3dSmrg pos = strchr (buf, '.');
5411debfc3dSmrg if (pos)
5421debfc3dSmrg *pos = 0;
5431debfc3dSmrg /* Use a C library function to convert to the integral type. */
5441debfc3dSmrg return STR_TO_INT (buf, NULL, 10);
5451debfc3dSmrg }
5461debfc3dSmrg #endif
5471debfc3dSmrg
5481debfc3dSmrg #if defined (L_si_to_dd) || defined (L_si_to_td) \
5491debfc3dSmrg || defined (L_usi_to_dd) || defined (L_usi_to_td)
5501debfc3dSmrg /* Use decNumber to convert directly from integer to decimal float types. */
5511debfc3dSmrg DFP_C_TYPE
INT_TO_DFP(INT_TYPE i)5521debfc3dSmrg INT_TO_DFP (INT_TYPE i)
5531debfc3dSmrg {
5541debfc3dSmrg union { DFP_C_TYPE c; decFloat f; } u;
5551debfc3dSmrg
5561debfc3dSmrg u.f = *DEC_FLOAT_FROM_INT (&u.f, i);
5571debfc3dSmrg return u.c;
5581debfc3dSmrg }
5591debfc3dSmrg #endif
5601debfc3dSmrg
5611debfc3dSmrg #if defined (L_si_to_sd) || defined (L_usi_to_sd)
5621debfc3dSmrg _Decimal32
5631debfc3dSmrg /* Use decNumber to convert directly from integer to decimal float types. */
INT_TO_DFP(INT_TYPE i)5641debfc3dSmrg INT_TO_DFP (INT_TYPE i)
5651debfc3dSmrg {
5661debfc3dSmrg union { _Decimal32 c; decSingle f; } u32;
5671debfc3dSmrg decDouble f64;
5681debfc3dSmrg decContext context;
5691debfc3dSmrg
5701debfc3dSmrg decContextDefault (&context, DEC_INIT_DECIMAL128);
5711debfc3dSmrg f64 = *DEC_FLOAT_FROM_INT (&f64, i);
5721debfc3dSmrg u32.f = *decSingleFromWider (&u32.f, &f64, &context);
5731debfc3dSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
5741debfc3dSmrg dfp_conversion_exceptions (context.status);
5751debfc3dSmrg return u32.c;
5761debfc3dSmrg }
5771debfc3dSmrg #endif
5781debfc3dSmrg
5791debfc3dSmrg #if defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \
5801debfc3dSmrg || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td)
5811debfc3dSmrg /* decNumber doesn't provide support for conversions from 64-bit integer
5821debfc3dSmrg types, so do it the hard way. */
5831debfc3dSmrg DFP_C_TYPE
INT_TO_DFP(INT_TYPE i)5841debfc3dSmrg INT_TO_DFP (INT_TYPE i)
5851debfc3dSmrg {
5861debfc3dSmrg DFP_C_TYPE f;
5871debfc3dSmrg IEEE_TYPE s;
5881debfc3dSmrg char buf[BUFMAX];
5891debfc3dSmrg decContext context;
5901debfc3dSmrg
5911debfc3dSmrg decContextDefault (&context, CONTEXT_INIT);
5921debfc3dSmrg DFP_INIT_ROUNDMODE (context.round);
5931debfc3dSmrg
5941debfc3dSmrg /* Use a C library function to get a floating point string. */
5951debfc3dSmrg sprintf (buf, INT_FMT ".", CAST_FOR_FMT(i));
5961debfc3dSmrg /* Convert from the floating point string to a decimal* type. */
5971debfc3dSmrg FROM_STRING (&s, buf, &context);
5981debfc3dSmrg IEEE_TO_HOST (s, &f);
5991debfc3dSmrg
6001debfc3dSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
6011debfc3dSmrg dfp_conversion_exceptions (context.status);
6021debfc3dSmrg
6031debfc3dSmrg return f;
6041debfc3dSmrg }
6051debfc3dSmrg #endif
6061debfc3dSmrg
6071debfc3dSmrg #if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \
6081debfc3dSmrg || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \
6091debfc3dSmrg || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \
6101debfc3dSmrg && LONG_DOUBLE_HAS_XF_MODE) \
6111debfc3dSmrg || ((defined (L_sd_to_tf) || defined (L_dd_to_tf) || defined (L_td_to_tf)) \
6121debfc3dSmrg && LONG_DOUBLE_HAS_TF_MODE)
6131debfc3dSmrg BFP_TYPE
DFP_TO_BFP(DFP_C_TYPE f)6141debfc3dSmrg DFP_TO_BFP (DFP_C_TYPE f)
6151debfc3dSmrg {
6161debfc3dSmrg IEEE_TYPE s;
6171debfc3dSmrg char buf[BUFMAX];
6181debfc3dSmrg
6191debfc3dSmrg HOST_TO_IEEE (f, &s);
6201debfc3dSmrg /* Write the value to a string. */
6211debfc3dSmrg TO_STRING (&s, buf);
6221debfc3dSmrg /* Read it as the binary floating point type and return that. */
6231debfc3dSmrg return STR_TO_BFP (buf, NULL);
6241debfc3dSmrg }
6251debfc3dSmrg #endif
6261debfc3dSmrg
6271debfc3dSmrg #if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \
6281debfc3dSmrg || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \
6291debfc3dSmrg || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \
6301debfc3dSmrg && LONG_DOUBLE_HAS_XF_MODE) \
6311debfc3dSmrg || ((defined (L_tf_to_sd) || defined (L_tf_to_dd) || defined (L_tf_to_td)) \
6321debfc3dSmrg && LONG_DOUBLE_HAS_TF_MODE)
6331debfc3dSmrg DFP_C_TYPE
BFP_TO_DFP(BFP_TYPE x)6341debfc3dSmrg BFP_TO_DFP (BFP_TYPE x)
6351debfc3dSmrg {
6361debfc3dSmrg DFP_C_TYPE f;
6371debfc3dSmrg IEEE_TYPE s;
6381debfc3dSmrg char buf[BUFMAX];
6391debfc3dSmrg decContext context;
6401debfc3dSmrg
6411debfc3dSmrg decContextDefault (&context, CONTEXT_INIT);
6421debfc3dSmrg DFP_INIT_ROUNDMODE (context.round);
6431debfc3dSmrg
6441debfc3dSmrg /* Use a C library function to write the floating point value to a string. */
6451debfc3dSmrg sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
6461debfc3dSmrg
6471debfc3dSmrg /* Convert from the floating point string to a decimal* type. */
6481debfc3dSmrg FROM_STRING (&s, buf, &context);
6491debfc3dSmrg IEEE_TO_HOST (s, &f);
6501debfc3dSmrg
6511debfc3dSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
6521debfc3dSmrg {
6531debfc3dSmrg /* decNumber exception flags we care about here. */
6541debfc3dSmrg int ieee_flags;
6551debfc3dSmrg int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Invalid_operation
6561debfc3dSmrg | DEC_IEEE_854_Overflow | DEC_IEEE_854_Underflow;
6571debfc3dSmrg dec_flags &= context.status;
6581debfc3dSmrg ieee_flags = DFP_IEEE_FLAGS (dec_flags);
6591debfc3dSmrg if (ieee_flags != 0)
6601debfc3dSmrg DFP_HANDLE_EXCEPTIONS (ieee_flags);
6611debfc3dSmrg }
6621debfc3dSmrg
6631debfc3dSmrg return f;
6641debfc3dSmrg }
6651debfc3dSmrg #endif
6661debfc3dSmrg
6671debfc3dSmrg #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
6681debfc3dSmrg CMPtype
DFP_UNORD(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)6691debfc3dSmrg DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
6701debfc3dSmrg {
6711debfc3dSmrg decNumber arg1, arg2;
6721debfc3dSmrg IEEE_TYPE a, b;
6731debfc3dSmrg
6741debfc3dSmrg HOST_TO_IEEE (arg_a, &a);
6751debfc3dSmrg HOST_TO_IEEE (arg_b, &b);
6761debfc3dSmrg TO_INTERNAL (&a, &arg1);
6771debfc3dSmrg TO_INTERNAL (&b, &arg2);
6781debfc3dSmrg return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2));
6791debfc3dSmrg }
6801debfc3dSmrg #endif /* L_unord_sd || L_unord_dd || L_unord_td */
681