]>
Commit | Line | Data |
---|---|---|
2d8d5935 | 1 | /* This is a software decimal floating point library. |
83ffe9cd | 2 | Copyright (C) 2005-2023 Free Software Foundation, Inc. |
2d8d5935 RO |
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 "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 | \f | |
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 | \f | |
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 | f64 = *DEC_FLOAT_FROM_INT (&f64, i); | |
572 | u32.f = *decSingleFromWider (&u32.f, &f64, &context); | |
573 | if (DFP_EXCEPTIONS_ENABLED && context.status != 0) | |
574 | dfp_conversion_exceptions (context.status); | |
575 | return u32.c; | |
576 | } | |
577 | #endif | |
578 | ||
579 | #if defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \ | |
580 | || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td) | |
581 | /* decNumber doesn't provide support for conversions from 64-bit integer | |
582 | types, so do it the hard way. */ | |
583 | DFP_C_TYPE | |
584 | INT_TO_DFP (INT_TYPE i) | |
585 | { | |
586 | DFP_C_TYPE f; | |
587 | IEEE_TYPE s; | |
588 | char buf[BUFMAX]; | |
589 | decContext context; | |
590 | ||
591 | decContextDefault (&context, CONTEXT_INIT); | |
592 | DFP_INIT_ROUNDMODE (context.round); | |
593 | ||
594 | /* Use a C library function to get a floating point string. */ | |
595 | sprintf (buf, INT_FMT ".", CAST_FOR_FMT(i)); | |
596 | /* Convert from the floating point string to a decimal* type. */ | |
597 | FROM_STRING (&s, buf, &context); | |
598 | IEEE_TO_HOST (s, &f); | |
599 | ||
600 | if (DFP_EXCEPTIONS_ENABLED && context.status != 0) | |
601 | dfp_conversion_exceptions (context.status); | |
602 | ||
603 | return f; | |
604 | } | |
605 | #endif | |
606 | ||
607 | #if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \ | |
608 | || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \ | |
78118359 | 609 | || defined (L_sd_to_kf) || defined (L_dd_to_kf) || defined (L_td_to_kf) \ |
2d8d5935 RO |
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) \ | |
78118359 | 630 | || defined (L_kf_to_sd) || defined (L_kf_to_dd) || defined (L_kf_to_td) \ |
2d8d5935 RO |
631 | || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \ |
632 | && LONG_DOUBLE_HAS_XF_MODE) \ | |
633 | || ((defined (L_tf_to_sd) || defined (L_tf_to_dd) || defined (L_tf_to_td)) \ | |
634 | && LONG_DOUBLE_HAS_TF_MODE) | |
635 | DFP_C_TYPE | |
636 | BFP_TO_DFP (BFP_TYPE x) | |
637 | { | |
638 | DFP_C_TYPE f; | |
639 | IEEE_TYPE s; | |
640 | char buf[BUFMAX]; | |
641 | decContext context; | |
642 | ||
643 | decContextDefault (&context, CONTEXT_INIT); | |
644 | DFP_INIT_ROUNDMODE (context.round); | |
645 | ||
692ba083 MM |
646 | /* Use the sprintf library function to write the floating point value to a |
647 | string. | |
78118359 MM |
648 | |
649 | If we are handling the IEEE 128-bit floating point on PowerPC, use the | |
650 | special function __sprintfkf instead of sprintf. This function allows us | |
651 | to use __sprintfieee128 if we have a new enough GLIBC, and it can fall back | |
652 | to using the traditional sprintf via conversion to IBM 128-bit if the glibc | |
653 | is older. */ | |
654 | BFP_SPRINTF (buf, BFP_FMT, (BFP_VIA_TYPE) x); | |
2d8d5935 RO |
655 | |
656 | /* Convert from the floating point string to a decimal* type. */ | |
657 | FROM_STRING (&s, buf, &context); | |
658 | IEEE_TO_HOST (s, &f); | |
659 | ||
660 | if (DFP_EXCEPTIONS_ENABLED && context.status != 0) | |
661 | { | |
662 | /* decNumber exception flags we care about here. */ | |
663 | int ieee_flags; | |
664 | int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Invalid_operation | |
665 | | DEC_IEEE_854_Overflow | DEC_IEEE_854_Underflow; | |
666 | dec_flags &= context.status; | |
667 | ieee_flags = DFP_IEEE_FLAGS (dec_flags); | |
668 | if (ieee_flags != 0) | |
669 | DFP_HANDLE_EXCEPTIONS (ieee_flags); | |
670 | } | |
671 | ||
672 | return f; | |
673 | } | |
674 | #endif | |
675 | ||
676 | #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td) | |
677 | CMPtype | |
678 | DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) | |
679 | { | |
680 | decNumber arg1, arg2; | |
681 | IEEE_TYPE a, b; | |
682 | ||
683 | HOST_TO_IEEE (arg_a, &a); | |
684 | HOST_TO_IEEE (arg_b, &b); | |
685 | TO_INTERNAL (&a, &arg1); | |
686 | TO_INTERNAL (&b, &arg2); | |
687 | return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2)); | |
688 | } | |
689 | #endif /* L_unord_sd || L_unord_dd || L_unord_td */ |