OSDN Git Service

Fix typo in ChangeLog
[pf3gnuchains/gcc-fork.git] / libgcc / dfp-bit.c
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 \f
61 /* Binary operations.  */
62
63 /* Use a decFloat (decDouble or decQuad) function to perform a DFP
64    binary operation.  */
65 static inline decFloat
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
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
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
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
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
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 \f
201 #if defined(L_conv_sd)
202 void
203 __host_to_ieee_32 (_Decimal32 in, decimal32 *out)
204 {
205   memcpy (out, &in, 4);
206 }
207
208 void
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
217 __host_to_ieee_64 (_Decimal64 in, decimal64 *out)
218 {
219   memcpy (out, &in, 8);
220 }
221
222 void
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
231 __host_to_ieee_128 (_Decimal128 in, decimal128 *out)
232 {
233   memcpy (out, &in, 16);
234 }
235
236 void
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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.  */
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
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
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
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
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 */