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