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