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