1 // vim: filetype=c:tabstop=4:ai:expandtab 2 // SPDX-License-Identifier: ICU 3 // scspell-id: a0c30a33-f62c-11ec-a4e6-80ee73e9b8e7 4 /* ------------------------------------------------------------------- */ 5 /* Decimal Context module */ 6 /* ------------------------------------------------------------------- */ 7 /* Copyright (c) IBM Corporation, 2000, 2009. All rights reserved. */ 8 /* */ 9 /* This software is made available under the terms of the ICU License. */ 10 /* */ 11 /* The description and User's Guide ("The decNumber C Library") for */ 12 /* this software is called decNumber.pdf. This document is available, */ 13 /* together with arithmetic and format specifications, testcases, and */ 14 /* 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 "decContext.h" // context and base types 27 #include "decNumberLocal.h" // decNumber local types, etc. 28 29 /* compile-time endian tester [assumes sizeof(Int)>1] */ 30 static const Int mfcone=1; // constant 1 31 static const Flag *mfctop=(const Flag *)&mfcone; // -> top byte 32 #define LITEND *mfctop // named flag; 1=little-endian 33 34 /* ------------------------------------------------------------------ */ 35 /* round-for-reround digits */ 36 /* ------------------------------------------------------------------ */ 37 const uByte DECSTICKYTAB[10]={1,1,2,3,4,6,6,7,8,9}; /* used if sticky */ 38 39 /* ------------------------------------------------------------------ */ 40 /* Powers of ten (powers[n]==10**n, 0<=n<=9) */ 41 /* ------------------------------------------------------------------ */ 42 const uInt DECPOWERS[10]={1, 10, 100, 1000, 10000, 100000, 1000000, 43 10000000, 100000000, 1000000000}; 44 45 /* ------------------------------------------------------------------ */ 46 /* decContextClearStatus -- clear bits in current status */ 47 /* */ 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) */ 51 /* returns context */ 52 /* */ 53 /* No error is possible. */ 54 /* ------------------------------------------------------------------ */ 55 decContext *decContextClearStatus(decContext *context, uInt mask) { /* */ 56 context->status&=~mask; 57 return context; 58 } // decContextClearStatus 59 60 /* ------------------------------------------------------------------ */ 61 /* decContextDefault -- initialize a context structure */ 62 /* */ 63 /* context is the structure to be initialized */ 64 /* kind selects the required set of default values, one of: */ 65 /* DEC_INIT_BASE -- select ANSI X3-274 defaults */ 66 /* DEC_INIT_DECIMAL32 -- select IEEE 754 defaults, 32-bit */ 67 /* DEC_INIT_DECIMAL64 -- select IEEE 754 defaults, 64-bit */ 68 /* DEC_INIT_DECIMAL128 -- select IEEE 754 defaults, 128-bit */ 69 /* For any other value a valid context is returned, but with */ 70 /* Invalid_operation set in the status field. */ 71 /* returns a context structure with the appropriate initial values. */ 72 /* ------------------------------------------------------------------ */ 73 decContext * decContextDefault(decContext *context, Int kind) { /* */ 74 // set defaults... 75 context->digits=9; // 9 digits 76 context->emax=DEC_MAX_EMAX; // 9-digit exponents 77 context->emin=DEC_MIN_EMIN; // .. balanced 78 context->round=DEC_ROUND_HALF_UP; // 0.5 rises 79 context->traps=DEC_Errors; // all but informational 80 context->status=0; // cleared 81 context->clamp=0; // no clamping 82 #if DECSUBSET 83 context->extended=0; // cleared 84 #endif 85 switch (kind) { 86 case DEC_INIT_BASE: 87 // [use defaults] 88 break; 89 case DEC_INIT_DECIMAL32: 90 context->digits=7; // digits 91 context->emax=96; // Emax 92 context->emin=-95; // Emin 93 context->round=DEC_ROUND_HALF_EVEN; // 0.5 to nearest even 94 context->traps=0; // no traps set 95 context->clamp=1; // clamp exponents 96 #if DECSUBSET 97 context->extended=1; // set 98 #endif 99 break; 100 case DEC_INIT_DECIMAL64: 101 context->digits=16; // digits 102 context->emax=384; // Emax 103 context->emin=-383; // Emin 104 context->round=DEC_ROUND_HALF_EVEN; // 0.5 to nearest even 105 context->traps=0; // no traps set 106 context->clamp=1; // clamp exponents 107 #if DECSUBSET 108 context->extended=1; // set 109 #endif 110 break; 111 case DEC_INIT_DECIMAL128: 112 context->digits=34; // digits 113 context->emax=6144; // Emax 114 context->emin=-6143; // Emin 115 context->round=DEC_ROUND_HALF_EVEN; // 0.5 to nearest even 116 context->traps=0; // no traps set 117 context->clamp=1; // clamp exponents 118 #if DECSUBSET 119 context->extended=1; // set 120 #endif 121 break; 122 123 default: // invalid Kind 124 // use defaults, and trap 125 (void)decContextSetStatus(context, DEC_Invalid_operation); 126 } 127 128 return context;} // decContextDefault 129 130 /* ------------------------------------------------------------------ */ 131 /* decContextGetRounding -- return current rounding mode */ 132 /* */ 133 /* context is the context structure to be queried */ 134 /* returns the rounding mode */ 135 /* */ 136 /* No error is possible. */ 137 /* ------------------------------------------------------------------ */ 138 enum rounding decContextGetRounding(decContext *context) { /* */ 139 return context->round; 140 } // decContextGetRounding 141 142 /* ------------------------------------------------------------------ */ 143 /* decContextGetStatus -- return current status */ 144 /* */ 145 /* context is the context structure to be queried */ 146 /* returns status */ 147 /* */ 148 /* No error is possible. */ 149 /* ------------------------------------------------------------------ */ 150 uInt decContextGetStatus(decContext *context) { /* */ 151 return context->status; 152 } // decContextGetStatus 153 154 /* ------------------------------------------------------------------ */ 155 /* decContextRestoreStatus -- restore bits in current status */ 156 /* */ 157 /* context is the context structure to be updated */ 158 /* newstatus is the source for the bits to be restored */ 159 /* mask indicates the bits to be restored (the status bit that */ 160 /* corresponds to each 1 bit in the mask is set to the value of */ 161 /* the corresponding bit in newstatus) */ 162 /* returns context */ 163 /* */ 164 /* No error is possible. */ 165 /* ------------------------------------------------------------------ */ 166 decContext *decContextRestoreStatus(decContext *context, /* */ 167 uInt newstatus, uInt mask) { 168 context->status&=~mask; // clear the selected bits 169 context->status|=(mask&newstatus); // or in the new bits 170 return context; 171 } // decContextRestoreStatus 172 173 /* ------------------------------------------------------------------ */ 174 /* decContextSaveStatus -- save bits in current status */ 175 /* */ 176 /* context is the context structure to be queried */ 177 /* mask indicates the bits to be saved (the status bits that */ 178 /* correspond to each 1 bit in the mask are saved) */ 179 /* returns the AND of the mask and the current status */ 180 /* */ 181 /* No error is possible. */ 182 /* ------------------------------------------------------------------ */ 183 uInt decContextSaveStatus(decContext *context, uInt mask) { /* */ 184 return context->status&mask; 185 } // decContextSaveStatus 186 187 /* ------------------------------------------------------------------ */ 188 /* decContextSetRounding -- set current rounding mode */ 189 /* */ 190 /* context is the context structure to be updated */ 191 /* newround is the value which will replace the current mode */ 192 /* returns context */ 193 /* */ 194 /* No error is possible. */ 195 /* ------------------------------------------------------------------ */ 196 decContext *decContextSetRounding(decContext *context, /* */ 197 enum rounding newround) { 198 context->round=newround; 199 return context; 200 } // decContextSetRounding 201 202 /* ------------------------------------------------------------------ */ 203 /* decContextSetStatus -- set status and raise trap if appropriate */ 204 /* */ 205 /* context is the context structure to be updated */ 206 /* status is the DEC_ exception code */ 207 /* returns the context structure */ 208 /* */ 209 /* Control may never return from this routine, if there is a signal */ 210 /* handler and it takes a long jump. */ 211 /* ------------------------------------------------------------------ */ 212 decContext * decContextSetStatus(decContext *context, uInt status) { /* */ 213 context->status|=status; 214 if (status & context->traps) raise(SIGFPE); 215 return context;} // decContextSetStatus 216 217 /* ------------------------------------------------------------------ */ 218 /* decContextSetStatusFromString -- set status from a string + trap */ 219 /* */ 220 /* context is the context structure to be updated */ 221 /* string is a string exactly equal to one that might be returned */ 222 /* by decContextStatusToString */ 223 /* */ 224 /* The status bit corresponding to the string is set, and a trap */ 225 /* is raised if appropriate. */ 226 /* */ 227 /* returns the context structure, unless the string is equal to */ 228 /* DEC_Condition_MU or is not recognized. In these cases NULL is */ 229 /* returned. */ 230 /* ------------------------------------------------------------------ */ 231 decContext * decContextSetStatusFromString(decContext *context, /* */ 232 const char *string) { 233 if (strcmp(string, DEC_Condition_CS)==0) 234 return decContextSetStatus(context, DEC_Conversion_syntax); 235 if (strcmp(string, DEC_Condition_DZ)==0) 236 return decContextSetStatus(context, DEC_Division_by_zero); 237 if (strcmp(string, DEC_Condition_DI)==0) 238 return decContextSetStatus(context, DEC_Division_impossible); 239 if (strcmp(string, DEC_Condition_DU)==0) 240 return decContextSetStatus(context, DEC_Division_undefined); 241 if (strcmp(string, DEC_Condition_IE)==0) 242 return decContextSetStatus(context, DEC_Inexact); 243 if (strcmp(string, DEC_Condition_IS)==0) 244 return decContextSetStatus(context, DEC_Insufficient_storage); 245 if (strcmp(string, DEC_Condition_IC)==0) 246 return decContextSetStatus(context, DEC_Invalid_context); 247 if (strcmp(string, DEC_Condition_IO)==0) 248 return decContextSetStatus(context, DEC_Invalid_operation); 249 #if DECSUBSET 250 if (strcmp(string, DEC_Condition_LD)==0) 251 return decContextSetStatus(context, DEC_Lost_digits); 252 #endif 253 if (strcmp(string, DEC_Condition_OV)==0) 254 return decContextSetStatus(context, DEC_Overflow); 255 if (strcmp(string, DEC_Condition_PA)==0) 256 return decContextSetStatus(context, DEC_Clamped); 257 if (strcmp(string, DEC_Condition_RO)==0) 258 return decContextSetStatus(context, DEC_Rounded); 259 if (strcmp(string, DEC_Condition_SU)==0) 260 return decContextSetStatus(context, DEC_Subnormal); 261 if (strcmp(string, DEC_Condition_UN)==0) 262 return decContextSetStatus(context, DEC_Underflow); 263 if (strcmp(string, DEC_Condition_ZE)==0) 264 return context; 265 return NULL; // Multiple status, or unknown 266 } // decContextSetStatusFromString 267 268 /* ------------------------------------------------------------------ */ 269 /* decContextSetStatusFromStringQuiet -- set status from a string */ 270 /* */ 271 /* context is the context structure to be updated */ 272 /* string is a string exactly equal to one that might be returned */ 273 /* by decContextStatusToString */ 274 /* */ 275 /* The status bit corresponding to the string is set; no trap is */ 276 /* raised. */ 277 /* */ 278 /* returns the context structure, unless the string is equal to */ 279 /* DEC_Condition_MU or is not recognized. In these cases NULL is */ 280 /* returned. */ 281 /* ------------------------------------------------------------------ */ 282 decContext * decContextSetStatusFromStringQuiet(decContext *context, /* */ 283 const char *string) { 284 if (strcmp(string, DEC_Condition_CS)==0) 285 return decContextSetStatusQuiet(context, DEC_Conversion_syntax); 286 if (strcmp(string, DEC_Condition_DZ)==0) 287 return decContextSetStatusQuiet(context, DEC_Division_by_zero); 288 if (strcmp(string, DEC_Condition_DI)==0) 289 return decContextSetStatusQuiet(context, DEC_Division_impossible); 290 if (strcmp(string, DEC_Condition_DU)==0) 291 return decContextSetStatusQuiet(context, DEC_Division_undefined); 292 if (strcmp(string, DEC_Condition_IE)==0) 293 return decContextSetStatusQuiet(context, DEC_Inexact); 294 if (strcmp(string, DEC_Condition_IS)==0) 295 return decContextSetStatusQuiet(context, DEC_Insufficient_storage); 296 if (strcmp(string, DEC_Condition_IC)==0) 297 return decContextSetStatusQuiet(context, DEC_Invalid_context); 298 if (strcmp(string, DEC_Condition_IO)==0) 299 return decContextSetStatusQuiet(context, DEC_Invalid_operation); 300 #if DECSUBSET 301 if (strcmp(string, DEC_Condition_LD)==0) 302 return decContextSetStatusQuiet(context, DEC_Lost_digits); 303 #endif 304 if (strcmp(string, DEC_Condition_OV)==0) 305 return decContextSetStatusQuiet(context, DEC_Overflow); 306 if (strcmp(string, DEC_Condition_PA)==0) 307 return decContextSetStatusQuiet(context, DEC_Clamped); 308 if (strcmp(string, DEC_Condition_RO)==0) 309 return decContextSetStatusQuiet(context, DEC_Rounded); 310 if (strcmp(string, DEC_Condition_SU)==0) 311 return decContextSetStatusQuiet(context, DEC_Subnormal); 312 if (strcmp(string, DEC_Condition_UN)==0) 313 return decContextSetStatusQuiet(context, DEC_Underflow); 314 if (strcmp(string, DEC_Condition_ZE)==0) 315 return context; 316 return NULL; // Multiple status, or unknown 317 } // decContextSetStatusFromStringQuiet 318 319 /* ------------------------------------------------------------------ */ 320 /* decContextSetStatusQuiet -- set status without trap */ 321 /* */ 322 /* context is the context structure to be updated */ 323 /* status is the DEC_ exception code */ 324 /* returns the context structure */ 325 /* */ 326 /* No error is possible. */ 327 /* ------------------------------------------------------------------ */ 328 decContext * decContextSetStatusQuiet(decContext *context, uInt status) { /* */ 329 context->status|=status; 330 return context;} // decContextSetStatusQuiet 331 332 /* ------------------------------------------------------------------ */ 333 /* decContextStatusToString -- convert status flags to a string */ 334 /* */ 335 /* context is a context with valid status field */ 336 /* */ 337 /* returns a constant string describing the condition. If multiple */ 338 /* (or no) flags are set, a generic constant message is returned. */ 339 /* ------------------------------------------------------------------ */ 340 const char *decContextStatusToString(const decContext *context) { /* */ 341 Int status=context->status; 342 343 // test the five IEEE first, as some of the others are ambiguous when 344 // DECEXTFLAG=0 345 if (status==DEC_Invalid_operation ) return DEC_Condition_IO; 346 if (status==DEC_Division_by_zero ) return DEC_Condition_DZ; 347 if (status==DEC_Overflow ) return DEC_Condition_OV; 348 if (status==DEC_Underflow ) return DEC_Condition_UN; 349 if (status==DEC_Inexact ) return DEC_Condition_IE; 350 351 if (status==DEC_Division_impossible ) return DEC_Condition_DI; 352 if (status==DEC_Division_undefined ) return DEC_Condition_DU; 353 if (status==DEC_Rounded ) return DEC_Condition_RO; 354 if (status==DEC_Clamped ) return DEC_Condition_PA; 355 if (status==DEC_Subnormal ) return DEC_Condition_SU; 356 if (status==DEC_Conversion_syntax ) return DEC_Condition_CS; 357 if (status==DEC_Insufficient_storage ) return DEC_Condition_IS; 358 if (status==DEC_Invalid_context ) return DEC_Condition_IC; 359 #if DECSUBSET 360 if (status==DEC_Lost_digits ) return DEC_Condition_LD; 361 #endif 362 if (status==0 ) return DEC_Condition_ZE; 363 return DEC_Condition_MU; // Multiple errors 364 } // decContextStatusToString 365 366 /* ------------------------------------------------------------------ */ 367 /* decContextTestEndian -- test whether DECLITEND is set correctly */ 368 /* */ 369 /* quiet is 1 to suppress message; 0 otherwise */ 370 /* returns 0 if DECLITEND is correct */ 371 /* 1 if DECLITEND is incorrect and should be 1 */ 372 /* -1 if DECLITEND is incorrect and should be 0 */ 373 /* */ 374 /* A message is displayed if the return value is not 0 and quiet==0. */ 375 /* */ 376 /* No error is possible. */ 377 /* ------------------------------------------------------------------ */ 378 Int decContextTestEndian(void) { /* */ 379 Int res=0; // optimist 380 uInt dle=(uInt)DECLITEND; // unsign 381 /* cppcheck-suppress knownConditionTrueFalse */ 382 if (dle>1) dle=1; //-V547 383 384 if (LITEND!=DECLITEND) { 385 res=(Int)LITEND-dle; 386 } 387 return res; 388 } // decContextTestEndian 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 uInt 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 uInt 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 decContext *decContextZeroStatus(decContext *context) { /* */ 427 context->status=0; 428 return context; 429 } // decContextZeroStatus 430