1// Copyright (C) 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] */ 32static const Int mfcone=1; /* constant 1 */ 33static 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/* ------------------------------------------------------------------ */ 47U_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/* ------------------------------------------------------------------ */ 65U_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/* ------------------------------------------------------------------ */ 130U_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/* ------------------------------------------------------------------ */ 142U_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 correspnding bit in newstatus) */ 154/* returns context */ 155/* */ 156/* No error is possible. */ 157/* ------------------------------------------------------------------ */ 158U_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/* ------------------------------------------------------------------ */ 175U_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/* ------------------------------------------------------------------ */ 188U_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/* ------------------------------------------------------------------ */ 204U_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 NULL is */ 223/* returned. */ 224/* ------------------------------------------------------------------ */ 225U_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 NULL; /* 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 NULL is */ 274/* returned. */ 275/* ------------------------------------------------------------------ */ 276U_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 NULL; /* 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/* ------------------------------------------------------------------ */ 322U_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/* ------------------------------------------------------------------ */ 334U_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(). */ 373U_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/* ------------------------------------------------------------------ */ 402U_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/* ------------------------------------------------------------------ */ 416U_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/* ------------------------------------------------------------------ */ 428U_CAPI decContext * U_EXPORT2 uprv_decContextZeroStatus(decContext *context) { 429 context->status=0; 430 return context; 431 } /* decContextZeroStatus */ 432 433