• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ------------------------------------------------------------------ */
2 /* Decimal Context module                                             */
3 /* ------------------------------------------------------------------ */
4 /* Copyright (c) IBM Corporation, 2000-2010.  All rights reserved.    */
5 /*                                                                    */
6 /* This software is made available under the terms of the             */
7 /* ICU License -- ICU 1.8.1 and later.                                */
8 /*                                                                    */
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.  */
13 /*                                                                    */
14 /* Please send comments, suggestions, and corrections to the author:  */
15 /*   mfc@uk.ibm.com                                                   */
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 /* ------------------------------------------------------------------ */
22 
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.  */
27 
28 /* compile-time endian tester [assumes sizeof(Int)>1] */
29 static  const  Int mfcone=1;                 /* constant 1  */
30 static  const  Flag *mfctop=(Flag *)&mfcone; /* -> top byte  */
31 #define LITEND *mfctop             /* named flag; 1=little-endian  */
32 
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 */
37 
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};
43 
44 /* ------------------------------------------------------------------ */
45 /* decContextClearStatus -- clear bits in current status              */
46 /*                                                                    */
47 /*  context is the context structure to be queried                    */
48 /*  mask indicates the bits to be cleared (the status bit that        */
49 /*    corresponds to each 1 bit in the mask is cleared)               */
50 /*  returns context                                                   */
51 /*                                                                    */
52 /* No error is possible.                                              */
53 /* ------------------------------------------------------------------ */
uprv_decContextClearStatus(decContext * context,uInt mask)54 U_CAPI decContext * U_EXPORT2 uprv_decContextClearStatus(decContext *context, uInt mask) {
55   context->status&=~mask;
56   return context;
57   } /* decContextClearStatus  */
58 
59 /* ------------------------------------------------------------------ */
60 /* decContextDefault -- initialize a context structure                */
61 /*                                                                    */
62 /*  context is the structure to be initialized                        */
63 /*  kind selects the required set of default values, one of:          */
64 /*      DEC_INIT_BASE       -- select ANSI X3-274 defaults            */
65 /*      DEC_INIT_DECIMAL32  -- select IEEE 754 defaults, 32-bit       */
66 /*      DEC_INIT_DECIMAL64  -- select IEEE 754 defaults, 64-bit       */
67 /*      DEC_INIT_DECIMAL128 -- select IEEE 754 defaults, 128-bit      */
68 /*      For any other value a valid context is returned, but with     */
69 /*      Invalid_operation set in the status field.                    */
70 /*  returns a context structure with the appropriate initial values.  */
71 /* ------------------------------------------------------------------ */
uprv_decContextDefault(decContext * context,Int kind)72 U_CAPI decContext *  U_EXPORT2 uprv_decContextDefault(decContext *context, Int kind) {
73   /* set defaults...  */
74   context->digits=9;                         /* 9 digits  */
75   context->emax=DEC_MAX_EMAX;                /* 9-digit exponents  */
76   context->emin=DEC_MIN_EMIN;                /* .. balanced  */
77   context->round=DEC_ROUND_HALF_UP;          /* 0.5 rises  */
78   context->traps=DEC_Errors;                 /* all but informational  */
79   context->status=0;                         /* cleared  */
80   context->clamp=0;                          /* no clamping  */
81   #if DECSUBSET
82   context->extended=0;                       /* cleared  */
83   #endif
84   switch (kind) {
85     case DEC_INIT_BASE:
86       /* [use defaults]  */
87       break;
88     case DEC_INIT_DECIMAL32:
89       context->digits=7;                     /* digits  */
90       context->emax=96;                      /* Emax  */
91       context->emin=-95;                     /* Emin  */
92       context->round=DEC_ROUND_HALF_EVEN;    /* 0.5 to nearest even  */
93       context->traps=0;                      /* no traps set  */
94       context->clamp=1;                      /* clamp exponents  */
95       #if DECSUBSET
96       context->extended=1;                   /* set  */
97       #endif
98       break;
99     case DEC_INIT_DECIMAL64:
100       context->digits=16;                    /* digits  */
101       context->emax=384;                     /* Emax  */
102       context->emin=-383;                    /* Emin  */
103       context->round=DEC_ROUND_HALF_EVEN;    /* 0.5 to nearest even  */
104       context->traps=0;                      /* no traps set  */
105       context->clamp=1;                      /* clamp exponents  */
106       #if DECSUBSET
107       context->extended=1;                   /* set  */
108       #endif
109       break;
110     case DEC_INIT_DECIMAL128:
111       context->digits=34;                    /* digits  */
112       context->emax=6144;                    /* Emax  */
113       context->emin=-6143;                   /* Emin  */
114       context->round=DEC_ROUND_HALF_EVEN;    /* 0.5 to nearest even  */
115       context->traps=0;                      /* no traps set  */
116       context->clamp=1;                      /* clamp exponents  */
117       #if DECSUBSET
118       context->extended=1;                   /* set  */
119       #endif
120       break;
121 
122     default:                                 /* invalid Kind  */
123       /* use defaults, and ..  */
124       uprv_decContextSetStatus(context, DEC_Invalid_operation); /* trap  */
125     }
126 
127   return context;} /* decContextDefault  */
128 
129 /* ------------------------------------------------------------------ */
130 /* decContextGetRounding -- return current rounding mode              */
131 /*                                                                    */
132 /*  context is the context structure to be queried                    */
133 /*  returns the rounding mode                                         */
134 /*                                                                    */
135 /* No error is possible.                                              */
136 /* ------------------------------------------------------------------ */
uprv_decContextGetRounding(decContext * context)137 U_CAPI enum rounding  U_EXPORT2 uprv_decContextGetRounding(decContext *context) {
138   return context->round;
139   } /* decContextGetRounding  */
140 
141 /* ------------------------------------------------------------------ */
142 /* decContextGetStatus -- return current status                       */
143 /*                                                                    */
144 /*  context is the context structure to be queried                    */
145 /*  returns status                                                    */
146 /*                                                                    */
147 /* No error is possible.                                              */
148 /* ------------------------------------------------------------------ */
uprv_decContextGetStatus(decContext * context)149 U_CAPI uInt  U_EXPORT2 uprv_decContextGetStatus(decContext *context) {
150   return context->status;
151   } /* decContextGetStatus  */
152 
153 /* ------------------------------------------------------------------ */
154 /* decContextRestoreStatus -- restore bits in current status          */
155 /*                                                                    */
156 /*  context is the context structure to be updated                    */
157 /*  newstatus is the source for the bits to be restored               */
158 /*  mask indicates the bits to be restored (the status bit that       */
159 /*    corresponds to each 1 bit in the mask is set to the value of    */
160 /*    the correspnding bit in newstatus)                              */
161 /*  returns context                                                   */
162 /*                                                                    */
163 /* No error is possible.                                              */
164 /* ------------------------------------------------------------------ */
uprv_decContextRestoreStatus(decContext * context,uInt newstatus,uInt mask)165 U_CAPI decContext * U_EXPORT2 uprv_decContextRestoreStatus(decContext *context,
166                                     uInt newstatus, uInt mask) {
167   context->status&=~mask;               /* clear the selected bits  */
168   context->status|=(mask&newstatus);    /* or in the new bits  */
169   return context;
170   } /* decContextRestoreStatus  */
171 
172 /* ------------------------------------------------------------------ */
173 /* decContextSaveStatus -- save bits in current status                */
174 /*                                                                    */
175 /*  context is the context structure to be queried                    */
176 /*  mask indicates the bits to be saved (the status bits that         */
177 /*    correspond to each 1 bit in the mask are saved)                 */
178 /*  returns the AND of the mask and the current status                */
179 /*                                                                    */
180 /* No error is possible.                                              */
181 /* ------------------------------------------------------------------ */
uprv_decContextSaveStatus(decContext * context,uInt mask)182 U_CAPI uInt  U_EXPORT2 uprv_decContextSaveStatus(decContext *context, uInt mask) {
183   return context->status&mask;
184   } /* decContextSaveStatus  */
185 
186 /* ------------------------------------------------------------------ */
187 /* decContextSetRounding -- set current rounding mode                 */
188 /*                                                                    */
189 /*  context is the context structure to be updated                    */
190 /*  newround is the value which will replace the current mode         */
191 /*  returns context                                                   */
192 /*                                                                    */
193 /* No error is possible.                                              */
194 /* ------------------------------------------------------------------ */
uprv_decContextSetRounding(decContext * context,enum rounding newround)195 U_CAPI decContext * U_EXPORT2 uprv_decContextSetRounding(decContext *context,
196                                   enum rounding newround) {
197   context->round=newround;
198   return context;
199   } /* decContextSetRounding  */
200 
201 /* ------------------------------------------------------------------ */
202 /* decContextSetStatus -- set status and raise trap if appropriate    */
203 /*                                                                    */
204 /*  context is the context structure to be updated                    */
205 /*  status  is the DEC_ exception code                                */
206 /*  returns the context structure                                     */
207 /*                                                                    */
208 /* Control may never return from this routine, if there is a signal   */
209 /* handler and it takes a long jump.                                  */
210 /* ------------------------------------------------------------------ */
uprv_decContextSetStatus(decContext * context,uInt status)211 U_CAPI decContext *  U_EXPORT2 uprv_decContextSetStatus(decContext *context, uInt status) {
212   context->status|=status;
213   if (status & context->traps) raise(SIGFPE);
214   return context;} /* decContextSetStatus  */
215 
216 /* ------------------------------------------------------------------ */
217 /* decContextSetStatusFromString -- set status from a string + trap   */
218 /*                                                                    */
219 /*  context is the context structure to be updated                    */
220 /*  string is a string exactly equal to one that might be returned    */
221 /*            by decContextStatusToString                             */
222 /*                                                                    */
223 /*  The status bit corresponding to the string is set, and a trap     */
224 /*  is raised if appropriate.                                         */
225 /*                                                                    */
226 /*  returns the context structure, unless the string is equal to      */
227 /*    DEC_Condition_MU or is not recognized.  In these cases NULL is  */
228 /*    returned.                                                       */
229 /* ------------------------------------------------------------------ */
uprv_decContextSetStatusFromString(decContext * context,const char * string)230 U_CAPI decContext *  U_EXPORT2 uprv_decContextSetStatusFromString(decContext *context,
231                                            const char *string) {
232   if (strcmp(string, DEC_Condition_CS)==0)
233     return uprv_decContextSetStatus(context, DEC_Conversion_syntax);
234   if (strcmp(string, DEC_Condition_DZ)==0)
235     return uprv_decContextSetStatus(context, DEC_Division_by_zero);
236   if (strcmp(string, DEC_Condition_DI)==0)
237     return uprv_decContextSetStatus(context, DEC_Division_impossible);
238   if (strcmp(string, DEC_Condition_DU)==0)
239     return uprv_decContextSetStatus(context, DEC_Division_undefined);
240   if (strcmp(string, DEC_Condition_IE)==0)
241     return uprv_decContextSetStatus(context, DEC_Inexact);
242   if (strcmp(string, DEC_Condition_IS)==0)
243     return uprv_decContextSetStatus(context, DEC_Insufficient_storage);
244   if (strcmp(string, DEC_Condition_IC)==0)
245     return uprv_decContextSetStatus(context, DEC_Invalid_context);
246   if (strcmp(string, DEC_Condition_IO)==0)
247     return uprv_decContextSetStatus(context, DEC_Invalid_operation);
248   #if DECSUBSET
249   if (strcmp(string, DEC_Condition_LD)==0)
250     return uprv_decContextSetStatus(context, DEC_Lost_digits);
251   #endif
252   if (strcmp(string, DEC_Condition_OV)==0)
253     return uprv_decContextSetStatus(context, DEC_Overflow);
254   if (strcmp(string, DEC_Condition_PA)==0)
255     return uprv_decContextSetStatus(context, DEC_Clamped);
256   if (strcmp(string, DEC_Condition_RO)==0)
257     return uprv_decContextSetStatus(context, DEC_Rounded);
258   if (strcmp(string, DEC_Condition_SU)==0)
259     return uprv_decContextSetStatus(context, DEC_Subnormal);
260   if (strcmp(string, DEC_Condition_UN)==0)
261     return uprv_decContextSetStatus(context, DEC_Underflow);
262   if (strcmp(string, DEC_Condition_ZE)==0)
263     return context;
264   return NULL;  /* Multiple status, or unknown  */
265   } /* decContextSetStatusFromString  */
266 
267 /* ------------------------------------------------------------------ */
268 /* decContextSetStatusFromStringQuiet -- set status from a string     */
269 /*                                                                    */
270 /*  context is the context structure to be updated                    */
271 /*  string is a string exactly equal to one that might be returned    */
272 /*            by decContextStatusToString                             */
273 /*                                                                    */
274 /*  The status bit corresponding to the string is set; no trap is     */
275 /*  raised.                                                           */
276 /*                                                                    */
277 /*  returns the context structure, unless the string is equal to      */
278 /*    DEC_Condition_MU or is not recognized.  In these cases NULL is  */
279 /*    returned.                                                       */
280 /* ------------------------------------------------------------------ */
uprv_decContextSetStatusFromStringQuiet(decContext * context,const char * string)281 U_CAPI decContext *  U_EXPORT2 uprv_decContextSetStatusFromStringQuiet(decContext *context,
282                                                 const char *string) {
283   if (strcmp(string, DEC_Condition_CS)==0)
284     return uprv_decContextSetStatusQuiet(context, DEC_Conversion_syntax);
285   if (strcmp(string, DEC_Condition_DZ)==0)
286     return uprv_decContextSetStatusQuiet(context, DEC_Division_by_zero);
287   if (strcmp(string, DEC_Condition_DI)==0)
288     return uprv_decContextSetStatusQuiet(context, DEC_Division_impossible);
289   if (strcmp(string, DEC_Condition_DU)==0)
290     return uprv_decContextSetStatusQuiet(context, DEC_Division_undefined);
291   if (strcmp(string, DEC_Condition_IE)==0)
292     return uprv_decContextSetStatusQuiet(context, DEC_Inexact);
293   if (strcmp(string, DEC_Condition_IS)==0)
294     return uprv_decContextSetStatusQuiet(context, DEC_Insufficient_storage);
295   if (strcmp(string, DEC_Condition_IC)==0)
296     return uprv_decContextSetStatusQuiet(context, DEC_Invalid_context);
297   if (strcmp(string, DEC_Condition_IO)==0)
298     return uprv_decContextSetStatusQuiet(context, DEC_Invalid_operation);
299   #if DECSUBSET
300   if (strcmp(string, DEC_Condition_LD)==0)
301     return uprv_decContextSetStatusQuiet(context, DEC_Lost_digits);
302   #endif
303   if (strcmp(string, DEC_Condition_OV)==0)
304     return uprv_decContextSetStatusQuiet(context, DEC_Overflow);
305   if (strcmp(string, DEC_Condition_PA)==0)
306     return uprv_decContextSetStatusQuiet(context, DEC_Clamped);
307   if (strcmp(string, DEC_Condition_RO)==0)
308     return uprv_decContextSetStatusQuiet(context, DEC_Rounded);
309   if (strcmp(string, DEC_Condition_SU)==0)
310     return uprv_decContextSetStatusQuiet(context, DEC_Subnormal);
311   if (strcmp(string, DEC_Condition_UN)==0)
312     return uprv_decContextSetStatusQuiet(context, DEC_Underflow);
313   if (strcmp(string, DEC_Condition_ZE)==0)
314     return context;
315   return NULL;  /* Multiple status, or unknown  */
316   } /* decContextSetStatusFromStringQuiet  */
317 
318 /* ------------------------------------------------------------------ */
319 /* decContextSetStatusQuiet -- set status without trap                */
320 /*                                                                    */
321 /*  context is the context structure to be updated                    */
322 /*  status  is the DEC_ exception code                                */
323 /*  returns the context structure                                     */
324 /*                                                                    */
325 /* No error is possible.                                              */
326 /* ------------------------------------------------------------------ */
uprv_decContextSetStatusQuiet(decContext * context,uInt status)327 U_CAPI decContext *  U_EXPORT2 uprv_decContextSetStatusQuiet(decContext *context, uInt status) {
328   context->status|=status;
329   return context;} /* decContextSetStatusQuiet  */
330 
331 /* ------------------------------------------------------------------ */
332 /* decContextStatusToString -- convert status flags to a string       */
333 /*                                                                    */
334 /*  context is a context with valid status field                      */
335 /*                                                                    */
336 /*  returns a constant string describing the condition.  If multiple  */
337 /*    (or no) flags are set, a generic constant message is returned.  */
338 /* ------------------------------------------------------------------ */
uprv_decContextStatusToString(const decContext * context)339 U_CAPI const char * U_EXPORT2 uprv_decContextStatusToString(const decContext *context) {
340   Int status=context->status;
341 
342   /* test the five IEEE first, as some of the others are ambiguous when  */
343   /* DECEXTFLAG=0  */
344   if (status==DEC_Invalid_operation    ) return DEC_Condition_IO;
345   if (status==DEC_Division_by_zero     ) return DEC_Condition_DZ;
346   if (status==DEC_Overflow             ) return DEC_Condition_OV;
347   if (status==DEC_Underflow            ) return DEC_Condition_UN;
348   if (status==DEC_Inexact              ) return DEC_Condition_IE;
349 
350   if (status==DEC_Division_impossible  ) return DEC_Condition_DI;
351   if (status==DEC_Division_undefined   ) return DEC_Condition_DU;
352   if (status==DEC_Rounded              ) return DEC_Condition_RO;
353   if (status==DEC_Clamped              ) return DEC_Condition_PA;
354   if (status==DEC_Subnormal            ) return DEC_Condition_SU;
355   if (status==DEC_Conversion_syntax    ) return DEC_Condition_CS;
356   if (status==DEC_Insufficient_storage ) return DEC_Condition_IS;
357   if (status==DEC_Invalid_context      ) return DEC_Condition_IC;
358   #if DECSUBSET
359   if (status==DEC_Lost_digits          ) return DEC_Condition_LD;
360   #endif
361   if (status==0                        ) return DEC_Condition_ZE;
362   return DEC_Condition_MU;  /* Multiple errors  */
363   } /* decContextStatusToString  */
364 
365 /* ------------------------------------------------------------------ */
366 /* decContextTestEndian -- test whether DECLITEND is set correctly    */
367 /*                                                                    */
368 /*  quiet is 1 to suppress message; 0 otherwise                       */
369 /*  returns 0 if DECLITEND is correct                                 */
370 /*          1 if DECLITEND is incorrect and should be 1               */
371 /*         -1 if DECLITEND is incorrect and should be 0               */
372 /*                                                                    */
373 /* A message is displayed if the return value is not 0 and quiet==0.  */
374 /*                                                                    */
375 /* No error is possible.                                              */
376 /* ------------------------------------------------------------------ */
uprv_decContextTestEndian(Flag quiet)377 U_CAPI Int  U_EXPORT2 uprv_decContextTestEndian(Flag quiet) {
378   Int res=0;                  /* optimist  */
379   uInt dle=(uInt)DECLITEND;   /* unsign  */
380   if (dle>1) dle=1;           /* ensure 0 or 1  */
381 
382   if (LITEND!=DECLITEND) {
383     const char *adj;
384     if (!quiet) {
385       if (LITEND) adj="little";
386              else adj="big";
387       printf("Warning: DECLITEND is set to %d, but this computer appears to be %s-endian\n",
388              DECLITEND, adj);
389       }
390     res=(Int)LITEND-dle;
391     }
392   return res;
393   } /* decContextTestEndian  */
394 
395 /* ------------------------------------------------------------------ */
396 /* decContextTestSavedStatus -- test bits in saved status             */
397 /*                                                                    */
398 /*  oldstatus is the status word to be tested                         */
399 /*  mask indicates the bits to be tested (the oldstatus bits that     */
400 /*    correspond to each 1 bit in the mask are tested)                */
401 /*  returns 1 if any of the tested bits are 1, or 0 otherwise         */
402 /*                                                                    */
403 /* No error is possible.                                              */
404 /* ------------------------------------------------------------------ */
uprv_decContextTestSavedStatus(uInt oldstatus,uInt mask)405 U_CAPI  uInt U_EXPORT2 uprv_decContextTestSavedStatus(uInt oldstatus, uInt mask) {
406   return (oldstatus&mask)!=0;
407   } /* decContextTestSavedStatus  */
408 
409 /* ------------------------------------------------------------------ */
410 /* decContextTestStatus -- test bits in current status                */
411 /*                                                                    */
412 /*  context is the context structure to be updated                    */
413 /*  mask indicates the bits to be tested (the status bits that        */
414 /*    correspond to each 1 bit in the mask are tested)                */
415 /*  returns 1 if any of the tested bits are 1, or 0 otherwise         */
416 /*                                                                    */
417 /* No error is possible.                                              */
418 /* ------------------------------------------------------------------ */
uprv_decContextTestStatus(decContext * context,uInt mask)419 U_CAPI uInt  U_EXPORT2 uprv_decContextTestStatus(decContext *context, uInt mask) {
420   return (context->status&mask)!=0;
421   } /* decContextTestStatus  */
422 
423 /* ------------------------------------------------------------------ */
424 /* decContextZeroStatus -- clear all status bits                      */
425 /*                                                                    */
426 /*  context is the context structure to be updated                    */
427 /*  returns context                                                   */
428 /*                                                                    */
429 /* No error is possible.                                              */
430 /* ------------------------------------------------------------------ */
uprv_decContextZeroStatus(decContext * context)431 U_CAPI decContext * U_EXPORT2 uprv_decContextZeroStatus(decContext *context) {
432   context->status=0;
433   return context;
434   } /* decContextZeroStatus  */
435 
436