1 /* ------------------------------------------------------------------ */
2 /* Decimal Context module */
3 /* ------------------------------------------------------------------ */
4 /* Copyright (c) IBM Corporation, 2000, 2009. All rights reserved. */
6 /* This software is made available under the terms of the */
7 /* ICU License -- ICU 1.8.1 and later. */
9 /* The description and User's Guide ("The decNumber C Library") for */
10 /* this software is called decNumber.pdf. This document is */
11 /* available, together with arithmetic and format specifications, */
12 /* testcases, and Web links, on the General Decimal Arithmetic page. */
14 /* Please send comments, suggestions, and corrections to the author: */
16 /* Mike Cowlishaw, IBM Fellow */
17 /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */
18 /* ------------------------------------------------------------------ */
19 /* This module comprises the routines for handling arithmetic */
20 /* context structures. */
21 /* ------------------------------------------------------------------ */
23 #include <string.h> // for strcmp
24 #include <stdio.h> // for printf if DECCHECK
25 #include "decContext.h" // context and base types
26 #include "decNumberLocal.h" // decNumber local types, etc.
28 /* compile-time endian tester [assumes sizeof(Int)>1] */
29 static const Int mfcone = 1; // constant 1
30 static const Flag *mfctop = (const Flag *)&mfcone; // -> top byte
31 #define LITEND *mfctop // named flag; 1=little-endian
33 /* ------------------------------------------------------------------ */
34 /* round-for-reround digits */
35 /* ------------------------------------------------------------------ */
36 const uByte DECSTICKYTAB[10] = { 1, 1, 2, 3, 4, 6, 6, 7, 8, 9 }; /* used if sticky */
38 /* ------------------------------------------------------------------ */
39 /* Powers of ten (powers[n]==10**n, 0<=n<=9) */
40 /* ------------------------------------------------------------------ */
41 const uInt DECPOWERS[10] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
42 10000000, 100000000, 1000000000
45 /* ------------------------------------------------------------------ */
46 /* decContextClearStatus -- clear bits in current status */
48 /* context is the context structure to be queried */
49 /* mask indicates the bits to be cleared (the status bit that */
50 /* corresponds to each 1 bit in the mask is cleared) */
53 /* No error is possible. */
54 /* ------------------------------------------------------------------ */
55 decContext *decContextClearStatus(decContext * context, uInt mask)
57 context->status &= ~mask;
59 } // decContextClearStatus
61 /* ------------------------------------------------------------------ */
62 /* decContextDefault -- initialize a context structure */
64 /* context is the structure to be initialized */
65 /* kind selects the required set of default values, one of: */
66 /* DEC_INIT_BASE -- select ANSI X3-274 defaults */
67 /* DEC_INIT_DECIMAL32 -- select IEEE 754 defaults, 32-bit */
68 /* DEC_INIT_DECIMAL64 -- select IEEE 754 defaults, 64-bit */
69 /* DEC_INIT_DECIMAL128 -- select IEEE 754 defaults, 128-bit */
70 /* For any other value a valid context is returned, but with */
71 /* Invalid_operation set in the status field. */
72 /* returns a context structure with the appropriate initial values. */
73 /* ------------------------------------------------------------------ */
74 decContext *decContextDefault(decContext * context, Int kind)
77 context->digits = 9; // 9 digits
78 context->emax = DEC_MAX_EMAX; // 9-digit exponents
79 context->emin = DEC_MIN_EMIN; // .. balanced
80 context->round = DEC_ROUND_HALF_UP; // 0.5 rises
81 context->traps = DEC_Errors; // all but informational
82 context->status = 0; // cleared
83 context->clamp = 0; // no clamping
85 context->extended = 0; // cleared
91 case DEC_INIT_DECIMAL32:
92 context->digits = 7; // digits
93 context->emax = 96; // Emax
94 context->emin = -95; // Emin
95 context->round = DEC_ROUND_HALF_EVEN; // 0.5 to nearest even
96 context->traps = 0; // no traps set
97 context->clamp = 1; // clamp exponents
99 context->extended = 1; // set
102 case DEC_INIT_DECIMAL64:
103 context->digits = 16; // digits
104 context->emax = 384; // Emax
105 context->emin = -383; // Emin
106 context->round = DEC_ROUND_HALF_EVEN; // 0.5 to nearest even
107 context->traps = 0; // no traps set
108 context->clamp = 1; // clamp exponents
110 context->extended = 1; // set
113 case DEC_INIT_DECIMAL128:
114 context->digits = 34; // digits
115 context->emax = 6144; // Emax
116 context->emin = -6143; // Emin
117 context->round = DEC_ROUND_HALF_EVEN; // 0.5 to nearest even
118 context->traps = 0; // no traps set
119 context->clamp = 1; // clamp exponents
121 context->extended = 1; // set
125 default: // invalid Kind
126 // use defaults, and ..
127 decContextSetStatus(context, DEC_Invalid_operation); // trap
131 } // decContextDefault
133 /* ------------------------------------------------------------------ */
134 /* decContextGetRounding -- return current rounding mode */
136 /* context is the context structure to be queried */
137 /* returns the rounding mode */
139 /* No error is possible. */
140 /* ------------------------------------------------------------------ */
141 enum rounding decContextGetRounding(decContext * context)
143 return context->round;
144 } // decContextGetRounding
146 /* ------------------------------------------------------------------ */
147 /* decContextGetStatus -- return current status */
149 /* context is the context structure to be queried */
152 /* No error is possible. */
153 /* ------------------------------------------------------------------ */
154 uInt decContextGetStatus(decContext * context)
156 return context->status;
157 } // decContextGetStatus
159 /* ------------------------------------------------------------------ */
160 /* decContextRestoreStatus -- restore bits in current status */
162 /* context is the context structure to be updated */
163 /* newstatus is the source for the bits to be restored */
164 /* mask indicates the bits to be restored (the status bit that */
165 /* corresponds to each 1 bit in the mask is set to the value of */
166 /* the correspnding bit in newstatus) */
167 /* returns context */
169 /* No error is possible. */
170 /* ------------------------------------------------------------------ */
171 decContext *decContextRestoreStatus(decContext * context,
172 uInt newstatus, uInt mask)
174 context->status &= ~mask; // clear the selected bits
175 context->status |= (mask & newstatus); // or in the new bits
177 } // decContextRestoreStatus
179 /* ------------------------------------------------------------------ */
180 /* decContextSaveStatus -- save bits in current status */
182 /* context is the context structure to be queried */
183 /* mask indicates the bits to be saved (the status bits that */
184 /* correspond to each 1 bit in the mask are saved) */
185 /* returns the AND of the mask and the current status */
187 /* No error is possible. */
188 /* ------------------------------------------------------------------ */
189 uInt decContextSaveStatus(decContext * context, uInt mask)
191 return context->status & mask;
192 } // decContextSaveStatus
194 /* ------------------------------------------------------------------ */
195 /* decContextSetRounding -- set current rounding mode */
197 /* context is the context structure to be updated */
198 /* newround is the value which will replace the current mode */
199 /* returns context */
201 /* No error is possible. */
202 /* ------------------------------------------------------------------ */
203 decContext *decContextSetRounding(decContext * context, enum rounding newround)
205 context->round = newround;
207 } // decContextSetRounding
209 /* ------------------------------------------------------------------ */
210 /* decContextSetStatus -- set status and raise trap if appropriate */
212 /* context is the context structure to be updated */
213 /* status is the DEC_ exception code */
214 /* returns the context structure */
216 /* Control may never return from this routine, if there is a signal */
217 /* handler and it takes a long jump. */
218 /* ------------------------------------------------------------------ */
219 decContext *decContextSetStatus(decContext * context, uInt status)
221 context->status |= status;
222 if (status & context->traps)
225 } // decContextSetStatus
227 /* ------------------------------------------------------------------ */
228 /* decContextSetStatusFromString -- set status from a string + trap */
230 /* context is the context structure to be updated */
231 /* string is a string exactly equal to one that might be returned */
232 /* by decContextStatusToString */
234 /* The status bit corresponding to the string is set, and a trap */
235 /* is raised if appropriate. */
237 /* returns the context structure, unless the string is equal to */
238 /* DEC_Condition_MU or is not recognized. In these cases NULL is */
240 /* ------------------------------------------------------------------ */
241 decContext *decContextSetStatusFromString(decContext * context,
244 if (strcmp(string, DEC_Condition_CS) == 0)
245 return decContextSetStatus(context, DEC_Conversion_syntax);
246 if (strcmp(string, DEC_Condition_DZ) == 0)
247 return decContextSetStatus(context, DEC_Division_by_zero);
248 if (strcmp(string, DEC_Condition_DI) == 0)
249 return decContextSetStatus(context, DEC_Division_impossible);
250 if (strcmp(string, DEC_Condition_DU) == 0)
251 return decContextSetStatus(context, DEC_Division_undefined);
252 if (strcmp(string, DEC_Condition_IE) == 0)
253 return decContextSetStatus(context, DEC_Inexact);
254 if (strcmp(string, DEC_Condition_IS) == 0)
255 return decContextSetStatus(context, DEC_Insufficient_storage);
256 if (strcmp(string, DEC_Condition_IC) == 0)
257 return decContextSetStatus(context, DEC_Invalid_context);
258 if (strcmp(string, DEC_Condition_IO) == 0)
259 return decContextSetStatus(context, DEC_Invalid_operation);
261 if (strcmp(string, DEC_Condition_LD) == 0)
262 return decContextSetStatus(context, DEC_Lost_digits);
264 if (strcmp(string, DEC_Condition_OV) == 0)
265 return decContextSetStatus(context, DEC_Overflow);
266 if (strcmp(string, DEC_Condition_PA) == 0)
267 return decContextSetStatus(context, DEC_Clamped);
268 if (strcmp(string, DEC_Condition_RO) == 0)
269 return decContextSetStatus(context, DEC_Rounded);
270 if (strcmp(string, DEC_Condition_SU) == 0)
271 return decContextSetStatus(context, DEC_Subnormal);
272 if (strcmp(string, DEC_Condition_UN) == 0)
273 return decContextSetStatus(context, DEC_Underflow);
274 if (strcmp(string, DEC_Condition_ZE) == 0)
276 return NULL; // Multiple status, or unknown
277 } // decContextSetStatusFromString
279 /* ------------------------------------------------------------------ */
280 /* decContextSetStatusFromStringQuiet -- set status from a string */
282 /* context is the context structure to be updated */
283 /* string is a string exactly equal to one that might be returned */
284 /* by decContextStatusToString */
286 /* The status bit corresponding to the string is set; no trap is */
289 /* returns the context structure, unless the string is equal to */
290 /* DEC_Condition_MU or is not recognized. In these cases NULL is */
292 /* ------------------------------------------------------------------ */
293 decContext *decContextSetStatusFromStringQuiet(decContext * context,
296 if (strcmp(string, DEC_Condition_CS) == 0)
297 return decContextSetStatusQuiet(context, DEC_Conversion_syntax);
298 if (strcmp(string, DEC_Condition_DZ) == 0)
299 return decContextSetStatusQuiet(context, DEC_Division_by_zero);
300 if (strcmp(string, DEC_Condition_DI) == 0)
301 return decContextSetStatusQuiet(context,
302 DEC_Division_impossible);
303 if (strcmp(string, DEC_Condition_DU) == 0)
304 return decContextSetStatusQuiet(context,
305 DEC_Division_undefined);
306 if (strcmp(string, DEC_Condition_IE) == 0)
307 return decContextSetStatusQuiet(context, DEC_Inexact);
308 if (strcmp(string, DEC_Condition_IS) == 0)
309 return decContextSetStatusQuiet(context,
310 DEC_Insufficient_storage);
311 if (strcmp(string, DEC_Condition_IC) == 0)
312 return decContextSetStatusQuiet(context, DEC_Invalid_context);
313 if (strcmp(string, DEC_Condition_IO) == 0)
314 return decContextSetStatusQuiet(context, DEC_Invalid_operation);
316 if (strcmp(string, DEC_Condition_LD) == 0)
317 return decContextSetStatusQuiet(context, DEC_Lost_digits);
319 if (strcmp(string, DEC_Condition_OV) == 0)
320 return decContextSetStatusQuiet(context, DEC_Overflow);
321 if (strcmp(string, DEC_Condition_PA) == 0)
322 return decContextSetStatusQuiet(context, DEC_Clamped);
323 if (strcmp(string, DEC_Condition_RO) == 0)
324 return decContextSetStatusQuiet(context, DEC_Rounded);
325 if (strcmp(string, DEC_Condition_SU) == 0)
326 return decContextSetStatusQuiet(context, DEC_Subnormal);
327 if (strcmp(string, DEC_Condition_UN) == 0)
328 return decContextSetStatusQuiet(context, DEC_Underflow);
329 if (strcmp(string, DEC_Condition_ZE) == 0)
331 return NULL; // Multiple status, or unknown
332 } // decContextSetStatusFromStringQuiet
334 /* ------------------------------------------------------------------ */
335 /* decContextSetStatusQuiet -- set status without trap */
337 /* context is the context structure to be updated */
338 /* status is the DEC_ exception code */
339 /* returns the context structure */
341 /* No error is possible. */
342 /* ------------------------------------------------------------------ */
343 decContext *decContextSetStatusQuiet(decContext * context, uInt status)
345 context->status |= status;
347 } // decContextSetStatusQuiet
349 /* ------------------------------------------------------------------ */
350 /* decContextStatusToString -- convert status flags to a string */
352 /* context is a context with valid status field */
354 /* returns a constant string describing the condition. If multiple */
355 /* (or no) flags are set, a generic constant message is returned. */
356 /* ------------------------------------------------------------------ */
357 const char *decContextStatusToString(const decContext * context)
359 Int status = context->status;
361 // test the five IEEE first, as some of the others are ambiguous when
363 if (status == DEC_Invalid_operation)
364 return DEC_Condition_IO;
365 if (status == DEC_Division_by_zero)
366 return DEC_Condition_DZ;
367 if (status == DEC_Overflow)
368 return DEC_Condition_OV;
369 if (status == DEC_Underflow)
370 return DEC_Condition_UN;
371 if (status == DEC_Inexact)
372 return DEC_Condition_IE;
374 if (status == DEC_Division_impossible)
375 return DEC_Condition_DI;
376 if (status == DEC_Division_undefined)
377 return DEC_Condition_DU;
378 if (status == DEC_Rounded)
379 return DEC_Condition_RO;
380 if (status == DEC_Clamped)
381 return DEC_Condition_PA;
382 if (status == DEC_Subnormal)
383 return DEC_Condition_SU;
384 if (status == DEC_Conversion_syntax)
385 return DEC_Condition_CS;
386 if (status == DEC_Insufficient_storage)
387 return DEC_Condition_IS;
388 if (status == DEC_Invalid_context)
389 return DEC_Condition_IC;
391 if (status == DEC_Lost_digits)
392 return DEC_Condition_LD;
395 return DEC_Condition_ZE;
396 return DEC_Condition_MU; // Multiple errors
397 } // decContextStatusToString
399 /* ------------------------------------------------------------------ */
400 /* decContextTestEndian -- test whether DECLITEND is set correctly */
402 /* quiet is 1 to suppress message; 0 otherwise */
403 /* returns 0 if DECLITEND is correct */
404 /* 1 if DECLITEND is incorrect and should be 1 */
405 /* -1 if DECLITEND is incorrect and should be 0 */
407 /* A message is displayed if the return value is not 0 and quiet==0. */
409 /* No error is possible. */
410 /* ------------------------------------------------------------------ */
411 Int decContextTestEndian(Flag quiet)
413 Int res = 0; // optimist
414 uInt dle = (uInt) DECLITEND; // unsign
416 dle = 1; // ensure 0 or 1
418 if (LITEND != DECLITEND) {
419 if (!quiet) { // always refer to this
427 ("Warning: DECLITEND is set to %d, but this computer appears to be %s-endian\n",
431 res = (Int) LITEND - dle;
434 } // decContextTestEndian
436 /* ------------------------------------------------------------------ */
437 /* decContextTestSavedStatus -- test bits in saved status */
439 /* oldstatus is the status word to be tested */
440 /* mask indicates the bits to be tested (the oldstatus bits that */
441 /* correspond to each 1 bit in the mask are tested) */
442 /* returns 1 if any of the tested bits are 1, or 0 otherwise */
444 /* No error is possible. */
445 /* ------------------------------------------------------------------ */
446 uInt decContextTestSavedStatus(uInt oldstatus, uInt mask)
448 return (oldstatus & mask) != 0;
449 } // decContextTestSavedStatus
451 /* ------------------------------------------------------------------ */
452 /* decContextTestStatus -- test bits in current status */
454 /* context is the context structure to be updated */
455 /* mask indicates the bits to be tested (the status bits that */
456 /* correspond to each 1 bit in the mask are tested) */
457 /* returns 1 if any of the tested bits are 1, or 0 otherwise */
459 /* No error is possible. */
460 /* ------------------------------------------------------------------ */
461 uInt decContextTestStatus(decContext * context, uInt mask)
463 return (context->status & mask) != 0;
464 } // decContextTestStatus
466 /* ------------------------------------------------------------------ */
467 /* decContextZeroStatus -- clear all status bits */
469 /* context is the context structure to be updated */
470 /* returns context */
472 /* No error is possible. */
473 /* ------------------------------------------------------------------ */
474 decContext *decContextZeroStatus(decContext * context)
478 } // decContextZeroStatus