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@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] */ 30static const Int mfcone=1; /* constant 1 */ 31static 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/* ------------------------------------------------------------------ */ 45U_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/* ------------------------------------------------------------------ */ 63U_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/* ------------------------------------------------------------------ */ 128U_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/* ------------------------------------------------------------------ */ 140U_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/* ------------------------------------------------------------------ */ 156U_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/* ------------------------------------------------------------------ */ 173U_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/* ------------------------------------------------------------------ */ 186U_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/* ------------------------------------------------------------------ */ 202U_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/* ------------------------------------------------------------------ */ 223U_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/* ------------------------------------------------------------------ */ 274U_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/* ------------------------------------------------------------------ */ 320U_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/* ------------------------------------------------------------------ */ 332U_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(). */ 371U_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/* ------------------------------------------------------------------ */ 400U_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/* ------------------------------------------------------------------ */ 414U_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/* ------------------------------------------------------------------ */ 426U_CAPI decContext * U_EXPORT2 uprv_decContextZeroStatus(decContext *context) { 427 context->status=0; 428 return context; 429 } /* decContextZeroStatus */ 430 431