148fb7bfaSmrg /* This is a software decimal floating point library.
2*b1e83836Smrg Copyright (C) 2005-2022 Free Software Foundation, Inc.
348fb7bfaSmrg
448fb7bfaSmrg This file is part of GCC.
548fb7bfaSmrg
648fb7bfaSmrg GCC is free software; you can redistribute it and/or modify it under
748fb7bfaSmrg the terms of the GNU General Public License as published by the Free
848fb7bfaSmrg Software Foundation; either version 3, or (at your option) any later
948fb7bfaSmrg version.
1048fb7bfaSmrg
1148fb7bfaSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1248fb7bfaSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
1348fb7bfaSmrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1448fb7bfaSmrg for more details.
1548fb7bfaSmrg
1648fb7bfaSmrg Under Section 7 of GPL version 3, you are granted additional
1748fb7bfaSmrg permissions described in the GCC Runtime Library Exception, version
1848fb7bfaSmrg 3.1, as published by the Free Software Foundation.
1948fb7bfaSmrg
2048fb7bfaSmrg You should have received a copy of the GNU General Public License and
2148fb7bfaSmrg a copy of the GCC Runtime Library Exception along with this program;
2248fb7bfaSmrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
2348fb7bfaSmrg <http://www.gnu.org/licenses/>. */
2448fb7bfaSmrg
2548fb7bfaSmrg /* This implements IEEE 754 decimal floating point arithmetic, but
2648fb7bfaSmrg does not provide a mechanism for setting the rounding mode, or for
2748fb7bfaSmrg generating or handling exceptions. Conversions between decimal
2848fb7bfaSmrg floating point types and other types depend on C library functions.
2948fb7bfaSmrg
3048fb7bfaSmrg Contributed by Ben Elliston <bje@au.ibm.com>. */
3148fb7bfaSmrg
3248fb7bfaSmrg #include <stdio.h>
3348fb7bfaSmrg #include <stdlib.h>
3448fb7bfaSmrg /* FIXME: compile with -std=gnu99 to get these from stdlib.h */
3548fb7bfaSmrg extern float strtof (const char *, char **);
3648fb7bfaSmrg extern long double strtold (const char *, char **);
3748fb7bfaSmrg #include <string.h>
3848fb7bfaSmrg #include <limits.h>
3948fb7bfaSmrg
4048fb7bfaSmrg #include "dfp-bit.h"
4148fb7bfaSmrg
4248fb7bfaSmrg /* Forward declarations. */
4348fb7bfaSmrg #if WIDTH == 32 || WIDTH_TO == 32
4448fb7bfaSmrg void __host_to_ieee_32 (_Decimal32 in, decimal32 *out);
4548fb7bfaSmrg void __ieee_to_host_32 (decimal32 in, _Decimal32 *out);
4648fb7bfaSmrg #endif
4748fb7bfaSmrg #if WIDTH == 64 || WIDTH_TO == 64
4848fb7bfaSmrg void __host_to_ieee_64 (_Decimal64 in, decimal64 *out);
4948fb7bfaSmrg void __ieee_to_host_64 (decimal64 in, _Decimal64 *out);
5048fb7bfaSmrg #endif
5148fb7bfaSmrg #if WIDTH == 128 || WIDTH_TO == 128
5248fb7bfaSmrg void __host_to_ieee_128 (_Decimal128 in, decimal128 *out);
5348fb7bfaSmrg void __ieee_to_host_128 (decimal128 in, _Decimal128 *out);
5448fb7bfaSmrg #endif
5548fb7bfaSmrg
5648fb7bfaSmrg /* A pointer to a binary decFloat operation. */
5748fb7bfaSmrg typedef decFloat* (*dfp_binary_func)
5848fb7bfaSmrg (decFloat *, const decFloat *, const decFloat *, decContext *);
5948fb7bfaSmrg
6048fb7bfaSmrg /* Binary operations. */
6148fb7bfaSmrg
6248fb7bfaSmrg /* Use a decFloat (decDouble or decQuad) function to perform a DFP
6348fb7bfaSmrg binary operation. */
6448fb7bfaSmrg static inline decFloat
dfp_binary_op(dfp_binary_func op,decFloat arg_a,decFloat arg_b)6548fb7bfaSmrg dfp_binary_op (dfp_binary_func op, decFloat arg_a, decFloat arg_b)
6648fb7bfaSmrg {
6748fb7bfaSmrg decFloat result;
6848fb7bfaSmrg decContext context;
6948fb7bfaSmrg
7048fb7bfaSmrg decContextDefault (&context, CONTEXT_INIT);
7148fb7bfaSmrg DFP_INIT_ROUNDMODE (context.round);
7248fb7bfaSmrg
7348fb7bfaSmrg /* Perform the operation. */
7448fb7bfaSmrg op (&result, &arg_a, &arg_b, &context);
7548fb7bfaSmrg
7648fb7bfaSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
7748fb7bfaSmrg {
7848fb7bfaSmrg /* decNumber exception flags we care about here. */
7948fb7bfaSmrg int ieee_flags;
8048fb7bfaSmrg int dec_flags = DEC_IEEE_854_Division_by_zero | DEC_IEEE_854_Inexact
8148fb7bfaSmrg | DEC_IEEE_854_Invalid_operation | DEC_IEEE_854_Overflow
8248fb7bfaSmrg | DEC_IEEE_854_Underflow;
8348fb7bfaSmrg dec_flags &= context.status;
8448fb7bfaSmrg ieee_flags = DFP_IEEE_FLAGS (dec_flags);
8548fb7bfaSmrg if (ieee_flags != 0)
8648fb7bfaSmrg DFP_HANDLE_EXCEPTIONS (ieee_flags);
8748fb7bfaSmrg }
8848fb7bfaSmrg
8948fb7bfaSmrg return result;
9048fb7bfaSmrg }
9148fb7bfaSmrg
9248fb7bfaSmrg #if WIDTH == 32
9348fb7bfaSmrg /* The decNumber package doesn't provide arithmetic for decSingle (32 bits);
9448fb7bfaSmrg convert to decDouble, use the operation for that, and convert back. */
9548fb7bfaSmrg static inline _Decimal32
d32_binary_op(dfp_binary_func op,_Decimal32 arg_a,_Decimal32 arg_b)9648fb7bfaSmrg d32_binary_op (dfp_binary_func op, _Decimal32 arg_a, _Decimal32 arg_b)
9748fb7bfaSmrg {
9848fb7bfaSmrg union { _Decimal32 c; decSingle f; } a32, b32, res32;
9948fb7bfaSmrg decDouble a, b, res;
10048fb7bfaSmrg decContext context;
10148fb7bfaSmrg
10248fb7bfaSmrg /* Widen the operands and perform the operation. */
10348fb7bfaSmrg a32.c = arg_a;
10448fb7bfaSmrg b32.c = arg_b;
10548fb7bfaSmrg decSingleToWider (&a32.f, &a);
10648fb7bfaSmrg decSingleToWider (&b32.f, &b);
10748fb7bfaSmrg res = dfp_binary_op (op, a, b);
10848fb7bfaSmrg
10948fb7bfaSmrg /* Narrow the result, which might result in an underflow or overflow. */
11048fb7bfaSmrg decContextDefault (&context, CONTEXT_INIT);
11148fb7bfaSmrg DFP_INIT_ROUNDMODE (context.round);
11248fb7bfaSmrg decSingleFromWider (&res32.f, &res, &context);
11348fb7bfaSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
11448fb7bfaSmrg {
11548fb7bfaSmrg /* decNumber exception flags we care about here. */
11648fb7bfaSmrg int ieee_flags;
11748fb7bfaSmrg int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Overflow
11848fb7bfaSmrg | DEC_IEEE_854_Underflow;
11948fb7bfaSmrg dec_flags &= context.status;
12048fb7bfaSmrg ieee_flags = DFP_IEEE_FLAGS (dec_flags);
12148fb7bfaSmrg if (ieee_flags != 0)
12248fb7bfaSmrg DFP_HANDLE_EXCEPTIONS (ieee_flags);
12348fb7bfaSmrg }
12448fb7bfaSmrg
12548fb7bfaSmrg return res32.c;
12648fb7bfaSmrg }
12748fb7bfaSmrg #else
12848fb7bfaSmrg /* decFloat operations are supported for decDouble (64 bits) and
12948fb7bfaSmrg decQuad (128 bits). The bit patterns for the types are the same. */
13048fb7bfaSmrg static inline DFP_C_TYPE
dnn_binary_op(dfp_binary_func op,DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)13148fb7bfaSmrg dnn_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
13248fb7bfaSmrg {
13348fb7bfaSmrg union { DFP_C_TYPE c; decFloat f; } a, b, result;
13448fb7bfaSmrg
13548fb7bfaSmrg a.c = arg_a;
13648fb7bfaSmrg b.c = arg_b;
13748fb7bfaSmrg result.f = dfp_binary_op (op, a.f, b.f);
13848fb7bfaSmrg return result.c;
13948fb7bfaSmrg }
14048fb7bfaSmrg #endif
14148fb7bfaSmrg
14248fb7bfaSmrg /* Comparison operations. */
14348fb7bfaSmrg
14448fb7bfaSmrg /* Use a decFloat (decDouble or decQuad) function to perform a DFP
14548fb7bfaSmrg comparison. */
14648fb7bfaSmrg static inline CMPtype
dfp_compare_op(dfp_binary_func op,decFloat arg_a,decFloat arg_b)14748fb7bfaSmrg dfp_compare_op (dfp_binary_func op, decFloat arg_a, decFloat arg_b)
14848fb7bfaSmrg {
14948fb7bfaSmrg decContext context;
15048fb7bfaSmrg decFloat res;
15148fb7bfaSmrg int result;
15248fb7bfaSmrg
15348fb7bfaSmrg decContextDefault (&context, CONTEXT_INIT);
15448fb7bfaSmrg DFP_INIT_ROUNDMODE (context.round);
15548fb7bfaSmrg
15648fb7bfaSmrg /* Perform the comparison. */
15748fb7bfaSmrg op (&res, &arg_a, &arg_b, &context);
15848fb7bfaSmrg
15948fb7bfaSmrg if (DEC_FLOAT_IS_SIGNED (&res))
16048fb7bfaSmrg result = -1;
16148fb7bfaSmrg else if (DEC_FLOAT_IS_ZERO (&res))
16248fb7bfaSmrg result = 0;
16348fb7bfaSmrg else if (DEC_FLOAT_IS_NAN (&res))
16448fb7bfaSmrg result = -2;
16548fb7bfaSmrg else
16648fb7bfaSmrg result = 1;
16748fb7bfaSmrg
16848fb7bfaSmrg return (CMPtype) result;
16948fb7bfaSmrg }
17048fb7bfaSmrg
17148fb7bfaSmrg #if WIDTH == 32
17248fb7bfaSmrg /* The decNumber package doesn't provide comparisons for decSingle (32 bits);
17348fb7bfaSmrg convert to decDouble, use the operation for that, and convert back. */
17448fb7bfaSmrg static inline CMPtype
d32_compare_op(dfp_binary_func op,_Decimal32 arg_a,_Decimal32 arg_b)17548fb7bfaSmrg d32_compare_op (dfp_binary_func op, _Decimal32 arg_a, _Decimal32 arg_b)
17648fb7bfaSmrg {
17748fb7bfaSmrg union { _Decimal32 c; decSingle f; } a32, b32;
17848fb7bfaSmrg decDouble a, b;
17948fb7bfaSmrg
18048fb7bfaSmrg a32.c = arg_a;
18148fb7bfaSmrg b32.c = arg_b;
18248fb7bfaSmrg decSingleToWider (&a32.f, &a);
18348fb7bfaSmrg decSingleToWider (&b32.f, &b);
18448fb7bfaSmrg return dfp_compare_op (op, a, b);
18548fb7bfaSmrg }
18648fb7bfaSmrg #else
18748fb7bfaSmrg /* decFloat comparisons are supported for decDouble (64 bits) and
18848fb7bfaSmrg decQuad (128 bits). The bit patterns for the types are the same. */
18948fb7bfaSmrg static inline CMPtype
dnn_compare_op(dfp_binary_func op,DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)19048fb7bfaSmrg dnn_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
19148fb7bfaSmrg {
19248fb7bfaSmrg union { DFP_C_TYPE c; decFloat f; } a, b;
19348fb7bfaSmrg
19448fb7bfaSmrg a.c = arg_a;
19548fb7bfaSmrg b.c = arg_b;
19648fb7bfaSmrg return dfp_compare_op (op, a.f, b.f);
19748fb7bfaSmrg }
19848fb7bfaSmrg #endif
19948fb7bfaSmrg
20048fb7bfaSmrg #if defined(L_conv_sd)
20148fb7bfaSmrg void
__host_to_ieee_32(_Decimal32 in,decimal32 * out)20248fb7bfaSmrg __host_to_ieee_32 (_Decimal32 in, decimal32 *out)
20348fb7bfaSmrg {
20448fb7bfaSmrg memcpy (out, &in, 4);
20548fb7bfaSmrg }
20648fb7bfaSmrg
20748fb7bfaSmrg void
__ieee_to_host_32(decimal32 in,_Decimal32 * out)20848fb7bfaSmrg __ieee_to_host_32 (decimal32 in, _Decimal32 *out)
20948fb7bfaSmrg {
21048fb7bfaSmrg memcpy (out, &in, 4);
21148fb7bfaSmrg }
21248fb7bfaSmrg #endif /* L_conv_sd */
21348fb7bfaSmrg
21448fb7bfaSmrg #if defined(L_conv_dd)
21548fb7bfaSmrg void
__host_to_ieee_64(_Decimal64 in,decimal64 * out)21648fb7bfaSmrg __host_to_ieee_64 (_Decimal64 in, decimal64 *out)
21748fb7bfaSmrg {
21848fb7bfaSmrg memcpy (out, &in, 8);
21948fb7bfaSmrg }
22048fb7bfaSmrg
22148fb7bfaSmrg void
__ieee_to_host_64(decimal64 in,_Decimal64 * out)22248fb7bfaSmrg __ieee_to_host_64 (decimal64 in, _Decimal64 *out)
22348fb7bfaSmrg {
22448fb7bfaSmrg memcpy (out, &in, 8);
22548fb7bfaSmrg }
22648fb7bfaSmrg #endif /* L_conv_dd */
22748fb7bfaSmrg
22848fb7bfaSmrg #if defined(L_conv_td)
22948fb7bfaSmrg void
__host_to_ieee_128(_Decimal128 in,decimal128 * out)23048fb7bfaSmrg __host_to_ieee_128 (_Decimal128 in, decimal128 *out)
23148fb7bfaSmrg {
23248fb7bfaSmrg memcpy (out, &in, 16);
23348fb7bfaSmrg }
23448fb7bfaSmrg
23548fb7bfaSmrg void
__ieee_to_host_128(decimal128 in,_Decimal128 * out)23648fb7bfaSmrg __ieee_to_host_128 (decimal128 in, _Decimal128 *out)
23748fb7bfaSmrg {
23848fb7bfaSmrg memcpy (out, &in, 16);
23948fb7bfaSmrg }
24048fb7bfaSmrg #endif /* L_conv_td */
24148fb7bfaSmrg
24248fb7bfaSmrg #if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td)
24348fb7bfaSmrg DFP_C_TYPE
DFP_ADD(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)24448fb7bfaSmrg DFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
24548fb7bfaSmrg {
24648fb7bfaSmrg return DFP_BINARY_OP (DEC_FLOAT_ADD, arg_a, arg_b);
24748fb7bfaSmrg }
24848fb7bfaSmrg
24948fb7bfaSmrg DFP_C_TYPE
DFP_SUB(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)25048fb7bfaSmrg DFP_SUB (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
25148fb7bfaSmrg {
25248fb7bfaSmrg return DFP_BINARY_OP (DEC_FLOAT_SUBTRACT, arg_a, arg_b);
25348fb7bfaSmrg }
25448fb7bfaSmrg #endif /* L_addsub */
25548fb7bfaSmrg
25648fb7bfaSmrg #if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td)
25748fb7bfaSmrg DFP_C_TYPE
DFP_MULTIPLY(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)25848fb7bfaSmrg DFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
25948fb7bfaSmrg {
26048fb7bfaSmrg return DFP_BINARY_OP (DEC_FLOAT_MULTIPLY, arg_a, arg_b);
26148fb7bfaSmrg }
26248fb7bfaSmrg #endif /* L_mul */
26348fb7bfaSmrg
26448fb7bfaSmrg #if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td)
26548fb7bfaSmrg DFP_C_TYPE
DFP_DIVIDE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)26648fb7bfaSmrg DFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
26748fb7bfaSmrg {
26848fb7bfaSmrg return DFP_BINARY_OP (DEC_FLOAT_DIVIDE, arg_a, arg_b);
26948fb7bfaSmrg }
27048fb7bfaSmrg #endif /* L_div */
27148fb7bfaSmrg
27248fb7bfaSmrg #if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td)
27348fb7bfaSmrg CMPtype
DFP_EQ(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)27448fb7bfaSmrg DFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
27548fb7bfaSmrg {
27648fb7bfaSmrg CMPtype stat;
27748fb7bfaSmrg stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
27848fb7bfaSmrg /* For EQ return zero for true, nonzero for false. */
27948fb7bfaSmrg return stat != 0;
28048fb7bfaSmrg }
28148fb7bfaSmrg #endif /* L_eq */
28248fb7bfaSmrg
28348fb7bfaSmrg #if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td)
28448fb7bfaSmrg CMPtype
DFP_NE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)28548fb7bfaSmrg DFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
28648fb7bfaSmrg {
28748fb7bfaSmrg int stat;
28848fb7bfaSmrg stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
28948fb7bfaSmrg /* For NE return zero for true, nonzero for false. */
29048fb7bfaSmrg if (__builtin_expect (stat == -2, 0)) /* An operand is NaN. */
29148fb7bfaSmrg return 1;
29248fb7bfaSmrg return stat != 0;
29348fb7bfaSmrg }
29448fb7bfaSmrg #endif /* L_ne */
29548fb7bfaSmrg
29648fb7bfaSmrg #if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td)
29748fb7bfaSmrg CMPtype
DFP_LT(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)29848fb7bfaSmrg DFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
29948fb7bfaSmrg {
30048fb7bfaSmrg int stat;
30148fb7bfaSmrg stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
30248fb7bfaSmrg /* For LT return -1 (<0) for true, 1 for false. */
30348fb7bfaSmrg return (stat == -1) ? -1 : 1;
30448fb7bfaSmrg }
30548fb7bfaSmrg #endif /* L_lt */
30648fb7bfaSmrg
30748fb7bfaSmrg #if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td)
30848fb7bfaSmrg CMPtype
DFP_GT(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)30948fb7bfaSmrg DFP_GT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
31048fb7bfaSmrg {
31148fb7bfaSmrg int stat;
31248fb7bfaSmrg stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
31348fb7bfaSmrg /* For GT return 1 (>0) for true, -1 for false. */
31448fb7bfaSmrg return (stat == 1) ? 1 : -1;
31548fb7bfaSmrg }
31648fb7bfaSmrg #endif
31748fb7bfaSmrg
31848fb7bfaSmrg #if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td)
31948fb7bfaSmrg CMPtype
DFP_LE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)32048fb7bfaSmrg DFP_LE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
32148fb7bfaSmrg {
32248fb7bfaSmrg int stat;
32348fb7bfaSmrg stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
32448fb7bfaSmrg /* For LE return 0 (<= 0) for true, 1 for false. */
32548fb7bfaSmrg if (__builtin_expect (stat == -2, 0)) /* An operand is NaN. */
32648fb7bfaSmrg return 1;
32748fb7bfaSmrg return stat == 1;
32848fb7bfaSmrg }
32948fb7bfaSmrg #endif /* L_le */
33048fb7bfaSmrg
33148fb7bfaSmrg #if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td)
33248fb7bfaSmrg CMPtype
DFP_GE(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)33348fb7bfaSmrg DFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
33448fb7bfaSmrg {
33548fb7bfaSmrg int stat;
33648fb7bfaSmrg stat = DFP_COMPARE_OP (DEC_FLOAT_COMPARE, arg_a, arg_b);
33748fb7bfaSmrg /* For GE return 1 (>=0) for true, -1 for false. */
33848fb7bfaSmrg if (__builtin_expect (stat == -2, 0)) /* An operand is NaN. */
33948fb7bfaSmrg return -1;
34048fb7bfaSmrg return (stat != -1) ? 1 : -1;
34148fb7bfaSmrg }
34248fb7bfaSmrg #endif /* L_ge */
34348fb7bfaSmrg
34448fb7bfaSmrg #define BUFMAX 128
34548fb7bfaSmrg
34648fb7bfaSmrg /* Check for floating point exceptions that are relevant for conversions
34748fb7bfaSmrg between decimal float values and handle them. */
34848fb7bfaSmrg static inline void
dfp_conversion_exceptions(const int status)34948fb7bfaSmrg dfp_conversion_exceptions (const int status)
35048fb7bfaSmrg {
35148fb7bfaSmrg /* decNumber exception flags we care about here. */
35248fb7bfaSmrg int ieee_flags;
35348fb7bfaSmrg int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Invalid_operation
35448fb7bfaSmrg | DEC_IEEE_854_Overflow;
35548fb7bfaSmrg dec_flags &= status;
35648fb7bfaSmrg ieee_flags = DFP_IEEE_FLAGS (dec_flags);
35748fb7bfaSmrg if (ieee_flags != 0)
35848fb7bfaSmrg DFP_HANDLE_EXCEPTIONS (ieee_flags);
35948fb7bfaSmrg }
36048fb7bfaSmrg
36148fb7bfaSmrg #if defined (L_sd_to_dd)
36248fb7bfaSmrg /* Use decNumber to convert directly from _Decimal32 to _Decimal64. */
36348fb7bfaSmrg _Decimal64
DFP_TO_DFP(_Decimal32 f_from)36448fb7bfaSmrg DFP_TO_DFP (_Decimal32 f_from)
36548fb7bfaSmrg {
36648fb7bfaSmrg union { _Decimal32 c; decSingle f; } from;
36748fb7bfaSmrg union { _Decimal64 c; decDouble f; } to;
36848fb7bfaSmrg
36948fb7bfaSmrg from.c = f_from;
37048fb7bfaSmrg to.f = *decSingleToWider (&from.f, &to.f);
37148fb7bfaSmrg return to.c;
37248fb7bfaSmrg }
37348fb7bfaSmrg #endif
37448fb7bfaSmrg
37548fb7bfaSmrg #if defined (L_sd_to_td)
37648fb7bfaSmrg /* Use decNumber to convert directly from _Decimal32 to _Decimal128. */
37748fb7bfaSmrg _Decimal128
DFP_TO_DFP(_Decimal32 f_from)37848fb7bfaSmrg DFP_TO_DFP (_Decimal32 f_from)
37948fb7bfaSmrg {
38048fb7bfaSmrg union { _Decimal32 c; decSingle f; } from;
38148fb7bfaSmrg union { _Decimal128 c; decQuad f; } to;
38248fb7bfaSmrg decDouble temp;
38348fb7bfaSmrg
38448fb7bfaSmrg from.c = f_from;
38548fb7bfaSmrg temp = *decSingleToWider (&from.f, &temp);
38648fb7bfaSmrg to.f = *decDoubleToWider (&temp, &to.f);
38748fb7bfaSmrg return to.c;
38848fb7bfaSmrg }
38948fb7bfaSmrg #endif
39048fb7bfaSmrg
39148fb7bfaSmrg #if defined (L_dd_to_td)
39248fb7bfaSmrg /* Use decNumber to convert directly from _Decimal64 to _Decimal128. */
39348fb7bfaSmrg _Decimal128
DFP_TO_DFP(_Decimal64 f_from)39448fb7bfaSmrg DFP_TO_DFP (_Decimal64 f_from)
39548fb7bfaSmrg {
39648fb7bfaSmrg union { _Decimal64 c; decDouble f; } from;
39748fb7bfaSmrg union { _Decimal128 c; decQuad f; } to;
39848fb7bfaSmrg
39948fb7bfaSmrg from.c = f_from;
40048fb7bfaSmrg to.f = *decDoubleToWider (&from.f, &to.f);
40148fb7bfaSmrg return to.c;
40248fb7bfaSmrg }
40348fb7bfaSmrg #endif
40448fb7bfaSmrg
40548fb7bfaSmrg #if defined (L_dd_to_sd)
40648fb7bfaSmrg /* Use decNumber to convert directly from _Decimal64 to _Decimal32. */
40748fb7bfaSmrg _Decimal32
DFP_TO_DFP(_Decimal64 f_from)40848fb7bfaSmrg DFP_TO_DFP (_Decimal64 f_from)
40948fb7bfaSmrg {
41048fb7bfaSmrg union { _Decimal32 c; decSingle f; } to;
41148fb7bfaSmrg union { _Decimal64 c; decDouble f; } from;
41248fb7bfaSmrg decContext context;
41348fb7bfaSmrg
41448fb7bfaSmrg decContextDefault (&context, CONTEXT_INIT);
41548fb7bfaSmrg DFP_INIT_ROUNDMODE (context.round);
41648fb7bfaSmrg from.c = f_from;
41748fb7bfaSmrg to.f = *decSingleFromWider (&to.f, &from.f, &context);
41848fb7bfaSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
41948fb7bfaSmrg dfp_conversion_exceptions (context.status);
42048fb7bfaSmrg return to.c;
42148fb7bfaSmrg }
42248fb7bfaSmrg #endif
42348fb7bfaSmrg
42448fb7bfaSmrg #if defined (L_td_to_sd)
42548fb7bfaSmrg /* Use decNumber to convert directly from _Decimal128 to _Decimal32. */
42648fb7bfaSmrg _Decimal32
DFP_TO_DFP(_Decimal128 f_from)42748fb7bfaSmrg DFP_TO_DFP (_Decimal128 f_from)
42848fb7bfaSmrg {
42948fb7bfaSmrg union { _Decimal32 c; decSingle f; } to;
43048fb7bfaSmrg union { _Decimal128 c; decQuad f; } from;
43148fb7bfaSmrg decDouble temp;
43248fb7bfaSmrg decContext context;
43348fb7bfaSmrg
43448fb7bfaSmrg decContextDefault (&context, CONTEXT_INIT);
43548fb7bfaSmrg DFP_INIT_ROUNDMODE (context.round);
43648fb7bfaSmrg from.c = f_from;
43748fb7bfaSmrg temp = *decDoubleFromWider (&temp, &from.f, &context);
43848fb7bfaSmrg to.f = *decSingleFromWider (&to.f, &temp, &context);
43948fb7bfaSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
44048fb7bfaSmrg dfp_conversion_exceptions (context.status);
44148fb7bfaSmrg return to.c;
44248fb7bfaSmrg }
44348fb7bfaSmrg #endif
44448fb7bfaSmrg
44548fb7bfaSmrg #if defined (L_td_to_dd)
44648fb7bfaSmrg /* Use decNumber to convert directly from _Decimal128 to _Decimal64. */
44748fb7bfaSmrg _Decimal64
DFP_TO_DFP(_Decimal128 f_from)44848fb7bfaSmrg DFP_TO_DFP (_Decimal128 f_from)
44948fb7bfaSmrg {
45048fb7bfaSmrg union { _Decimal64 c; decDouble f; } to;
45148fb7bfaSmrg union { _Decimal128 c; decQuad f; } from;
45248fb7bfaSmrg decContext context;
45348fb7bfaSmrg
45448fb7bfaSmrg decContextDefault (&context, CONTEXT_INIT);
45548fb7bfaSmrg DFP_INIT_ROUNDMODE (context.round);
45648fb7bfaSmrg from.c = f_from;
45748fb7bfaSmrg to.f = *decDoubleFromWider (&to.f, &from.f, &context);
45848fb7bfaSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
45948fb7bfaSmrg dfp_conversion_exceptions (context.status);
46048fb7bfaSmrg return to.c;
46148fb7bfaSmrg }
46248fb7bfaSmrg #endif
46348fb7bfaSmrg
46448fb7bfaSmrg #if defined (L_dd_to_si) || defined (L_td_to_si) \
46548fb7bfaSmrg || defined (L_dd_to_usi) || defined (L_td_to_usi)
46648fb7bfaSmrg /* Use decNumber to convert directly from decimal float to integer types. */
46748fb7bfaSmrg INT_TYPE
DFP_TO_INT(DFP_C_TYPE x)46848fb7bfaSmrg DFP_TO_INT (DFP_C_TYPE x)
46948fb7bfaSmrg {
47048fb7bfaSmrg union { DFP_C_TYPE c; decFloat f; } u;
47148fb7bfaSmrg decContext context;
47248fb7bfaSmrg INT_TYPE i;
47348fb7bfaSmrg
47448fb7bfaSmrg decContextDefault (&context, DEC_INIT_DECIMAL128);
47548fb7bfaSmrg context.round = DEC_ROUND_DOWN;
47648fb7bfaSmrg u.c = x;
47748fb7bfaSmrg i = DEC_FLOAT_TO_INT (&u.f, &context, context.round);
47848fb7bfaSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
47948fb7bfaSmrg dfp_conversion_exceptions (context.status);
48048fb7bfaSmrg return i;
48148fb7bfaSmrg }
48248fb7bfaSmrg #endif
48348fb7bfaSmrg
48448fb7bfaSmrg #if defined (L_sd_to_si) || (L_sd_to_usi)
48548fb7bfaSmrg /* Use decNumber to convert directly from decimal float to integer types. */
48648fb7bfaSmrg INT_TYPE
DFP_TO_INT(_Decimal32 x)48748fb7bfaSmrg DFP_TO_INT (_Decimal32 x)
48848fb7bfaSmrg {
48948fb7bfaSmrg union { _Decimal32 c; decSingle f; } u32;
49048fb7bfaSmrg decDouble f64;
49148fb7bfaSmrg decContext context;
49248fb7bfaSmrg INT_TYPE i;
49348fb7bfaSmrg
49448fb7bfaSmrg decContextDefault (&context, DEC_INIT_DECIMAL128);
49548fb7bfaSmrg context.round = DEC_ROUND_DOWN;
49648fb7bfaSmrg u32.c = x;
49748fb7bfaSmrg f64 = *decSingleToWider (&u32.f, &f64);
49848fb7bfaSmrg i = DEC_FLOAT_TO_INT (&f64, &context, context.round);
49948fb7bfaSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
50048fb7bfaSmrg dfp_conversion_exceptions (context.status);
50148fb7bfaSmrg return i;
50248fb7bfaSmrg }
50348fb7bfaSmrg #endif
50448fb7bfaSmrg
50548fb7bfaSmrg #if defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) \
50648fb7bfaSmrg || defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi)
50748fb7bfaSmrg /* decNumber doesn't provide support for conversions to 64-bit integer
50848fb7bfaSmrg types, so do it the hard way. */
50948fb7bfaSmrg INT_TYPE
DFP_TO_INT(DFP_C_TYPE x)51048fb7bfaSmrg DFP_TO_INT (DFP_C_TYPE x)
51148fb7bfaSmrg {
51248fb7bfaSmrg /* decNumber's decimal* types have the same format as C's _Decimal*
51348fb7bfaSmrg types, but they have different calling conventions. */
51448fb7bfaSmrg
51548fb7bfaSmrg /* TODO: Decimal float to integer conversions should raise FE_INVALID
51648fb7bfaSmrg if the result value does not fit into the result type. */
51748fb7bfaSmrg
51848fb7bfaSmrg IEEE_TYPE s;
51948fb7bfaSmrg char buf[BUFMAX];
52048fb7bfaSmrg char *pos;
52148fb7bfaSmrg decNumber qval, n1, n2;
52248fb7bfaSmrg decContext context;
52348fb7bfaSmrg
52448fb7bfaSmrg /* Use a large context to avoid losing precision. */
52548fb7bfaSmrg decContextDefault (&context, DEC_INIT_DECIMAL128);
52648fb7bfaSmrg /* Need non-default rounding mode here. */
52748fb7bfaSmrg context.round = DEC_ROUND_DOWN;
52848fb7bfaSmrg
52948fb7bfaSmrg HOST_TO_IEEE (x, &s);
53048fb7bfaSmrg TO_INTERNAL (&s, &n1);
53148fb7bfaSmrg /* Rescale if the exponent is less than zero. */
53248fb7bfaSmrg decNumberToIntegralValue (&n2, &n1, &context);
53348fb7bfaSmrg /* Get a value to use for the quantize call. */
53448fb7bfaSmrg decNumberFromString (&qval, "1.", &context);
53548fb7bfaSmrg /* Force the exponent to zero. */
53648fb7bfaSmrg decNumberQuantize (&n1, &n2, &qval, &context);
53748fb7bfaSmrg /* Get a string, which at this point will not include an exponent. */
53848fb7bfaSmrg decNumberToString (&n1, buf);
53948fb7bfaSmrg /* Ignore the fractional part. */
54048fb7bfaSmrg pos = strchr (buf, '.');
54148fb7bfaSmrg if (pos)
54248fb7bfaSmrg *pos = 0;
54348fb7bfaSmrg /* Use a C library function to convert to the integral type. */
54448fb7bfaSmrg return STR_TO_INT (buf, NULL, 10);
54548fb7bfaSmrg }
54648fb7bfaSmrg #endif
54748fb7bfaSmrg
54848fb7bfaSmrg #if defined (L_si_to_dd) || defined (L_si_to_td) \
54948fb7bfaSmrg || defined (L_usi_to_dd) || defined (L_usi_to_td)
55048fb7bfaSmrg /* Use decNumber to convert directly from integer to decimal float types. */
55148fb7bfaSmrg DFP_C_TYPE
INT_TO_DFP(INT_TYPE i)55248fb7bfaSmrg INT_TO_DFP (INT_TYPE i)
55348fb7bfaSmrg {
55448fb7bfaSmrg union { DFP_C_TYPE c; decFloat f; } u;
55548fb7bfaSmrg
55648fb7bfaSmrg u.f = *DEC_FLOAT_FROM_INT (&u.f, i);
55748fb7bfaSmrg return u.c;
55848fb7bfaSmrg }
55948fb7bfaSmrg #endif
56048fb7bfaSmrg
56148fb7bfaSmrg #if defined (L_si_to_sd) || defined (L_usi_to_sd)
56248fb7bfaSmrg _Decimal32
56348fb7bfaSmrg /* Use decNumber to convert directly from integer to decimal float types. */
INT_TO_DFP(INT_TYPE i)56448fb7bfaSmrg INT_TO_DFP (INT_TYPE i)
56548fb7bfaSmrg {
56648fb7bfaSmrg union { _Decimal32 c; decSingle f; } u32;
56748fb7bfaSmrg decDouble f64;
56848fb7bfaSmrg decContext context;
56948fb7bfaSmrg
57048fb7bfaSmrg decContextDefault (&context, DEC_INIT_DECIMAL128);
57148fb7bfaSmrg f64 = *DEC_FLOAT_FROM_INT (&f64, i);
57248fb7bfaSmrg u32.f = *decSingleFromWider (&u32.f, &f64, &context);
57348fb7bfaSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
57448fb7bfaSmrg dfp_conversion_exceptions (context.status);
57548fb7bfaSmrg return u32.c;
57648fb7bfaSmrg }
57748fb7bfaSmrg #endif
57848fb7bfaSmrg
57948fb7bfaSmrg #if defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \
58048fb7bfaSmrg || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td)
58148fb7bfaSmrg /* decNumber doesn't provide support for conversions from 64-bit integer
58248fb7bfaSmrg types, so do it the hard way. */
58348fb7bfaSmrg DFP_C_TYPE
INT_TO_DFP(INT_TYPE i)58448fb7bfaSmrg INT_TO_DFP (INT_TYPE i)
58548fb7bfaSmrg {
58648fb7bfaSmrg DFP_C_TYPE f;
58748fb7bfaSmrg IEEE_TYPE s;
58848fb7bfaSmrg char buf[BUFMAX];
58948fb7bfaSmrg decContext context;
59048fb7bfaSmrg
59148fb7bfaSmrg decContextDefault (&context, CONTEXT_INIT);
59248fb7bfaSmrg DFP_INIT_ROUNDMODE (context.round);
59348fb7bfaSmrg
59448fb7bfaSmrg /* Use a C library function to get a floating point string. */
59548fb7bfaSmrg sprintf (buf, INT_FMT ".", CAST_FOR_FMT(i));
59648fb7bfaSmrg /* Convert from the floating point string to a decimal* type. */
59748fb7bfaSmrg FROM_STRING (&s, buf, &context);
59848fb7bfaSmrg IEEE_TO_HOST (s, &f);
59948fb7bfaSmrg
60048fb7bfaSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
60148fb7bfaSmrg dfp_conversion_exceptions (context.status);
60248fb7bfaSmrg
60348fb7bfaSmrg return f;
60448fb7bfaSmrg }
60548fb7bfaSmrg #endif
60648fb7bfaSmrg
60748fb7bfaSmrg #if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \
60848fb7bfaSmrg || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \
609*b1e83836Smrg || defined (L_sd_to_kf) || defined (L_dd_to_kf) || defined (L_td_to_kf) \
61048fb7bfaSmrg || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \
61148fb7bfaSmrg && LONG_DOUBLE_HAS_XF_MODE) \
61248fb7bfaSmrg || ((defined (L_sd_to_tf) || defined (L_dd_to_tf) || defined (L_td_to_tf)) \
61348fb7bfaSmrg && LONG_DOUBLE_HAS_TF_MODE)
61448fb7bfaSmrg BFP_TYPE
DFP_TO_BFP(DFP_C_TYPE f)61548fb7bfaSmrg DFP_TO_BFP (DFP_C_TYPE f)
61648fb7bfaSmrg {
61748fb7bfaSmrg IEEE_TYPE s;
61848fb7bfaSmrg char buf[BUFMAX];
61948fb7bfaSmrg
62048fb7bfaSmrg HOST_TO_IEEE (f, &s);
62148fb7bfaSmrg /* Write the value to a string. */
62248fb7bfaSmrg TO_STRING (&s, buf);
62348fb7bfaSmrg /* Read it as the binary floating point type and return that. */
62448fb7bfaSmrg return STR_TO_BFP (buf, NULL);
62548fb7bfaSmrg }
62648fb7bfaSmrg #endif
62748fb7bfaSmrg
62848fb7bfaSmrg #if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \
62948fb7bfaSmrg || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \
630*b1e83836Smrg || defined (L_kf_to_sd) || defined (L_kf_to_dd) || defined (L_kf_to_td) \
63148fb7bfaSmrg || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \
63248fb7bfaSmrg && LONG_DOUBLE_HAS_XF_MODE) \
63348fb7bfaSmrg || ((defined (L_tf_to_sd) || defined (L_tf_to_dd) || defined (L_tf_to_td)) \
63448fb7bfaSmrg && LONG_DOUBLE_HAS_TF_MODE)
63548fb7bfaSmrg DFP_C_TYPE
BFP_TO_DFP(BFP_TYPE x)63648fb7bfaSmrg BFP_TO_DFP (BFP_TYPE x)
63748fb7bfaSmrg {
63848fb7bfaSmrg DFP_C_TYPE f;
63948fb7bfaSmrg IEEE_TYPE s;
64048fb7bfaSmrg char buf[BUFMAX];
64148fb7bfaSmrg decContext context;
64248fb7bfaSmrg
64348fb7bfaSmrg decContextDefault (&context, CONTEXT_INIT);
64448fb7bfaSmrg DFP_INIT_ROUNDMODE (context.round);
64548fb7bfaSmrg
646*b1e83836Smrg /* Use the sprintf library function to write the floating point value to a
647*b1e83836Smrg string.
648*b1e83836Smrg
649*b1e83836Smrg If we are handling the IEEE 128-bit floating point on PowerPC, use the
650*b1e83836Smrg special function __sprintfkf instead of sprintf. This function allows us
651*b1e83836Smrg to use __sprintfieee128 if we have a new enough GLIBC, and it can fall back
652*b1e83836Smrg to using the traditional sprintf via conversion to IBM 128-bit if the glibc
653*b1e83836Smrg is older. */
654*b1e83836Smrg BFP_SPRINTF (buf, BFP_FMT, (BFP_VIA_TYPE) x);
65548fb7bfaSmrg
65648fb7bfaSmrg /* Convert from the floating point string to a decimal* type. */
65748fb7bfaSmrg FROM_STRING (&s, buf, &context);
65848fb7bfaSmrg IEEE_TO_HOST (s, &f);
65948fb7bfaSmrg
66048fb7bfaSmrg if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
66148fb7bfaSmrg {
66248fb7bfaSmrg /* decNumber exception flags we care about here. */
66348fb7bfaSmrg int ieee_flags;
66448fb7bfaSmrg int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Invalid_operation
66548fb7bfaSmrg | DEC_IEEE_854_Overflow | DEC_IEEE_854_Underflow;
66648fb7bfaSmrg dec_flags &= context.status;
66748fb7bfaSmrg ieee_flags = DFP_IEEE_FLAGS (dec_flags);
66848fb7bfaSmrg if (ieee_flags != 0)
66948fb7bfaSmrg DFP_HANDLE_EXCEPTIONS (ieee_flags);
67048fb7bfaSmrg }
67148fb7bfaSmrg
67248fb7bfaSmrg return f;
67348fb7bfaSmrg }
67448fb7bfaSmrg #endif
67548fb7bfaSmrg
67648fb7bfaSmrg #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
67748fb7bfaSmrg CMPtype
DFP_UNORD(DFP_C_TYPE arg_a,DFP_C_TYPE arg_b)67848fb7bfaSmrg DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
67948fb7bfaSmrg {
68048fb7bfaSmrg decNumber arg1, arg2;
68148fb7bfaSmrg IEEE_TYPE a, b;
68248fb7bfaSmrg
68348fb7bfaSmrg HOST_TO_IEEE (arg_a, &a);
68448fb7bfaSmrg HOST_TO_IEEE (arg_b, &b);
68548fb7bfaSmrg TO_INTERNAL (&a, &arg1);
68648fb7bfaSmrg TO_INTERNAL (&b, &arg2);
68748fb7bfaSmrg return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2));
68848fb7bfaSmrg }
68948fb7bfaSmrg #endif /* L_unord_sd || L_unord_dd || L_unord_td */
690