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