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