annotate libgcc/dfp-bit.c @ 144:8f4e72ab4e11

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