/* Modified version, for use from within ICU. * Renamed public functions, to avoid an unwanted export of the * standard names from the ICU library. * * Use ICU's uprv_malloc() and uprv_free() * * Revert comment syntax to plain C * * Remove a few compiler warnings.
*/
/* This module comprises the routines for arbitrary-precision General */ /* Decimal Arithmetic as defined in the specification which may be */ /* found on the General Decimal Arithmetic pages. It implements both */ /* the full ('extended') arithmetic and the simpler ('subset') */ /* arithmetic. */ /* */ /* Usage notes: */ /* */ /* 1. This code is ANSI C89 except: */ /* */ /* a) C99 line comments (double forward slash) are used. (Most C */ /* compilers accept these. If yours does not, a simple script */ /* can be used to convert them to ANSI C comments.) */ /* */ /* b) Types from C99 stdint.h are used. If you do not have this */ /* header file, see the User's Guide section of the decNumber */ /* documentation; this lists the necessary definitions. */ /* */ /* c) If DECDPUN>4 or DECUSE64=1, the C99 64-bit int64_t and */ /* uint64_t types may be used. To avoid these, set DECUSE64=0 */ /* and DECDPUN<=4 (see documentation). */ /* */ /* The code also conforms to C99 restrictions; in particular, */ /* strict aliasing rules are observed. */ /* */ /* 2. The decNumber format which this library uses is optimized for */ /* efficient processing of relatively short numbers; in particular */ /* it allows the use of fixed sized structures and minimizes copy */ /* and move operations. It does, however, support arbitrary */ /* precision (up to 999,999,999 digits) and arbitrary exponent */ /* range (Emax in the range 0 through 999,999,999 and Emin in the */ /* range -999,999,999 through 0). Mathematical functions (for */ /* example decNumberExp) as identified below are restricted more */ /* tightly: digits, emax, and -emin in the context must be <= */ /* DEC_MAX_MATH (999999), and their operand(s) must be within */ /* these bounds. */ /* */ /* 3. Logical functions are further restricted; their operands must */ /* be finite, positive, have an exponent of zero, and all digits */ /* must be either 0 or 1. The result will only contain digits */ /* which are 0 or 1 (and will have exponent=0 and a sign of 0). */ /* */ /* 4. Operands to operator functions are never modified unless they */ /* are also specified to be the result number (which is always */ /* permitted). Other than that case, operands must not overlap. */ /* */ /* 5. Error handling: the type of the error is ORed into the status */ /* flags in the current context (decContext structure). The */ /* SIGFPE signal is then raised if the corresponding trap-enabler */ /* flag in the decContext is set (is 1). */ /* */ /* It is the responsibility of the caller to clear the status */ /* flags as required. */ /* */ /* The result of any routine which returns a number will always */ /* be a valid number (which may be a special value, such as an */ /* Infinity or NaN). */ /* */ /* 6. The decNumber format is not an exchangeable concrete */ /* representation as it comprises fields which may be machine- */ /* dependent (packed or unpacked, or special length, for example). */ /* Canonical conversions to and from strings are provided; other */ /* conversions are available in separate modules. */ /* */ /* 7. Normally, input operands are assumed to be valid. Set DECCHECK */ /* to 1 for extended operand checking (including nullptr operands). */ /* Results are undefined if a badly-formed structure (or a nullptr */ /* pointer to a structure) is provided, though with DECCHECK */ /* enabled the operator routines are protected against exceptions. */ /* (Except if the result pointer is nullptr, which is unrecoverable.) */ /* */ /* However, the routines will never cause exceptions if they are */ /* given well-formed operands, even if the value of the operands */ /* is inappropriate for the operation and DECCHECK is not set. */ /* (Except for SIGFPE, as and where documented.) */ /* */ /* 8. Subset arithmetic is available only if DECSUBSET is set to 1. */ /* ------------------------------------------------------------------ */ /* Implementation notes for maintenance of this module: */ /* */ /* 1. Storage leak protection: Routines which use malloc are not */ /* permitted to use return for fastpath or error exits (i.e., */ /* they follow strict structured programming conventions). */ /* Instead they have a do{}while(0); construct surrounding the */ /* code which is protected -- break may be used to exit this. */ /* Other routines can safely use the return statement inline. */ /* */ /* Storage leak accounting can be enabled using DECALLOC. */ /* */ /* 2. All loops use the for(;;) construct. Any do construct does */ /* not loop; it is for allocation protection as just described. */ /* */ /* 3. Setting status in the context must always be the very last */ /* action in a routine, as non-0 status may raise a trap and hence */ /* the call to set status may not return (if the handler uses long */ /* jump). Therefore all cleanup must be done first. In general, */ /* to achieve this status is accumulated and is only applied just */ /* before return by calling decContextSetStatus (via decStatus). */ /* */ /* Routines which allocate storage cannot, in general, use the */ /* 'top level' routines which could cause a non-returning */ /* transfer of control. The decXxxxOp routines are safe (do not */ /* call decStatus even if traps are set in the context) and should */ /* be used instead (they are also a little faster). */ /* */ /* 4. Exponent checking is minimized by allowing the exponent to */ /* grow outside its limits during calculations, provided that */ /* the decFinalize function is called later. Multiplication and */ /* division, and intermediate calculations in exponentiation, */ /* require more careful checks because of the risk of 31-bit */ /* overflow (the most negative valid exponent is -1999999997, for */ /* a 999999999-digit number with adjusted exponent of -999999999). */ /* */ /* 5. Rounding is deferred until finalization of results, with any */ /* 'off to the right' data being represented as a single digit */ /* residue (in the range -1 through 9). This avoids any double- */ /* rounding when more than one shortening takes place (for */ /* example, when a result is subnormal). */ /* */ /* 6. The digits count is allowed to rise to a multiple of DECDPUN */ /* during many operations, so whole Units are handled and exact */ /* accounting of digits is not needed. The correct digits value */ /* is found by decGetDigits, which accounts for leading zeros. */ /* This must be called before any rounding if the number of digits */ /* is not known exactly. */ /* */ /* 7. The multiply-by-reciprocal 'trick' is used for partitioning */ /* numbers up to four digits, using appropriate constants. This */ /* is not useful for longer numbers because overflow of 32 bits */ /* would lead to 4 multiplies, which is almost as expensive as */ /* a divide (unless a floating-point or 64-bit multiply is */ /* assumed to be available). */ /* */ /* 8. Unusual abbreviations that may be used in the commentary: */ /* lhs -- left hand side (operand, of an operation) */ /* lsd -- least significant digit (of coefficient) */ /* lsu -- least significant Unit (of coefficient) */ /* msd -- most significant digit (of coefficient) */ /* msi -- most significant item (in an array) */ /* msu -- most significant Unit (of coefficient) */ /* rhs -- right hand side (operand, of an operation) */ /* +ve -- positive */ /* -ve -- negative */ /* ** -- raise to the power */ /* ------------------------------------------------------------------ */
#include <stdlib.h> /* for malloc, free, etc. */ /* #include <stdio.h> */ /* for printf [if needed] */ #include <string.h> /* for strcpy */ #include <ctype.h> /* for lower */ #include"cmemory.h"/* for uprv_malloc, etc., in ICU */ #include"decNumber.h"/* base number library */ #include"decNumberLocal.h"/* decNumber local types, etc. */ #include"uassert.h"
/* Constants */ /* Public lookup table used by the D2U macro */ staticconst uByte d2utable[DECMAXD2U+1]=D2UTABLE;
#define DECVERB 1 /* set to 1 for verbose DECCHECK */ #define powers DECPOWERS /* old internal name */
/* Granularity-dependent code */ #if DECDPUN<=4 #define eInt Int/* extended integer */ #define ueInt uInt /* unsigned extended integer */ /* Constant multipliers for divide-by-power-of five using reciprocal */ /* multiply, after removing powers of 2 by shifting, and final shift */ /* of 17 [we only need up to **4] */ staticconst uInt multies[]={131073, 26215, 5243, 1049, 210}; /* QUOT10 -- macro to return the quotient of unit u divided by 10**n */ #define QUOT10(u, n) ((((uInt)(u)>>(n))*multies[n])>>17) #else /* For DECDPUN>4 non-ANSI-89 64-bit types are needed. */ #if !DECUSE64 #error decNumber.c: DECUSE64 must be 1 when DECDPUN>4 #endif #define eInt Long/* extended integer */ #define ueInt uLong /* unsigned extended integer */ #endif
/* For use in ICU */ #define malloc(a) uprv_malloc(a) #define free(a) uprv_free(a)
/* Diagnostic macros, etc. */ #if DECALLOC /* Handle malloc/free accounting. If enabled, our accountable routines */ /* are used; otherwise the code just goes straight to the system malloc */ /* and free routines. */ #define malloc(a) decMalloc(a) #define free(a) decFree(a) #define DECFENCE 0x5a /* corruption detector */ /* 'Our' malloc and free: */ staticvoid *decMalloc(size_t); staticvoid decFree(void *);
uInt decAllocBytes=0; /* count of bytes allocated */ /* Note that DECALLOC code only checks for storage buffer overflow. */ /* To check for memory leaks, the decAllocBytes variable must be */ /* checked to be 0 at appropriate times (e.g., after the test */ /* harness completes a set of tests). This checking may be unreliable */ /* if the testing is done in a multi-thread environment. */ #endif
#if DECCHECK /* Optional checking routines. Enabling these means that decNumber */ /* and decContext operands to operator routines are checked for */ /* correctness. This roughly doubles the execution time of the */ /* fastest routines (and adds 600+ bytes), so should not normally be */ /* used in 'production'. */ /* decCheckInexact is used to check that inexact results have a full */ /* complement of digits (where appropriate -- this is not the case */ /* for Quantize, for example) */ #define DECUNRESU ((decNumber *)(void *)0xffffffff) #define DECUNUSED ((const decNumber *)(void *)0xffffffff) #define DECUNCONT ((decContext *)(void *)(0xffffffff)) static Flag decCheckOperands(decNumber *, const decNumber *, const decNumber *, decContext *); static Flag decCheckNumber(const decNumber *); staticvoid decCheckInexact(const decNumber *, decContext *); #endif
#if DECTRACE || DECCHECK /* Optional trace/debugging routines (may or may not be used) */ void decNumberShow(const decNumber *); /* displays the components of a number */ staticvoid decDumpAr(char, const Unit *, Int); #endif
/* ------------------------------------------------------------------ */ /* from-int32 -- conversion from Int or uInt */ /* */ /* dn is the decNumber to receive the integer */ /* in or uin is the integer to be converted */ /* returns dn */ /* */ /* No error is possible. */ /* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberFromInt32(decNumber *dn, Int in) {
uInt unsig; if (in>=0) unsig=in; else { /* negative (possibly BADINT) */ if (in==BADINT) unsig=(uInt)1073741824*2; /* special case */ else unsig=-in; /* invert */
} /* in is now positive */
uprv_decNumberFromUInt32(dn, unsig); if (in<0) dn->bits=DECNEG; /* sign needed */ return dn;
} /* decNumberFromInt32 */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberFromUInt32(decNumber *dn, uInt uin) {
Unit *up; /* work pointer */
uprv_decNumberZero(dn); /* clean */ if (uin==0) return dn; /* [or decGetDigits bad call] */ for (up=dn->lsu; uin>0; up++) {
*up=(Unit)(uin%(DECDPUNMAX+1));
uin=uin/(DECDPUNMAX+1);
}
dn->digits=decGetDigits(dn->lsu, static_cast<int32_t>(up - dn->lsu)); return dn;
} /* decNumberFromUInt32 */
/* ------------------------------------------------------------------ */ /* to-int32 -- conversion to Int or uInt */ /* */ /* dn is the decNumber to convert */ /* set is the context for reporting errors */ /* returns the converted decNumber, or 0 if Invalid is set */ /* */ /* Invalid is set if the decNumber does not have exponent==0 or if */ /* it is a NaN, Infinite, or out-of-range. */ /* ------------------------------------------------------------------ */
U_CAPI Int U_EXPORT2 uprv_decNumberToInt32(const decNumber *dn, decContext *set) { #if DECCHECK if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0; #endif
/* special or too many digits, or bad exponent */ if (dn->bits&DECSPECIAL || dn->digits>10 || dn->exponent!=0) ; /* bad */ else { /* is a finite integer with 10 or fewer digits */ Int d; /* work */ const Unit *up; /* .. */
uInt hi=0, lo; /* .. */
up=dn->lsu; /* -> lsu */
lo=*up; /* get 1 to 9 digits */ #if DECDPUN>1 /* split to higher */
hi=lo/10;
lo=lo%10; #endif
up++; /* collect remaining Units, if any, into hi */ for (d=DECDPUN; d<dn->digits; up++, d+=DECDPUN) hi+=*up*powers[d-1]; /* now low has the lsd, hi the remainder */ if (hi>214748364 || (hi==214748364 && lo>7)) { /* out of range? */ /* most-negative is a reprieve */ if (dn->bits&DECNEG && hi==214748364 && lo==8) return 0x80000000; /* bad -- drop through */
} else { /* in-range always */ Int i=X10(hi)+lo; if (dn->bits&DECNEG) return -i; return i;
}
} /* integer */
uprv_decContextSetStatus(set, DEC_Invalid_operation); /* [may not return] */ return 0;
} /* decNumberToInt32 */
U_CAPI uInt U_EXPORT2 uprv_decNumberToUInt32(const decNumber *dn, decContext *set) { #if DECCHECK if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0; #endif /* special or too many digits, or bad exponent, or negative (<0) */ if (dn->bits&DECSPECIAL || dn->digits>10 || dn->exponent!=0
|| (dn->bits&DECNEG && !ISZERO(dn))); /* bad */ else { /* is a finite integer with 10 or fewer digits */ Int d; /* work */ const Unit *up; /* .. */
uInt hi=0, lo; /* .. */
up=dn->lsu; /* -> lsu */
lo=*up; /* get 1 to 9 digits */ #if DECDPUN>1 /* split to higher */
hi=lo/10;
lo=lo%10; #endif
up++; /* collect remaining Units, if any, into hi */ for (d=DECDPUN; d<dn->digits; up++, d+=DECDPUN) hi+=*up*powers[d-1];
/* now low has the lsd, hi the remainder */ if (hi>429496729 || (hi==429496729 && lo>5)) ; /* no reprieve possible */ elsereturn X10(hi)+lo;
} /* integer */
uprv_decContextSetStatus(set, DEC_Invalid_operation); /* [may not return] */ return 0;
} /* decNumberToUInt32 */
/* ------------------------------------------------------------------ */ /* to-scientific-string -- conversion to numeric string */ /* to-engineering-string -- conversion to numeric string */ /* */ /* decNumberToString(dn, string); */ /* decNumberToEngString(dn, string); */ /* */ /* dn is the decNumber to convert */ /* string is the string where the result will be laid out */ /* */ /* string must be at least dn->digits+14 characters long */ /* */ /* No error is possible, and no status can be set. */ /* ------------------------------------------------------------------ */
U_CAPI char * U_EXPORT2 uprv_decNumberToString(const decNumber *dn, char *string){
decToString(dn, string, 0); return string;
} /* DecNumberToString */
/* ------------------------------------------------------------------ */ /* to-number -- conversion from numeric string */ /* */ /* decNumberFromString -- convert string to decNumber */ /* dn -- the number structure to fill */ /* chars[] -- the string to convert ('\0' terminated) */ /* set -- the context used for processing any error, */ /* determining the maximum precision available */ /* (set.digits), determining the maximum and minimum */ /* exponent (set.emax and set.emin), determining if */ /* extended values are allowed, and checking the */ /* rounding mode if overflow occurs or rounding is */ /* needed. */ /* */ /* The length of the coefficient and the size of the exponent are */ /* checked by this routine, so the correct error (Underflow or */ /* Overflow) can be reported or rounding applied, as necessary. */ /* */ /* If bad syntax is detected, the result will be a quiet NaN. */ /* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberFromString(decNumber *dn, constchar chars[],
decContext *set) { Int exponent=0; /* working exponent [assume 0] */
uByte bits=0; /* working flags [assume +ve] */
Unit *res; /* where result will be built */
Unit resbuff[SD2U(DECBUFFER+9)];/* local buffer in case need temporary */ /* [+9 allows for ln() constants] */
Unit *allocres=nullptr; /* -> allocated result, iff allocated */ Int d=0; /* count of digits found in decimal part */ constchar *dotchar=nullptr; /* where dot was found */ constchar *cfirst=chars; /* -> first character of decimal part */ constchar *last=nullptr; /* -> last digit of decimal part */ constchar *c; /* work */
Unit *up; /* .. */ #if DECDPUN>1 Int cut, out; /* .. */ #endif Int residue; /* rounding residue */
uInt status=0; /* error code */
#if DECCHECK if (decCheckOperands(DECUNRESU, DECUNUSED, DECUNUSED, set)) return uprv_decNumberZero(dn); #endif
do { /* status & malloc protection */ for (c=chars;; c++) { /* -> input character */ if (*c>='0' && *c<='9') { /* test for Arabic digit */
last=c;
d++; /* count of real digits */ continue; /* still in decimal part */
} if (*c=='.' && dotchar==nullptr) { /* first '.' */
dotchar=c; /* record offset into decimal part */ if (c==cfirst) cfirst++; /* first digit must follow */ continue;} if (c==chars) { /* first in string... */ if (*c=='-') { /* valid - sign */
cfirst++;
bits=DECNEG; continue;} if (*c=='+') { /* valid + sign */
cfirst++; continue;}
} /* *c is not a digit, or a valid +, -, or '.' */ break;
} /* c */
if (last==nullptr) { /* no digits yet */
status=DEC_Conversion_syntax;/* assume the worst */ if (*c=='\0') break; /* and no more to come... */ #if DECSUBSET /* if subset then infinities and NaNs are not allowed */ if (!set->extended) break; /* hopeless */ #endif /* Infinities and NaNs are possible, here */ if (dotchar!=nullptr) break; /* .. unless had a dot */
uprv_decNumberZero(dn); /* be optimistic */ if (decBiStr(c, "infinity", "INFINITY")
|| decBiStr(c, "inf", "INF")) {
dn->bits=bits | DECINF;
status=0; /* is OK */ break; /* all done */
} /* a NaN expected */ /* 2003.09.10 NaNs are now permitted to have a sign */
dn->bits=bits | DECNAN; /* assume simple NaN */ if (*c=='s' || *c=='S') { /* looks like an sNaN */
c++;
dn->bits=bits | DECSNAN;
} if (*c!='n' && *c!='N') break; /* check caseless "NaN" */
c++; if (*c!='a' && *c!='A') break; /* .. */
c++; if (*c!='n' && *c!='N') break; /* .. */
c++; /* now either nothing, or nnnn payload, expected */ /* -> start of integer and skip leading 0s [including plain 0] */ for (cfirst=c; *cfirst=='0';) cfirst++; if (*cfirst=='\0') { /* "NaN" or "sNaN", maybe with all 0s */
status=0; /* it's good */ break; /* .. */
} /* something other than 0s; setup last and d as usual [no dots] */ for (c=cfirst;; c++, d++) { if (*c<'0' || *c>'9') break; /* test for Arabic digit */
last=c;
} if (*c!='\0') break; /* not all digits */ if (d>set->digits-1) { /* [NB: payload in a decNumber can be full length unless */ /* clamped, in which case can only be digits-1] */ if (set->clamp) break; if (d>set->digits) break;
} /* too many digits? */ /* good; drop through to convert the integer to coefficient */
status=0; /* syntax is OK */
bits=dn->bits; /* for copy-back */
} /* last==nullptr */
elseif (*c!='\0') { /* more to process... */ /* had some digits; exponent is only valid sequence now */
Flag nege; /* 1=negative exponent */ constchar *firstexp; /* -> first significant exponent digit */
status=DEC_Conversion_syntax;/* assume the worst */ if (*c!='e' && *c!='E') break; /* Found 'e' or 'E' -- now process explicit exponent */ /* 1998.07.11: sign no longer required */
nege=0;
c++; /* to (possible) sign */ if (*c=='-') {nege=1; c++;} elseif (*c=='+') c++; if (*c=='\0') break;
for (; *c=='0' && *(c+1)!='\0';) c++; /* strip insignificant zeros */
firstexp=c; /* save exponent digit place */
uInt uexponent = 0; /* Avoid undefined behavior on signed int overflow */ for (; ;c++) { if (*c<'0' || *c>'9') break; /* not a digit */
uexponent=X10(uexponent)+(uInt)*c-(uInt)'0';
} /* c */
exponent = (Int)uexponent; /* if not now on a '\0', *c must not be a digit */ if (*c!='\0') break;
/* (this next test must be after the syntax checks) */ /* if it was too long the exponent may have wrapped, so check */ /* carefully and set it to a certain overflow if wrap possible */ if (c>=firstexp+9+1) { if (c>firstexp+9+1 || *firstexp>'1') exponent=DECNUMMAXE*2; /* [up to 1999999999 is OK, for example 1E-1000000998] */
} if (nege) exponent=-exponent; /* was negative */
status=0; /* is OK */
} /* stuff after digits */
/* Here when whole string has been inspected; syntax is good */ /* cfirst->first digit (never dot), last->last digit (ditto) */
/* strip leading zeros/dot [leave final 0 if all 0's] */ if (*cfirst=='0') { /* [cfirst has stepped over .] */ for (c=cfirst; c<last; c++, cfirst++) { if (*c=='.') continue; /* ignore dots */ if (*c!='0') break; /* non-zero found */
d--; /* 0 stripped */
} /* c */ #if DECSUBSET /* make a rapid exit for easy zeros if !extended */ if (*cfirst=='0' && !set->extended) {
uprv_decNumberZero(dn); /* clean result */ break; /* [could be return] */
} #endif
} /* at least one leading 0 */
/* Handle decimal point... */ if (dotchar!=nullptr && dotchar<last) /* non-trailing '.' found? */
exponent -= static_cast<int32_t>(last-dotchar); /* adjust exponent */ /* [we can now ignore the .] */
/* OK, the digits string is good. Assemble in the decNumber, or in */ /* a temporary units array if rounding is needed */ if (d<=set->digits) res=dn->lsu; /* fits into supplied decNumber */ else { /* rounding needed */ Int needbytes=D2U(d)*sizeof(Unit);/* bytes needed */
res=resbuff; /* assume use local buffer */ if (needbytes>(Int)sizeof(resbuff)) { /* too big for local */
allocres=(Unit *)malloc(needbytes); if (allocres==nullptr) {status|=DEC_Insufficient_storage; break;}
res=allocres;
}
} /* res now -> number lsu, buffer, or allocated storage for Unit array */
/* Place the coefficient into the selected Unit array */ /* [this is often 70% of the cost of this function when DECDPUN>1] */ #if DECDPUN>1
out=0; /* accumulator */
up=res+D2U(d)-1; /* -> msu */
cut=d-(up-res)*DECDPUN; /* digits in top unit */ for (c=cfirst;; c++) { /* along the digits */ if (*c=='.') continue; /* ignore '.' [don't decrement cut] */
out=X10(out)+(Int)*c-(Int)'0'; if (c==last) break; /* done [never get to trailing '.'] */
cut--; if (cut>0) continue; /* more for this unit */
*up=(Unit)out; /* write unit */
up--; /* prepare for unit below.. */
cut=DECDPUN; /* .. */
out=0; /* .. */
} /* c */
*up=(Unit)out; /* write lsu */
#else /* DECDPUN==1 */
up=res; /* -> lsu */ for (c=last; c>=cfirst; c--) { /* over each character, from least */ if (*c=='.') continue; /* ignore . [don't step up] */
*up=(Unit)((Int)*c-(Int)'0');
up++;
} /* c */ #endif
/* if not in number (too long) shorten into the number */ if (d>set->digits) {
residue=0;
decSetCoeff(dn, set, res, d, &residue, &status); /* always check for overflow or subnormal and round as needed */
decFinalize(dn, set, &residue, &status);
} else { /* no rounding, but may still have overflow or subnormal */ /* [these tests are just for performance; finalize repeats them] */ if ((dn->exponent-1<set->emin-dn->digits)
|| (dn->exponent-1>set->emax-set->digits)) {
residue=0;
decFinalize(dn, set, &residue, &status);
}
} /* decNumberShow(dn); */
} while(0); /* [for break] */
if (allocres!=nullptr) free(allocres); /* drop any storage used */ if (status!=0) decStatus(dn, status, set); return dn;
} /* decNumberFromString */
/* ------------------------------------------------------------------ */ /* decNumberAbs -- absolute value operator */ /* */ /* This computes C = abs(A) */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context */ /* */ /* See also decNumberCopyAbs for a quiet bitwise version of this. */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ /* This has the same effect as decNumberPlus unless A is negative, */ /* in which case it has the same effect as decNumberMinus. */ /* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberAbs(decNumber *res, const decNumber *rhs,
decContext *set) {
decNumber dzero; /* for 0 */
uInt status=0; /* accumulator */
#if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif
/* ------------------------------------------------------------------ */ /* decNumberAdd -- add two Numbers */ /* */ /* This computes C = A + B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X+X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */ /* This just calls the routine shared with Subtract */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberAdd(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decAddOp(res, lhs, rhs, set, 0, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK
decCheckInexact(res, set); #endif return res;
} /* decNumberAdd */
/* ------------------------------------------------------------------ */ /* decNumberAnd -- AND two Numbers, digitwise */ /* */ /* This computes C = A & B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X&X) */ /* lhs is A */ /* rhs is B */ /* set is the context (used for result length and error report) */ /* */ /* C must have space for set->digits digits. */ /* */ /* Logical function restrictions apply (see above); a NaN is */ /* returned with Invalid_operation if a restriction is violated. */ /* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberAnd(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) { const Unit *ua, *ub; /* -> operands */ const Unit *msua, *msub; /* -> operand msus */
Unit *uc, *msuc; /* -> result and its msu */ Int msudigs; /* digits in res msu */ #if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif
/* operands are valid */
ua=lhs->lsu; /* bottom-up */
ub=rhs->lsu; /* .. */
uc=res->lsu; /* .. */
msua=ua+D2U(lhs->digits)-1; /* -> msu of lhs */
msub=ub+D2U(rhs->digits)-1; /* -> msu of rhs */
msuc=uc+D2U(set->digits)-1; /* -> msu of result */
msudigs=MSUDIGITS(set->digits); /* [faster than remainder] */ for (; uc<=msuc; ua++, ub++, uc++) { /* Unit loop */
Unit a, b; /* extract units */ if (ua>msua) a=0; else a=*ua; if (ub>msub) b=0; else b=*ub;
*uc=0; /* can now write back */ if (a|b) { /* maybe 1 bits to examine */ Int i, j;
*uc=0; /* can now write back */ /* This loop could be unrolled and/or use BIN2BCD tables */ for (i=0; i<DECDPUN; i++) { if (a&b&1) *uc=*uc+(Unit)powers[i]; /* effect AND */
j=a%10;
a=a/10;
j|=b%10;
b=b/10; if (j>1) {
decStatus(res, DEC_Invalid_operation, set); return res;
} if (uc==msuc && i==msudigs-1) break; /* just did final digit */
} /* each digit */
} /* both OK */
} /* each unit */ /* [here uc-1 is the msu of the result] */
res->digits=decGetDigits(res->lsu, static_cast<int32_t>(uc - res->lsu));
res->exponent=0; /* integer */
res->bits=0; /* sign=0 */ return res; /* [no status to set] */
} /* decNumberAnd */
/* ------------------------------------------------------------------ */ /* decNumberCompare -- compare two Numbers */ /* */ /* This computes C = A ? B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X?X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for one digit (or NaN). */ /* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompare(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decCompareOp(res, lhs, rhs, set, COMPARE, &status); if (status!=0) decStatus(res, status, set); return res;
} /* decNumberCompare */
/* ------------------------------------------------------------------ */ /* decNumberCompareSignal -- compare, signalling on all NaNs */ /* */ /* This computes C = A ? B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X?X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for one digit (or NaN). */ /* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompareSignal(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decCompareOp(res, lhs, rhs, set, COMPSIG, &status); if (status!=0) decStatus(res, status, set); return res;
} /* decNumberCompareSignal */
/* ------------------------------------------------------------------ */ /* decNumberCompareTotal -- compare two Numbers, using total ordering */ /* */ /* This computes C = A ? B, under total ordering */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X?X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for one digit; the result will always be one of */ /* -1, 0, or 1. */ /* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompareTotal(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decCompareOp(res, lhs, rhs, set, COMPTOTAL, &status); if (status!=0) decStatus(res, status, set); return res;
} /* decNumberCompareTotal */
/* ------------------------------------------------------------------ */ /* decNumberCompareTotalMag -- compare, total ordering of magnitudes */ /* */ /* This computes C = |A| ? |B|, under total ordering */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X?X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for one digit; the result will always be one of */ /* -1, 0, or 1. */ /* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberCompareTotalMag(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
uInt needbytes; /* for space calculations */
decNumber bufa[D2N(DECBUFFER+1)];/* +1 in case DECBUFFER=0 */
decNumber *allocbufa=nullptr; /* -> allocated bufa, iff allocated */
decNumber bufb[D2N(DECBUFFER+1)];
decNumber *allocbufb=nullptr; /* -> allocated bufb, iff allocated */
decNumber *a, *b; /* temporary pointers */
#if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; #endif
do { /* protect allocated storage */ /* if either is negative, take a copy and absolute */ if (decNumberIsNegative(lhs)) { /* lhs<0 */
a=bufa;
needbytes=sizeof(decNumber)+(D2U(lhs->digits)-1)*sizeof(Unit); if (needbytes>sizeof(bufa)) { /* need malloc space */
allocbufa=(decNumber *)malloc(needbytes); if (allocbufa==nullptr) { /* hopeless -- abandon */
status|=DEC_Insufficient_storage; break;}
a=allocbufa; /* use the allocated space */
}
uprv_decNumberCopy(a, lhs); /* copy content */
a->bits&=~DECNEG; /* .. and clear the sign */
lhs=a; /* use copy from here on */
} if (decNumberIsNegative(rhs)) { /* rhs<0 */
b=bufb;
needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit); if (needbytes>sizeof(bufb)) { /* need malloc space */
allocbufb=(decNumber *)malloc(needbytes); if (allocbufb==nullptr) { /* hopeless -- abandon */
status|=DEC_Insufficient_storage; break;}
b=allocbufb; /* use the allocated space */
}
uprv_decNumberCopy(b, rhs); /* copy content */
b->bits&=~DECNEG; /* .. and clear the sign */
rhs=b; /* use copy from here on */
}
decCompareOp(res, lhs, rhs, set, COMPTOTAL, &status);
} while(0); /* end protected */
if (allocbufa!=nullptr) free(allocbufa); /* drop any storage used */ if (allocbufb!=nullptr) free(allocbufb); /* .. */ if (status!=0) decStatus(res, status, set); return res;
} /* decNumberCompareTotalMag */
/* ------------------------------------------------------------------ */ /* decNumberDivide -- divide one number by another */ /* */ /* This computes C = A / B */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X/X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberDivide(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decDivideOp(res, lhs, rhs, set, DIVIDE, &status); if (status!=0) decStatus(res, status, set); #if DECCHECK
decCheckInexact(res, set); #endif return res;
} /* decNumberDivide */
/* ------------------------------------------------------------------ */ /* decNumberDivideInteger -- divide and return integer quotient */ /* */ /* This computes C = A # B, where # is the integer divide operator */ /* */ /* res is C, the result. C may be A and/or B (e.g., X=X#X) */ /* lhs is A */ /* rhs is B */ /* set is the context */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberDivideInteger(decNumber *res, const decNumber *lhs, const decNumber *rhs, decContext *set) {
uInt status=0; /* accumulator */
decDivideOp(res, lhs, rhs, set, DIVIDEINT, &status); if (status!=0) decStatus(res, status, set); return res;
} /* decNumberDivideInteger */
/* ------------------------------------------------------------------ */ /* decNumberExp -- exponentiation */ /* */ /* This computes C = exp(A) */ /* */ /* res is C, the result. C may be A */ /* rhs is A */ /* set is the context; note that rounding mode has no effect */ /* */ /* C must have space for set->digits digits. */ /* */ /* Mathematical function restrictions apply (see above); a NaN is */ /* returned with Invalid_operation if a restriction is violated. */ /* */ /* Finite results will always be full precision and Inexact, except */ /* when A is a zero or -Infinity (giving 1 or 0 respectively). */ /* */ /* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */ /* almost always be correctly rounded, but may be up to 1 ulp in */ /* error in rare cases. */ /* ------------------------------------------------------------------ */ /* This is a wrapper for decExpOp which can handle the slightly wider */ /* (double) range needed by Ln (which has to be able to calculate */ /* exp(-a) where a can be the tiniest number (Ntiny). */ /* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberExp(decNumber *res, const decNumber *rhs,
decContext *set) {
uInt status=0; /* accumulator */ #if DECSUBSET
decNumber *allocrhs=nullptr; /* non-nullptr if rounded rhs allocated */ #endif
#if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif
/* Check restrictions; these restrictions ensure that if h=8 (see */ /* decExpOp) then the result will either overflow or underflow to 0. */ /* Other math functions restrict the input range, too, for inverses. */ /* If not violated then carry out the operation. */ if (!decCheckMath(rhs, set, &status)) do { /* protect allocation */ #if DECSUBSET if (!set->extended) { /* reduce operand and set lostDigits status, as needed */ if (rhs->digits>set->digits) {
allocrhs=decRoundOperand(rhs, set, &status); if (allocrhs==nullptr) break;
rhs=allocrhs;
}
} #endif
decExpOp(res, rhs, set, &status);
} while(0); /* end protected */
#if DECSUBSET if (allocrhs !=nullptr) free(allocrhs); /* drop any storage used */ #endif /* apply significant status */ if (status!=0) decStatus(res, status, set); #if DECCHECK
decCheckInexact(res, set); #endif return res;
} /* decNumberExp */
/* ------------------------------------------------------------------ */ /* decNumberFMA -- fused multiply add */ /* */ /* This computes D = (A * B) + C with only one rounding */ /* */ /* res is D, the result. D may be A or B or C (e.g., X=FMA(X,X,X)) */ /* lhs is A */ /* rhs is B */ /* fhs is C [far hand side] */ /* set is the context */ /* */ /* Mathematical function restrictions apply (see above); a NaN is */ /* returned with Invalid_operation if a restriction is violated. */ /* */ /* C must have space for set->digits digits. */ /* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberFMA(decNumber *res, const decNumber *lhs, const decNumber *rhs, const decNumber *fhs,
decContext *set) {
uInt status=0; /* accumulator */
decContext dcmul; /* context for the multiplication */
uInt needbytes; /* for space calculations */
decNumber bufa[D2N(DECBUFFER*2+1)];
decNumber *allocbufa=nullptr; /* -> allocated bufa, iff allocated */
decNumber *acc; /* accumulator pointer */
decNumber dzero; /* work */
#if DECCHECK if (decCheckOperands(res, lhs, rhs, set)) return res; if (decCheckOperands(res, fhs, DECUNUSED, set)) return res; #endif
do { /* protect allocated storage */ #if DECSUBSET if (!set->extended) { /* [undefined if subset] */
status|=DEC_Invalid_operation; break;} #endif /* Check math restrictions [these ensure no overflow or underflow] */ if ((!decNumberIsSpecial(lhs) && decCheckMath(lhs, set, &status))
|| (!decNumberIsSpecial(rhs) && decCheckMath(rhs, set, &status))
|| (!decNumberIsSpecial(fhs) && decCheckMath(fhs, set, &status))) break; /* set up context for multiply */
dcmul=*set;
dcmul.digits=lhs->digits+rhs->digits; /* just enough */ /* [The above may be an over-estimate for subset arithmetic, but that's OK] */
dcmul.emax=DEC_MAX_EMAX; /* effectively unbounded .. */
dcmul.emin=DEC_MIN_EMIN; /* [thanks to Math restrictions] */ /* set up decNumber space to receive the result of the multiply */
acc=bufa; /* may fit */
needbytes=sizeof(decNumber)+(D2U(dcmul.digits)-1)*sizeof(Unit); if (needbytes>sizeof(bufa)) { /* need malloc space */
allocbufa=(decNumber *)malloc(needbytes); if (allocbufa==nullptr) { /* hopeless -- abandon */
status|=DEC_Insufficient_storage; break;}
acc=allocbufa; /* use the allocated space */
} /* multiply with extended range and necessary precision */ /*printf("emin=%ld\n", dcmul.emin); */
decMultiplyOp(acc, lhs, rhs, &dcmul, &status); /* Only Invalid operation (from sNaN or Inf * 0) is possible in */ /* status; if either is seen than ignore fhs (in case it is */ /* another sNaN) and set acc to NaN unless we had an sNaN */ /* [decMultiplyOp leaves that to caller] */ /* Note sNaN has to go through addOp to shorten payload if */ /* necessary */ if ((status&DEC_Invalid_operation)!=0) { if (!(status&DEC_sNaN)) { /* but be true invalid */
uprv_decNumberZero(res); /* acc not yet set */
res->bits=DECNAN; break;
}
uprv_decNumberZero(&dzero); /* make 0 (any non-NaN would do) */
fhs=&dzero; /* use that */
} #if DECCHECK else { /* multiply was OK */ if (status!=0) printf("Status=%08lx after FMA multiply\n", (LI)status);
} #endif /* add the third operand and result -> res, and all is done */
decAddOp(res, acc, fhs, set, 0, &status);
} while(0); /* end protected */
if (allocbufa!=nullptr) free(allocbufa); /* drop any storage used */ if (status!=0) decStatus(res, status, set); #if DECCHECK
decCheckInexact(res, set); #endif return res;
} /* decNumberFMA */
/* ------------------------------------------------------------------ */ /* decNumberInvert -- invert a Number, digitwise */ /* */ /* This computes C = ~A */ /* */ /* res is C, the result. C may be A (e.g., X=~X) */ /* rhs is A */ /* set is the context (used for result length and error report) */ /* */ /* C must have space for set->digits digits. */ /* */ /* Logical function restrictions apply (see above); a NaN is */ /* returned with Invalid_operation if a restriction is violated. */ /* ------------------------------------------------------------------ */
U_CAPI decNumber * U_EXPORT2 uprv_decNumberInvert(decNumber *res, const decNumber *rhs,
decContext *set) { const Unit *ua, *msua; /* -> operand and its msu */
Unit *uc, *msuc; /* -> result and its msu */ Int msudigs; /* digits in res msu */ #if DECCHECK if (decCheckOperands(res, DECUNUSED, rhs, set)) return res; #endif
if (rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
decStatus(res, DEC_Invalid_operation, set); return res;
} /* operand is valid */
ua=rhs->lsu; /* bottom-up */
uc=res->lsu; /* .. */
msua=ua+D2U(rhs->digits)-1; /* -> msu of rhs */
msuc=uc+D2U(set->digits)-1; /* -> msu of result */
msudigs=MSUDIGITS(set->digits); /* [faster than remainder] */ for (; uc<=msuc; ua++, uc++) { /* Unit loop */
Unit a; /* extract unit */ Int i, j; /* work */ if (ua>msua) a=0; else a=*ua;
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.29 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.