00001 /* ------------------------------------------------------------------ */ 00002 /* Decimal Context module */ 00003 /* ------------------------------------------------------------------ */ 00004 /* Copyright (c) IBM Corporation, 2000, 2005. All rights reserved. */ 00005 /* */ 00006 /* This software is made available under the terms of the IBM */ 00007 /* alphaWorks License Agreement (distributed with this software as */ 00008 /* alphaWorks-License.txt). Your use of this software indicates */ 00009 /* your acceptance of the terms and conditions of that Agreement. */ 00010 /* */ 00011 /* The description and User's Guide ("The decNumber C Library") for */ 00012 /* this software is called decNumber.pdf. This document is */ 00013 /* available, together with arithmetic and format specifications, */ 00014 /* testcases, and Web links, on the General Decimal Arithmetic page. */ 00015 /* */ 00016 /* Please send comments, suggestions, and corrections to the author: */ 00017 /* mfc@uk.ibm.com */ 00018 /* Mike Cowlishaw, IBM Fellow */ 00019 /* IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK */ 00020 /* ------------------------------------------------------------------ */ 00021 /* This module comprises the routines for handling arithmetic */ 00022 /* context structures. */ 00023 /* ------------------------------------------------------------------ */ 00024 00025 #include <string.h> // for strcmp 00026 #include <stdio.h> // for printf if DECCHECK 00027 #include "decContext.h" // context and base types 00028 #include "decNumberLocal.h" // decNumber local types, etc. 00029 00030 00031 00032 00033 /* compile-time endian tester [assumes sizeof(Int)>1] */ 00034 static const Int mfcone=1; // constant 1 00035 static const Flag *mfctop=(Flag *)&mfcone; // -> top byte 00036 #define LITEND *mfctop // named flag; 1=little-endian 00037 00038 /* ------------------------------------------------------------------ */ 00039 /* round-for-reround digits */ 00040 /* ------------------------------------------------------------------ */ 00041 const uByte DECSTICKYTAB[10]={1,1,2,3,4,6,6,7,8,9}; /* used if sticky */ 00042 00043 /* ------------------------------------------------------------------ */ 00044 /* Powers of ten (powers[n]==10**n, 0<=n<=9) */ 00045 /* ------------------------------------------------------------------ */ 00046 const uInt DECPOWERS[10]={1, 10, 100, 1000, 10000, 100000, 1000000, 00047 10000000, 100000000, 1000000000}; 00048 00049 /* ------------------------------------------------------------------ */ 00050 /* decContextClearStatus -- clear bits in current status */ 00051 /* */ 00052 /* context is the context structure to be queried */ 00053 /* mask indicates the bits to be cleared (the status bit that */ 00054 /* corresponds to each 1 bit in the mask is cleared) */ 00055 /* returns context */ 00056 /* */ 00057 /* No error is possible. */ 00058 /* ------------------------------------------------------------------ */ 00059 decContext *decContextClearStatus(decContext *context, uInt mask) { 00060 context->status&=~mask; 00061 return context; 00062 } // decContextClearStatus 00063 00064 /* ------------------------------------------------------------------ */ 00065 /* decContextDefault -- initialize a context structure */ 00066 /* */ 00067 /* context is the structure to be initialized */ 00068 /* kind selects the required set of default values, one of: */ 00069 /* DEC_INIT_BASE -- select ANSI X3-274 defaults */ 00070 /* DEC_INIT_DECIMAL32 -- select IEEE 754 defaults, 32-bit */ 00071 /* DEC_INIT_DECIMAL64 -- select IEEE 754 defaults, 64-bit */ 00072 /* DEC_INIT_DECIMAL128 -- select IEEE 754 defaults, 128-bit */ 00073 /* For any other value a valid context is returned, but with */ 00074 /* Invalid_operation set in the status field. */ 00075 /* returns a context structure with the appropriate initial values. */ 00076 /* ------------------------------------------------------------------ */ 00077 decContext * decContextDefault(decContext *context, Int kind) { 00078 // set defaults... 00079 context->digits=9; // 9 digits 00080 context->emax=DEC_MAX_EMAX; // 9-digit exponents 00081 context->emin=DEC_MIN_EMIN; // .. balanced 00082 context->round=DEC_ROUND_HALF_UP; // 0.5 rises 00083 context->traps=DEC_Errors; // all but informational 00084 context->status=0; // cleared 00085 context->clamp=0; // no clamping 00086 #if DECSUBSET 00087 context->extended=0; // cleared 00088 #endif 00089 switch (kind) { 00090 case DEC_INIT_BASE: 00091 // [use defaults] 00092 break; 00093 case DEC_INIT_DECIMAL32: 00094 context->digits=7; // digits 00095 context->emax=96; // Emax 00096 context->emin=-95; // Emin 00097 context->round=DEC_ROUND_HALF_EVEN; // 0.5 to nearest even 00098 context->traps=0; // no traps set 00099 context->clamp=1; // clamp exponents 00100 #if DECSUBSET 00101 context->extended=1; // set 00102 #endif 00103 break; 00104 case DEC_INIT_DECIMAL64: 00105 context->digits=16; // digits 00106 context->emax=384; // Emax 00107 context->emin=-383; // Emin 00108 context->round=DEC_ROUND_HALF_EVEN; // 0.5 to nearest even 00109 context->traps=0; // no traps set 00110 context->clamp=1; // clamp exponents 00111 #if DECSUBSET 00112 context->extended=1; // set 00113 #endif 00114 break; 00115 case DEC_INIT_DECIMAL128: 00116 context->digits=34; // digits 00117 context->emax=6144; // Emax 00118 context->emin=-6143; // Emin 00119 context->round=DEC_ROUND_HALF_EVEN; // 0.5 to nearest even 00120 context->traps=0; // no traps set 00121 context->clamp=1; // clamp exponents 00122 #if DECSUBSET 00123 context->extended=1; // set 00124 #endif 00125 break; 00126 00127 default: // invalid Kind 00128 // use defaults, and .. 00129 decContextSetStatus(context, DEC_Invalid_operation); // trap 00130 } 00131 00132 return context;} // decContextDefault 00133 00134 /* ------------------------------------------------------------------ */ 00135 /* decContextGetRounding -- return current rounding mode */ 00136 /* */ 00137 /* context is the context structure to be queried */ 00138 /* returns the rounding mode */ 00139 /* */ 00140 /* No error is possible. */ 00141 /* ------------------------------------------------------------------ */ 00142 enum rounding decContextGetRounding(decContext *context) { 00143 return context->round; 00144 } // decContextGetRounding 00145 00146 /* ------------------------------------------------------------------ */ 00147 /* decContextGetStatus -- return current status */ 00148 /* */ 00149 /* context is the context structure to be queried */ 00150 /* returns status */ 00151 /* */ 00152 /* No error is possible. */ 00153 /* ------------------------------------------------------------------ */ 00154 uInt decContextGetStatus(decContext *context) { 00155 return context->status; 00156 } // decContextGetStatus 00157 00158 /* ------------------------------------------------------------------ */ 00159 /* decContextRestoreStatus -- restore bits in current status */ 00160 /* */ 00161 /* context is the context structure to be updated */ 00162 /* newstatus is the source for the bits to be restored */ 00163 /* mask indicates the bits to be restored (the status bit that */ 00164 /* corresponds to each 1 bit in the mask is set to the value of */ 00165 /* the correspnding bit in newstatus) */ 00166 /* returns context */ 00167 /* */ 00168 /* No error is possible. */ 00169 /* ------------------------------------------------------------------ */ 00170 decContext *decContextRestoreStatus(decContext *context, 00171 uInt newstatus, uInt mask) { 00172 context->status&=~mask; // clear the selected bits 00173 context->status|=(mask&newstatus); // or in the new bits 00174 return context; 00175 } // decContextRestoreStatus 00176 00177 /* ------------------------------------------------------------------ */ 00178 /* decContextSaveStatus -- save bits in current status */ 00179 /* */ 00180 /* context is the context structure to be queried */ 00181 /* mask indicates the bits to be saved (the status bits that */ 00182 /* correspond to each 1 bit in the mask are saved) */ 00183 /* returns the AND of the mask and the current status */ 00184 /* */ 00185 /* No error is possible. */ 00186 /* ------------------------------------------------------------------ */ 00187 uInt decContextSaveStatus(decContext *context, uInt mask) { 00188 return context->status&mask; 00189 } // decContextSaveStatus 00190 00191 /* ------------------------------------------------------------------ */ 00192 /* decContextSetRounding -- set current rounding mode */ 00193 /* */ 00194 /* context is the context structure to be updated */ 00195 /* newround is the value which will replace the current mode */ 00196 /* returns context */ 00197 /* */ 00198 /* No error is possible. */ 00199 /* ------------------------------------------------------------------ */ 00200 decContext *decContextSetRounding(decContext *context, 00201 enum rounding newround) { 00202 context->round=newround; 00203 return context; 00204 } // decContextSetRounding 00205 00206 /* ------------------------------------------------------------------ */ 00207 /* decContextSetStatus -- set status and raise trap if appropriate */ 00208 /* */ 00209 /* context is the context structure to be updated */ 00210 /* status is the DEC_ exception code */ 00211 /* returns the context structure */ 00212 /* */ 00213 /* Control may never return from this routine, if there is a signal */ 00214 /* handler and it takes a long jump. */ 00215 /* ------------------------------------------------------------------ */ 00216 decContext * decContextSetStatus(decContext *context, uInt status) { 00217 context->status|=status; 00218 if (status & context->traps) raise(SIGFPE); 00219 return context;} // decContextSetStatus 00220 00221 /* ------------------------------------------------------------------ */ 00222 /* decContextSetStatusFromString -- set status from a string + trap */ 00223 /* */ 00224 /* context is the context structure to be updated */ 00225 /* string is a string exactly equal to one that might be returned */ 00226 /* by decContextStatusToString */ 00227 /* */ 00228 /* The status bit corresponding to the string is set, and a trap */ 00229 /* is raised if appropriate. */ 00230 /* */ 00231 /* returns the context structure, unless the string is equal to */ 00232 /* DEC_Condition_MU or is not recognized. In these cases NULL is */ 00233 /* returned. */ 00234 /* ------------------------------------------------------------------ */ 00235 decContext * decContextSetStatusFromString(decContext *context, 00236 const char *string) { 00237 if (strcmp(string, DEC_Condition_CS)==0) 00238 return decContextSetStatus(context, DEC_Conversion_syntax); 00239 if (strcmp(string, DEC_Condition_DZ)==0) 00240 return decContextSetStatus(context, DEC_Division_by_zero); 00241 if (strcmp(string, DEC_Condition_DI)==0) 00242 return decContextSetStatus(context, DEC_Division_impossible); 00243 if (strcmp(string, DEC_Condition_DU)==0) 00244 return decContextSetStatus(context, DEC_Division_undefined); 00245 if (strcmp(string, DEC_Condition_IE)==0) 00246 return decContextSetStatus(context, DEC_Inexact); 00247 if (strcmp(string, DEC_Condition_IS)==0) 00248 return decContextSetStatus(context, DEC_Insufficient_storage); 00249 if (strcmp(string, DEC_Condition_IC)==0) 00250 return decContextSetStatus(context, DEC_Invalid_context); 00251 if (strcmp(string, DEC_Condition_IO)==0) 00252 return decContextSetStatus(context, DEC_Invalid_operation); 00253 #if DECSUBSET 00254 if (strcmp(string, DEC_Condition_LD)==0) 00255 return decContextSetStatus(context, DEC_Lost_digits); 00256 #endif 00257 if (strcmp(string, DEC_Condition_OV)==0) 00258 return decContextSetStatus(context, DEC_Overflow); 00259 if (strcmp(string, DEC_Condition_PA)==0) 00260 return decContextSetStatus(context, DEC_Clamped); 00261 if (strcmp(string, DEC_Condition_RO)==0) 00262 return decContextSetStatus(context, DEC_Rounded); 00263 if (strcmp(string, DEC_Condition_SU)==0) 00264 return decContextSetStatus(context, DEC_Subnormal); 00265 if (strcmp(string, DEC_Condition_UN)==0) 00266 return decContextSetStatus(context, DEC_Underflow); 00267 if (strcmp(string, DEC_Condition_ZE)==0) 00268 return context; 00269 return NULL; // Multiple status, or unknown 00270 } // decContextSetStatusFromString 00271 00272 /* ------------------------------------------------------------------ */ 00273 /* decContextSetStatusFromStringQuiet -- set status from a string */ 00274 /* */ 00275 /* context is the context structure to be updated */ 00276 /* string is a string exactly equal to one that might be returned */ 00277 /* by decContextStatusToString */ 00278 /* */ 00279 /* The status bit corresponding to the string is set; no trap is */ 00280 /* raised. */ 00281 /* */ 00282 /* returns the context structure, unless the string is equal to */ 00283 /* DEC_Condition_MU or is not recognized. In these cases NULL is */ 00284 /* returned. */ 00285 /* ------------------------------------------------------------------ */ 00286 decContext * decContextSetStatusFromStringQuiet(decContext *context, 00287 const char *string) { 00288 if (strcmp(string, DEC_Condition_CS)==0) 00289 return decContextSetStatusQuiet(context, DEC_Conversion_syntax); 00290 if (strcmp(string, DEC_Condition_DZ)==0) 00291 return decContextSetStatusQuiet(context, DEC_Division_by_zero); 00292 if (strcmp(string, DEC_Condition_DI)==0) 00293 return decContextSetStatusQuiet(context, DEC_Division_impossible); 00294 if (strcmp(string, DEC_Condition_DU)==0) 00295 return decContextSetStatusQuiet(context, DEC_Division_undefined); 00296 if (strcmp(string, DEC_Condition_IE)==0) 00297 return decContextSetStatusQuiet(context, DEC_Inexact); 00298 if (strcmp(string, DEC_Condition_IS)==0) 00299 return decContextSetStatusQuiet(context, DEC_Insufficient_storage); 00300 if (strcmp(string, DEC_Condition_IC)==0) 00301 return decContextSetStatusQuiet(context, DEC_Invalid_context); 00302 if (strcmp(string, DEC_Condition_IO)==0) 00303 return decContextSetStatusQuiet(context, DEC_Invalid_operation); 00304 #if DECSUBSET 00305 if (strcmp(string, DEC_Condition_LD)==0) 00306 return decContextSetStatusQuiet(context, DEC_Lost_digits); 00307 #endif 00308 if (strcmp(string, DEC_Condition_OV)==0) 00309 return decContextSetStatusQuiet(context, DEC_Overflow); 00310 if (strcmp(string, DEC_Condition_PA)==0) 00311 return decContextSetStatusQuiet(context, DEC_Clamped); 00312 if (strcmp(string, DEC_Condition_RO)==0) 00313 return decContextSetStatusQuiet(context, DEC_Rounded); 00314 if (strcmp(string, DEC_Condition_SU)==0) 00315 return decContextSetStatusQuiet(context, DEC_Subnormal); 00316 if (strcmp(string, DEC_Condition_UN)==0) 00317 return decContextSetStatusQuiet(context, DEC_Underflow); 00318 if (strcmp(string, DEC_Condition_ZE)==0) 00319 return context; 00320 return NULL; // Multiple status, or unknown 00321 } // decContextSetStatusFromStringQuiet 00322 00323 /* ------------------------------------------------------------------ */ 00324 /* decContextSetStatusQuiet -- set status without trap */ 00325 /* */ 00326 /* context is the context structure to be updated */ 00327 /* status is the DEC_ exception code */ 00328 /* returns the context structure */ 00329 /* */ 00330 /* No error is possible. */ 00331 /* ------------------------------------------------------------------ */ 00332 decContext * decContextSetStatusQuiet(decContext *context, uInt status) { 00333 context->status|=status; 00334 return context;} // decContextSetStatusQuiet 00335 00336 /* ------------------------------------------------------------------ */ 00337 /* decContextStatusToString -- convert status flags to a string */ 00338 /* */ 00339 /* context is a context with valid status field */ 00340 /* */ 00341 /* returns a constant string describing the condition. If multiple */ 00342 /* (or no) flags are set, a generic constant message is returned. */ 00343 /* ------------------------------------------------------------------ */ 00344 const char *decContextStatusToString(const decContext *context) { 00345 Int status=context->status; 00346 00347 // test the five IEEE first, as some of the others are ambiguous when 00348 // DECEXTFLAG=0 00349 if (status==DEC_Invalid_operation ) return DEC_Condition_IO; 00350 if (status==DEC_Division_by_zero ) return DEC_Condition_DZ; 00351 if (status==DEC_Overflow ) return DEC_Condition_OV; 00352 if (status==DEC_Underflow ) return DEC_Condition_UN; 00353 if (status==DEC_Inexact ) return DEC_Condition_IE; 00354 00355 if (status==DEC_Division_impossible ) return DEC_Condition_DI; 00356 if (status==DEC_Division_undefined ) return DEC_Condition_DU; 00357 if (status==DEC_Rounded ) return DEC_Condition_RO; 00358 if (status==DEC_Clamped ) return DEC_Condition_PA; 00359 if (status==DEC_Subnormal ) return DEC_Condition_SU; 00360 if (status==DEC_Conversion_syntax ) return DEC_Condition_CS; 00361 if (status==DEC_Insufficient_storage ) return DEC_Condition_IS; 00362 if (status==DEC_Invalid_context ) return DEC_Condition_IC; 00363 #if DECSUBSET 00364 if (status==DEC_Lost_digits ) return DEC_Condition_LD; 00365 #endif 00366 if (status==0 ) return DEC_Condition_ZE; 00367 return DEC_Condition_MU; // Multiple errors 00368 } // decContextStatusToString 00369 00370 /* ------------------------------------------------------------------ */ 00371 /* decContextTestEndian -- test whether DECLITEND is set correctly */ 00372 /* */ 00373 /* quiet is 1 to suppress message; 0 otherwise */ 00374 /* returns 0 if DECLITEND is correct */ 00375 /* 1 if DECLITEND is incorrect and should be 1 */ 00376 /* -1 if DECLITEND is incorrect and should be 0 */ 00377 /* */ 00378 /* A message is displayed if the return value is not 0 and quiet==0. */ 00379 /* */ 00380 /* No error is possible. */ 00381 /* ------------------------------------------------------------------ */ 00382 Int decContextTestEndian(Flag quiet) { 00383 Int res=0; // optimist 00384 uInt dle=(uInt)DECLITEND; // unsign 00385 if (dle>1) dle=1; // ensure 0 or 1 00386 00387 if (LITEND!=DECLITEND) { 00388 const char *adj; 00389 if (!quiet) { 00390 if (LITEND) adj="little"; 00391 else adj="big"; 00392 printf("Warning: DECLITEND is set to %d, but this computer appears to be %s-endian\n", 00393 DECLITEND, adj); 00394 } 00395 res=(Int)LITEND-dle; 00396 } 00397 return res; 00398 } // decContextTestEndian 00399 00400 /* ------------------------------------------------------------------ */ 00401 /* decContextTestSavedStatus -- test bits in saved status */ 00402 /* */ 00403 /* oldstatus is the status word to be tested */ 00404 /* mask indicates the bits to be tested (the oldstatus bits that */ 00405 /* correspond to each 1 bit in the mask are tested) */ 00406 /* returns 1 if any of the tested bits are 1, or 0 otherwise */ 00407 /* */ 00408 /* No error is possible. */ 00409 /* ------------------------------------------------------------------ */ 00410 uInt decContextTestSavedStatus(uInt oldstatus, uInt mask) { 00411 return (oldstatus&mask)!=0; 00412 } // decContextTestSavedStatus 00413 00414 /* ------------------------------------------------------------------ */ 00415 /* decContextTestStatus -- test bits in current status */ 00416 /* */ 00417 /* context is the context structure to be updated */ 00418 /* mask indicates the bits to be tested (the status bits that */ 00419 /* correspond to each 1 bit in the mask are tested) */ 00420 /* returns 1 if any of the tested bits are 1, or 0 otherwise */ 00421 /* */ 00422 /* No error is possible. */ 00423 /* ------------------------------------------------------------------ */ 00424 uInt decContextTestStatus(decContext *context, uInt mask) { 00425 return (context->status&mask)!=0; 00426 } // decContextTestStatus 00427 00428 /* ------------------------------------------------------------------ */ 00429 /* decContextZeroStatus -- clear all status bits */ 00430 /* */ 00431 /* context is the context structure to be updated */ 00432 /* returns context */ 00433 /* */ 00434 /* No error is possible. */ 00435 /* ------------------------------------------------------------------ */ 00436 decContext *decContextZeroStatus(decContext *context) { 00437 context->status=0; 00438 return context; 00439 } // decContextZeroStatus 00440 00441 00442 00443 00444