111
|
1 /* This is a software decimal floating point library.
|
145
|
2 Copyright (C) 2005-2020 Free Software Foundation, Inc.
|
111
|
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
|
|
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 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) \
|
|
609 || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \
|
|
610 && LONG_DOUBLE_HAS_XF_MODE) \
|
|
611 || ((defined (L_sd_to_tf) || defined (L_dd_to_tf) || defined (L_td_to_tf)) \
|
|
612 && LONG_DOUBLE_HAS_TF_MODE)
|
|
613 BFP_TYPE
|
|
614 DFP_TO_BFP (DFP_C_TYPE f)
|
|
615 {
|
|
616 IEEE_TYPE s;
|
|
617 char buf[BUFMAX];
|
|
618
|
|
619 HOST_TO_IEEE (f, &s);
|
|
620 /* Write the value to a string. */
|
|
621 TO_STRING (&s, buf);
|
|
622 /* Read it as the binary floating point type and return that. */
|
|
623 return STR_TO_BFP (buf, NULL);
|
|
624 }
|
|
625 #endif
|
|
626
|
|
627 #if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \
|
|
628 || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \
|
|
629 || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \
|
|
630 && LONG_DOUBLE_HAS_XF_MODE) \
|
|
631 || ((defined (L_tf_to_sd) || defined (L_tf_to_dd) || defined (L_tf_to_td)) \
|
|
632 && LONG_DOUBLE_HAS_TF_MODE)
|
|
633 DFP_C_TYPE
|
|
634 BFP_TO_DFP (BFP_TYPE x)
|
|
635 {
|
|
636 DFP_C_TYPE f;
|
|
637 IEEE_TYPE s;
|
|
638 char buf[BUFMAX];
|
|
639 decContext context;
|
|
640
|
|
641 decContextDefault (&context, CONTEXT_INIT);
|
|
642 DFP_INIT_ROUNDMODE (context.round);
|
|
643
|
|
644 /* Use a C library function to write the floating point value to a string. */
|
|
645 sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x);
|
|
646
|
|
647 /* Convert from the floating point string to a decimal* type. */
|
|
648 FROM_STRING (&s, buf, &context);
|
|
649 IEEE_TO_HOST (s, &f);
|
|
650
|
|
651 if (DFP_EXCEPTIONS_ENABLED && context.status != 0)
|
|
652 {
|
|
653 /* decNumber exception flags we care about here. */
|
|
654 int ieee_flags;
|
|
655 int dec_flags = DEC_IEEE_854_Inexact | DEC_IEEE_854_Invalid_operation
|
|
656 | DEC_IEEE_854_Overflow | DEC_IEEE_854_Underflow;
|
|
657 dec_flags &= context.status;
|
|
658 ieee_flags = DFP_IEEE_FLAGS (dec_flags);
|
|
659 if (ieee_flags != 0)
|
|
660 DFP_HANDLE_EXCEPTIONS (ieee_flags);
|
|
661 }
|
|
662
|
|
663 return f;
|
|
664 }
|
|
665 #endif
|
|
666
|
|
667 #if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td)
|
|
668 CMPtype
|
|
669 DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
|
|
670 {
|
|
671 decNumber arg1, arg2;
|
|
672 IEEE_TYPE a, b;
|
|
673
|
|
674 HOST_TO_IEEE (arg_a, &a);
|
|
675 HOST_TO_IEEE (arg_b, &b);
|
|
676 TO_INTERNAL (&a, &arg1);
|
|
677 TO_INTERNAL (&b, &arg2);
|
|
678 return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2));
|
|
679 }
|
|
680 #endif /* L_unord_sd || L_unord_dd || L_unord_td */
|