172ac97cdSTom Musta /* Decimal number arithmetic module for the decNumber C Library.
272ac97cdSTom Musta Copyright (C) 2005, 2007 Free Software Foundation, Inc.
372ac97cdSTom Musta Contributed by IBM Corporation. Author Mike Cowlishaw.
472ac97cdSTom Musta
572ac97cdSTom Musta This file is part of GCC.
672ac97cdSTom Musta
772ac97cdSTom Musta GCC is free software; you can redistribute it and/or modify it under
872ac97cdSTom Musta the terms of the GNU General Public License as published by the Free
972ac97cdSTom Musta Software Foundation; either version 2, or (at your option) any later
1072ac97cdSTom Musta version.
1172ac97cdSTom Musta
1272ac97cdSTom Musta In addition to the permissions in the GNU General Public License,
1372ac97cdSTom Musta the Free Software Foundation gives you unlimited permission to link
1472ac97cdSTom Musta the compiled version of this file into combinations with other
1572ac97cdSTom Musta programs, and to distribute those combinations without any
1672ac97cdSTom Musta restriction coming from the use of this file. (The General Public
1772ac97cdSTom Musta License restrictions do apply in other respects; for example, they
1872ac97cdSTom Musta cover modification of the file, and distribution when not linked
1972ac97cdSTom Musta into a combine executable.)
2072ac97cdSTom Musta
2172ac97cdSTom Musta GCC is distributed in the hope that it will be useful, but WITHOUT ANY
2272ac97cdSTom Musta WARRANTY; without even the implied warranty of MERCHANTABILITY or
2372ac97cdSTom Musta FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
2472ac97cdSTom Musta for more details.
2572ac97cdSTom Musta
2672ac97cdSTom Musta You should have received a copy of the GNU General Public License
2772ac97cdSTom Musta along with GCC; see the file COPYING. If not, write to the Free
2872ac97cdSTom Musta Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
2972ac97cdSTom Musta 02110-1301, USA. */
3072ac97cdSTom Musta
3172ac97cdSTom Musta /* ------------------------------------------------------------------ */
3272ac97cdSTom Musta /* Decimal Number arithmetic module */
3372ac97cdSTom Musta /* ------------------------------------------------------------------ */
3472ac97cdSTom Musta /* This module comprises the routines for General Decimal Arithmetic */
3572ac97cdSTom Musta /* as defined in the specification which may be found on the */
3672ac97cdSTom Musta /* http://www2.hursley.ibm.com/decimal web pages. It implements both */
3772ac97cdSTom Musta /* the full ('extended') arithmetic and the simpler ('subset') */
3872ac97cdSTom Musta /* arithmetic. */
3972ac97cdSTom Musta /* */
4072ac97cdSTom Musta /* Usage notes: */
4172ac97cdSTom Musta /* */
4272ac97cdSTom Musta /* 1. This code is ANSI C89 except: */
4372ac97cdSTom Musta /* */
4472ac97cdSTom Musta /* If DECDPUN>4 or DECUSE64=1, the C99 64-bit int64_t and */
4572ac97cdSTom Musta /* uint64_t types may be used. To avoid these, set DECUSE64=0 */
4672ac97cdSTom Musta /* and DECDPUN<=4 (see documentation). */
4772ac97cdSTom Musta /* */
4872ac97cdSTom Musta /* 2. The decNumber format which this library uses is optimized for */
4972ac97cdSTom Musta /* efficient processing of relatively short numbers; in particular */
5072ac97cdSTom Musta /* it allows the use of fixed sized structures and minimizes copy */
5172ac97cdSTom Musta /* and move operations. It does, however, support arbitrary */
5272ac97cdSTom Musta /* precision (up to 999,999,999 digits) and arbitrary exponent */
5372ac97cdSTom Musta /* range (Emax in the range 0 through 999,999,999 and Emin in the */
5472ac97cdSTom Musta /* range -999,999,999 through 0). Mathematical functions (for */
5572ac97cdSTom Musta /* example decNumberExp) as identified below are restricted more */
5672ac97cdSTom Musta /* tightly: digits, emax, and -emin in the context must be <= */
5772ac97cdSTom Musta /* DEC_MAX_MATH (999999), and their operand(s) must be within */
5872ac97cdSTom Musta /* these bounds. */
5972ac97cdSTom Musta /* */
6072ac97cdSTom Musta /* 3. Logical functions are further restricted; their operands must */
6172ac97cdSTom Musta /* be finite, positive, have an exponent of zero, and all digits */
6272ac97cdSTom Musta /* must be either 0 or 1. The result will only contain digits */
6372ac97cdSTom Musta /* which are 0 or 1 (and will have exponent=0 and a sign of 0). */
6472ac97cdSTom Musta /* */
6572ac97cdSTom Musta /* 4. Operands to operator functions are never modified unless they */
6672ac97cdSTom Musta /* are also specified to be the result number (which is always */
6772ac97cdSTom Musta /* permitted). Other than that case, operands must not overlap. */
6872ac97cdSTom Musta /* */
6972ac97cdSTom Musta /* 5. Error handling: the type of the error is ORed into the status */
7072ac97cdSTom Musta /* flags in the current context (decContext structure). The */
7172ac97cdSTom Musta /* SIGFPE signal is then raised if the corresponding trap-enabler */
7272ac97cdSTom Musta /* flag in the decContext is set (is 1). */
7372ac97cdSTom Musta /* */
7472ac97cdSTom Musta /* It is the responsibility of the caller to clear the status */
7572ac97cdSTom Musta /* flags as required. */
7672ac97cdSTom Musta /* */
7772ac97cdSTom Musta /* The result of any routine which returns a number will always */
7872ac97cdSTom Musta /* be a valid number (which may be a special value, such as an */
7972ac97cdSTom Musta /* Infinity or NaN). */
8072ac97cdSTom Musta /* */
8172ac97cdSTom Musta /* 6. The decNumber format is not an exchangeable concrete */
8272ac97cdSTom Musta /* representation as it comprises fields which may be machine- */
8372ac97cdSTom Musta /* dependent (packed or unpacked, or special length, for example). */
8472ac97cdSTom Musta /* Canonical conversions to and from strings are provided; other */
8572ac97cdSTom Musta /* conversions are available in separate modules. */
8672ac97cdSTom Musta /* */
8772ac97cdSTom Musta /* 7. Normally, input operands are assumed to be valid. Set DECCHECK */
8872ac97cdSTom Musta /* to 1 for extended operand checking (including NULL operands). */
8972ac97cdSTom Musta /* Results are undefined if a badly-formed structure (or a NULL */
9072ac97cdSTom Musta /* pointer to a structure) is provided, though with DECCHECK */
9172ac97cdSTom Musta /* enabled the operator routines are protected against exceptions. */
9272ac97cdSTom Musta /* (Except if the result pointer is NULL, which is unrecoverable.) */
9372ac97cdSTom Musta /* */
9472ac97cdSTom Musta /* However, the routines will never cause exceptions if they are */
9572ac97cdSTom Musta /* given well-formed operands, even if the value of the operands */
9672ac97cdSTom Musta /* is inappropriate for the operation and DECCHECK is not set. */
9772ac97cdSTom Musta /* (Except for SIGFPE, as and where documented.) */
9872ac97cdSTom Musta /* */
9972ac97cdSTom Musta /* 8. Subset arithmetic is available only if DECSUBSET is set to 1. */
10072ac97cdSTom Musta /* ------------------------------------------------------------------ */
10172ac97cdSTom Musta /* Implementation notes for maintenance of this module: */
10272ac97cdSTom Musta /* */
10372ac97cdSTom Musta /* 1. Storage leak protection: Routines which use malloc are not */
10472ac97cdSTom Musta /* permitted to use return for fastpath or error exits (i.e., */
10572ac97cdSTom Musta /* they follow strict structured programming conventions). */
10672ac97cdSTom Musta /* Instead they have a do{}while(0); construct surrounding the */
10772ac97cdSTom Musta /* code which is protected -- break may be used to exit this. */
10872ac97cdSTom Musta /* Other routines can safely use the return statement inline. */
10972ac97cdSTom Musta /* */
11072ac97cdSTom Musta /* Storage leak accounting can be enabled using DECALLOC. */
11172ac97cdSTom Musta /* */
11272ac97cdSTom Musta /* 2. All loops use the for(;;) construct. Any do construct does */
11372ac97cdSTom Musta /* not loop; it is for allocation protection as just described. */
11472ac97cdSTom Musta /* */
11572ac97cdSTom Musta /* 3. Setting status in the context must always be the very last */
11672ac97cdSTom Musta /* action in a routine, as non-0 status may raise a trap and hence */
11772ac97cdSTom Musta /* the call to set status may not return (if the handler uses long */
11872ac97cdSTom Musta /* jump). Therefore all cleanup must be done first. In general, */
11972ac97cdSTom Musta /* to achieve this status is accumulated and is only applied just */
12072ac97cdSTom Musta /* before return by calling decContextSetStatus (via decStatus). */
12172ac97cdSTom Musta /* */
12272ac97cdSTom Musta /* Routines which allocate storage cannot, in general, use the */
12372ac97cdSTom Musta /* 'top level' routines which could cause a non-returning */
12472ac97cdSTom Musta /* transfer of control. The decXxxxOp routines are safe (do not */
12572ac97cdSTom Musta /* call decStatus even if traps are set in the context) and should */
12672ac97cdSTom Musta /* be used instead (they are also a little faster). */
12772ac97cdSTom Musta /* */
12872ac97cdSTom Musta /* 4. Exponent checking is minimized by allowing the exponent to */
12972ac97cdSTom Musta /* grow outside its limits during calculations, provided that */
13072ac97cdSTom Musta /* the decFinalize function is called later. Multiplication and */
13172ac97cdSTom Musta /* division, and intermediate calculations in exponentiation, */
13272ac97cdSTom Musta /* require more careful checks because of the risk of 31-bit */
13372ac97cdSTom Musta /* overflow (the most negative valid exponent is -1999999997, for */
13472ac97cdSTom Musta /* a 999999999-digit number with adjusted exponent of -999999999). */
13572ac97cdSTom Musta /* */
13672ac97cdSTom Musta /* 5. Rounding is deferred until finalization of results, with any */
13772ac97cdSTom Musta /* 'off to the right' data being represented as a single digit */
13872ac97cdSTom Musta /* residue (in the range -1 through 9). This avoids any double- */
13972ac97cdSTom Musta /* rounding when more than one shortening takes place (for */
14072ac97cdSTom Musta /* example, when a result is subnormal). */
14172ac97cdSTom Musta /* */
14272ac97cdSTom Musta /* 6. The digits count is allowed to rise to a multiple of DECDPUN */
14372ac97cdSTom Musta /* during many operations, so whole Units are handled and exact */
14472ac97cdSTom Musta /* accounting of digits is not needed. The correct digits value */
14572ac97cdSTom Musta /* is found by decGetDigits, which accounts for leading zeros. */
14672ac97cdSTom Musta /* This must be called before any rounding if the number of digits */
14772ac97cdSTom Musta /* is not known exactly. */
14872ac97cdSTom Musta /* */
14972ac97cdSTom Musta /* 7. The multiply-by-reciprocal 'trick' is used for partitioning */
15072ac97cdSTom Musta /* numbers up to four digits, using appropriate constants. This */
15172ac97cdSTom Musta /* is not useful for longer numbers because overflow of 32 bits */
15272ac97cdSTom Musta /* would lead to 4 multiplies, which is almost as expensive as */
15372ac97cdSTom Musta /* a divide (unless a floating-point or 64-bit multiply is */
15472ac97cdSTom Musta /* assumed to be available). */
15572ac97cdSTom Musta /* */
15672ac97cdSTom Musta /* 8. Unusual abbreviations that may be used in the commentary: */
15772ac97cdSTom Musta /* lhs -- left hand side (operand, of an operation) */
15872ac97cdSTom Musta /* lsd -- least significant digit (of coefficient) */
15972ac97cdSTom Musta /* lsu -- least significant Unit (of coefficient) */
16072ac97cdSTom Musta /* msd -- most significant digit (of coefficient) */
16172ac97cdSTom Musta /* msi -- most significant item (in an array) */
16272ac97cdSTom Musta /* msu -- most significant Unit (of coefficient) */
16372ac97cdSTom Musta /* rhs -- right hand side (operand, of an operation) */
16472ac97cdSTom Musta /* +ve -- positive */
16572ac97cdSTom Musta /* -ve -- negative */
16672ac97cdSTom Musta /* ** -- raise to the power */
16772ac97cdSTom Musta /* ------------------------------------------------------------------ */
16872ac97cdSTom Musta
1697a4e543dSPeter Maydell #include "qemu/osdep.h"
170727385c4SLuis Pires #include "qemu/host-utils.h"
1710f2d3732STom Musta #include "libdecnumber/dconfig.h"
1720f2d3732STom Musta #include "libdecnumber/decNumber.h"
1730f2d3732STom Musta #include "libdecnumber/decNumberLocal.h"
17472ac97cdSTom Musta
17572ac97cdSTom Musta /* Constants */
17672ac97cdSTom Musta /* Public lookup table used by the D2U macro */
17772ac97cdSTom Musta const uByte d2utable[DECMAXD2U+1]=D2UTABLE;
17872ac97cdSTom Musta
17972ac97cdSTom Musta #define DECVERB 1 /* set to 1 for verbose DECCHECK */
18072ac97cdSTom Musta #define powers DECPOWERS /* old internal name */
18172ac97cdSTom Musta
18272ac97cdSTom Musta /* Local constants */
18372ac97cdSTom Musta #define DIVIDE 0x80 /* Divide operators */
18472ac97cdSTom Musta #define REMAINDER 0x40 /* .. */
18572ac97cdSTom Musta #define DIVIDEINT 0x20 /* .. */
18672ac97cdSTom Musta #define REMNEAR 0x10 /* .. */
18772ac97cdSTom Musta #define COMPARE 0x01 /* Compare operators */
18872ac97cdSTom Musta #define COMPMAX 0x02 /* .. */
18972ac97cdSTom Musta #define COMPMIN 0x03 /* .. */
19072ac97cdSTom Musta #define COMPTOTAL 0x04 /* .. */
19172ac97cdSTom Musta #define COMPNAN 0x05 /* .. [NaN processing] */
19272ac97cdSTom Musta #define COMPSIG 0x06 /* .. [signaling COMPARE] */
19372ac97cdSTom Musta #define COMPMAXMAG 0x07 /* .. */
19472ac97cdSTom Musta #define COMPMINMAG 0x08 /* .. */
19572ac97cdSTom Musta
19672ac97cdSTom Musta #define DEC_sNaN 0x40000000 /* local status: sNaN signal */
19772ac97cdSTom Musta #define BADINT (Int)0x80000000 /* most-negative Int; error indicator */
19872ac97cdSTom Musta /* Next two indicate an integer >= 10**6, and its parity (bottom bit) */
19972ac97cdSTom Musta #define BIGEVEN (Int)0x80000002
20072ac97cdSTom Musta #define BIGODD (Int)0x80000003
20172ac97cdSTom Musta
20272ac97cdSTom Musta static Unit uarrone[1]={1}; /* Unit array of 1, used for incrementing */
20372ac97cdSTom Musta
20472ac97cdSTom Musta /* Granularity-dependent code */
20572ac97cdSTom Musta #if DECDPUN<=4
20672ac97cdSTom Musta #define eInt Int /* extended integer */
20772ac97cdSTom Musta #define ueInt uInt /* unsigned extended integer */
20872ac97cdSTom Musta /* Constant multipliers for divide-by-power-of five using reciprocal */
20972ac97cdSTom Musta /* multiply, after removing powers of 2 by shifting, and final shift */
21072ac97cdSTom Musta /* of 17 [we only need up to **4] */
21172ac97cdSTom Musta static const uInt multies[]={131073, 26215, 5243, 1049, 210};
21272ac97cdSTom Musta /* QUOT10 -- macro to return the quotient of unit u divided by 10**n */
21372ac97cdSTom Musta #define QUOT10(u, n) ((((uInt)(u)>>(n))*multies[n])>>17)
21472ac97cdSTom Musta #else
21572ac97cdSTom Musta /* For DECDPUN>4 non-ANSI-89 64-bit types are needed. */
21672ac97cdSTom Musta #if !DECUSE64
21772ac97cdSTom Musta #error decNumber.c: DECUSE64 must be 1 when DECDPUN>4
21872ac97cdSTom Musta #endif
21972ac97cdSTom Musta #define eInt Long /* extended integer */
22072ac97cdSTom Musta #define ueInt uLong /* unsigned extended integer */
22172ac97cdSTom Musta #endif
22272ac97cdSTom Musta
22372ac97cdSTom Musta /* Local routines */
22472ac97cdSTom Musta static decNumber * decAddOp(decNumber *, const decNumber *, const decNumber *,
22572ac97cdSTom Musta decContext *, uByte, uInt *);
22672ac97cdSTom Musta static Flag decBiStr(const char *, const char *, const char *);
22772ac97cdSTom Musta static uInt decCheckMath(const decNumber *, decContext *, uInt *);
22872ac97cdSTom Musta static void decApplyRound(decNumber *, decContext *, Int, uInt *);
22972ac97cdSTom Musta static Int decCompare(const decNumber *lhs, const decNumber *rhs, Flag);
23072ac97cdSTom Musta static decNumber * decCompareOp(decNumber *, const decNumber *,
23172ac97cdSTom Musta const decNumber *, decContext *,
23272ac97cdSTom Musta Flag, uInt *);
23372ac97cdSTom Musta static void decCopyFit(decNumber *, const decNumber *, decContext *,
23472ac97cdSTom Musta Int *, uInt *);
23572ac97cdSTom Musta static decNumber * decDecap(decNumber *, Int);
23672ac97cdSTom Musta static decNumber * decDivideOp(decNumber *, const decNumber *,
23772ac97cdSTom Musta const decNumber *, decContext *, Flag, uInt *);
23872ac97cdSTom Musta static decNumber * decExpOp(decNumber *, const decNumber *,
23972ac97cdSTom Musta decContext *, uInt *);
24072ac97cdSTom Musta static void decFinalize(decNumber *, decContext *, Int *, uInt *);
24172ac97cdSTom Musta static Int decGetDigits(Unit *, Int);
24272ac97cdSTom Musta static Int decGetInt(const decNumber *);
24372ac97cdSTom Musta static decNumber * decLnOp(decNumber *, const decNumber *,
24472ac97cdSTom Musta decContext *, uInt *);
24572ac97cdSTom Musta static decNumber * decMultiplyOp(decNumber *, const decNumber *,
24672ac97cdSTom Musta const decNumber *, decContext *,
24772ac97cdSTom Musta uInt *);
24872ac97cdSTom Musta static decNumber * decNaNs(decNumber *, const decNumber *,
24972ac97cdSTom Musta const decNumber *, decContext *, uInt *);
25072ac97cdSTom Musta static decNumber * decQuantizeOp(decNumber *, const decNumber *,
25172ac97cdSTom Musta const decNumber *, decContext *, Flag,
25272ac97cdSTom Musta uInt *);
25372ac97cdSTom Musta static void decReverse(Unit *, Unit *);
25472ac97cdSTom Musta static void decSetCoeff(decNumber *, decContext *, const Unit *,
25572ac97cdSTom Musta Int, Int *, uInt *);
25672ac97cdSTom Musta static void decSetMaxValue(decNumber *, decContext *);
25772ac97cdSTom Musta static void decSetOverflow(decNumber *, decContext *, uInt *);
25872ac97cdSTom Musta static void decSetSubnormal(decNumber *, decContext *, Int *, uInt *);
25972ac97cdSTom Musta static Int decShiftToLeast(Unit *, Int, Int);
26072ac97cdSTom Musta static Int decShiftToMost(Unit *, Int, Int);
26172ac97cdSTom Musta static void decStatus(decNumber *, uInt, decContext *);
26272ac97cdSTom Musta static void decToString(const decNumber *, char[], Flag);
26372ac97cdSTom Musta static decNumber * decTrim(decNumber *, decContext *, Flag, Int *);
26472ac97cdSTom Musta static Int decUnitAddSub(const Unit *, Int, const Unit *, Int, Int,
26572ac97cdSTom Musta Unit *, Int);
26672ac97cdSTom Musta static Int decUnitCompare(const Unit *, Int, const Unit *, Int, Int);
267*21d7826fSLuis Pires static bool mulUInt128ByPowOf10(uLong *, uLong *, uInt);
26872ac97cdSTom Musta
26972ac97cdSTom Musta #if !DECSUBSET
27072ac97cdSTom Musta /* decFinish == decFinalize when no subset arithmetic needed */
27172ac97cdSTom Musta #define decFinish(a,b,c,d) decFinalize(a,b,c,d)
27272ac97cdSTom Musta #else
27372ac97cdSTom Musta static void decFinish(decNumber *, decContext *, Int *, uInt *);
27472ac97cdSTom Musta static decNumber * decRoundOperand(const decNumber *, decContext *, uInt *);
27572ac97cdSTom Musta #endif
27672ac97cdSTom Musta
27772ac97cdSTom Musta /* Local macros */
27872ac97cdSTom Musta /* masked special-values bits */
27972ac97cdSTom Musta #define SPECIALARG (rhs->bits & DECSPECIAL)
28072ac97cdSTom Musta #define SPECIALARGS ((lhs->bits | rhs->bits) & DECSPECIAL)
28172ac97cdSTom Musta
28272ac97cdSTom Musta /* Diagnostic macros, etc. */
28372ac97cdSTom Musta #if DECALLOC
28472ac97cdSTom Musta /* Handle malloc/free accounting. If enabled, our accountable routines */
28572ac97cdSTom Musta /* are used; otherwise the code just goes straight to the system malloc */
28672ac97cdSTom Musta /* and free routines. */
28772ac97cdSTom Musta #define malloc(a) decMalloc(a)
28872ac97cdSTom Musta #define free(a) decFree(a)
28972ac97cdSTom Musta #define DECFENCE 0x5a /* corruption detector */
29072ac97cdSTom Musta /* 'Our' malloc and free: */
29172ac97cdSTom Musta static void *decMalloc(size_t);
29272ac97cdSTom Musta static void decFree(void *);
29372ac97cdSTom Musta uInt decAllocBytes=0; /* count of bytes allocated */
29472ac97cdSTom Musta /* Note that DECALLOC code only checks for storage buffer overflow. */
29572ac97cdSTom Musta /* To check for memory leaks, the decAllocBytes variable must be */
29672ac97cdSTom Musta /* checked to be 0 at appropriate times (e.g., after the test */
29772ac97cdSTom Musta /* harness completes a set of tests). This checking may be unreliable */
29872ac97cdSTom Musta /* if the testing is done in a multi-thread environment. */
29972ac97cdSTom Musta #endif
30072ac97cdSTom Musta
30172ac97cdSTom Musta #if DECCHECK
30272ac97cdSTom Musta /* Optional checking routines. Enabling these means that decNumber */
30372ac97cdSTom Musta /* and decContext operands to operator routines are checked for */
30472ac97cdSTom Musta /* correctness. This roughly doubles the execution time of the */
30572ac97cdSTom Musta /* fastest routines (and adds 600+ bytes), so should not normally be */
30672ac97cdSTom Musta /* used in 'production'. */
30772ac97cdSTom Musta /* decCheckInexact is used to check that inexact results have a full */
30872ac97cdSTom Musta /* complement of digits (where appropriate -- this is not the case */
30972ac97cdSTom Musta /* for Quantize, for example) */
31072ac97cdSTom Musta #define DECUNRESU ((decNumber *)(void *)0xffffffff)
31172ac97cdSTom Musta #define DECUNUSED ((const decNumber *)(void *)0xffffffff)
31272ac97cdSTom Musta #define DECUNCONT ((decContext *)(void *)(0xffffffff))
31372ac97cdSTom Musta static Flag decCheckOperands(decNumber *, const decNumber *,
31472ac97cdSTom Musta const decNumber *, decContext *);
31572ac97cdSTom Musta static Flag decCheckNumber(const decNumber *);
31672ac97cdSTom Musta static void decCheckInexact(const decNumber *, decContext *);
31772ac97cdSTom Musta #endif
31872ac97cdSTom Musta
31972ac97cdSTom Musta #if DECTRACE || DECCHECK
32072ac97cdSTom Musta /* Optional trace/debugging routines (may or may not be used) */
32172ac97cdSTom Musta void decNumberShow(const decNumber *); /* displays the components of a number */
32272ac97cdSTom Musta static void decDumpAr(char, const Unit *, Int);
32372ac97cdSTom Musta #endif
32472ac97cdSTom Musta
32572ac97cdSTom Musta /* ================================================================== */
32672ac97cdSTom Musta /* Conversions */
32772ac97cdSTom Musta /* ================================================================== */
32872ac97cdSTom Musta
32972ac97cdSTom Musta /* ------------------------------------------------------------------ */
33072ac97cdSTom Musta /* from-int32 -- conversion from Int or uInt */
33172ac97cdSTom Musta /* */
33272ac97cdSTom Musta /* dn is the decNumber to receive the integer */
33372ac97cdSTom Musta /* in or uin is the integer to be converted */
33472ac97cdSTom Musta /* returns dn */
33572ac97cdSTom Musta /* */
33672ac97cdSTom Musta /* No error is possible. */
33772ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberFromInt32(decNumber * dn,Int in)33872ac97cdSTom Musta decNumber * decNumberFromInt32(decNumber *dn, Int in) {
33972ac97cdSTom Musta uInt unsig;
34072ac97cdSTom Musta if (in>=0) unsig=in;
34172ac97cdSTom Musta else { /* negative (possibly BADINT) */
34272ac97cdSTom Musta if (in==BADINT) unsig=(uInt)1073741824*2; /* special case */
34372ac97cdSTom Musta else unsig=-in; /* invert */
34472ac97cdSTom Musta }
34572ac97cdSTom Musta /* in is now positive */
34672ac97cdSTom Musta decNumberFromUInt32(dn, unsig);
34772ac97cdSTom Musta if (in<0) dn->bits=DECNEG; /* sign needed */
34872ac97cdSTom Musta return dn;
34972ac97cdSTom Musta } /* decNumberFromInt32 */
35072ac97cdSTom Musta
decNumberFromUInt32(decNumber * dn,uInt uin)35172ac97cdSTom Musta decNumber * decNumberFromUInt32(decNumber *dn, uInt uin) {
35272ac97cdSTom Musta Unit *up; /* work pointer */
35372ac97cdSTom Musta decNumberZero(dn); /* clean */
35472ac97cdSTom Musta if (uin==0) return dn; /* [or decGetDigits bad call] */
35572ac97cdSTom Musta for (up=dn->lsu; uin>0; up++) {
35672ac97cdSTom Musta *up=(Unit)(uin%(DECDPUNMAX+1));
35772ac97cdSTom Musta uin=uin/(DECDPUNMAX+1);
35872ac97cdSTom Musta }
35972ac97cdSTom Musta dn->digits=decGetDigits(dn->lsu, up-dn->lsu);
36072ac97cdSTom Musta return dn;
36172ac97cdSTom Musta } /* decNumberFromUInt32 */
36272ac97cdSTom Musta
36372ac97cdSTom Musta /* ------------------------------------------------------------------ */
36472ac97cdSTom Musta /* to-int32 -- conversion to Int or uInt */
36572ac97cdSTom Musta /* */
36672ac97cdSTom Musta /* dn is the decNumber to convert */
36772ac97cdSTom Musta /* set is the context for reporting errors */
36872ac97cdSTom Musta /* returns the converted decNumber, or 0 if Invalid is set */
36972ac97cdSTom Musta /* */
37072ac97cdSTom Musta /* Invalid is set if the decNumber does not have exponent==0 or if */
37172ac97cdSTom Musta /* it is a NaN, Infinite, or out-of-range. */
37272ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberToInt32(const decNumber * dn,decContext * set)37372ac97cdSTom Musta Int decNumberToInt32(const decNumber *dn, decContext *set) {
37472ac97cdSTom Musta #if DECCHECK
37572ac97cdSTom Musta if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
37672ac97cdSTom Musta #endif
37772ac97cdSTom Musta
37872ac97cdSTom Musta /* special or too many digits, or bad exponent */
37972ac97cdSTom Musta if (dn->bits&DECSPECIAL || dn->digits>10 || dn->exponent!=0) ; /* bad */
38072ac97cdSTom Musta else { /* is a finite integer with 10 or fewer digits */
38172ac97cdSTom Musta Int d; /* work */
38272ac97cdSTom Musta const Unit *up; /* .. */
38372ac97cdSTom Musta uInt hi=0, lo; /* .. */
38472ac97cdSTom Musta up=dn->lsu; /* -> lsu */
38572ac97cdSTom Musta lo=*up; /* get 1 to 9 digits */
38672ac97cdSTom Musta #if DECDPUN>1 /* split to higher */
38772ac97cdSTom Musta hi=lo/10;
38872ac97cdSTom Musta lo=lo%10;
38972ac97cdSTom Musta #endif
39072ac97cdSTom Musta up++;
39172ac97cdSTom Musta /* collect remaining Units, if any, into hi */
39272ac97cdSTom Musta for (d=DECDPUN; d<dn->digits; up++, d+=DECDPUN) hi+=*up*powers[d-1];
39372ac97cdSTom Musta /* now low has the lsd, hi the remainder */
39472ac97cdSTom Musta if (hi>214748364 || (hi==214748364 && lo>7)) { /* out of range? */
39572ac97cdSTom Musta /* most-negative is a reprieve */
39672ac97cdSTom Musta if (dn->bits&DECNEG && hi==214748364 && lo==8) return 0x80000000;
39772ac97cdSTom Musta /* bad -- drop through */
39872ac97cdSTom Musta }
39972ac97cdSTom Musta else { /* in-range always */
40072ac97cdSTom Musta Int i=X10(hi)+lo;
40172ac97cdSTom Musta if (dn->bits&DECNEG) return -i;
40272ac97cdSTom Musta return i;
40372ac97cdSTom Musta }
40472ac97cdSTom Musta } /* integer */
40572ac97cdSTom Musta decContextSetStatus(set, DEC_Invalid_operation); /* [may not return] */
40672ac97cdSTom Musta return 0;
40772ac97cdSTom Musta } /* decNumberToInt32 */
40872ac97cdSTom Musta
decNumberToUInt32(const decNumber * dn,decContext * set)40972ac97cdSTom Musta uInt decNumberToUInt32(const decNumber *dn, decContext *set) {
41072ac97cdSTom Musta #if DECCHECK
41172ac97cdSTom Musta if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
41272ac97cdSTom Musta #endif
41372ac97cdSTom Musta /* special or too many digits, or bad exponent, or negative (<0) */
41472ac97cdSTom Musta if (dn->bits&DECSPECIAL || dn->digits>10 || dn->exponent!=0
41572ac97cdSTom Musta || (dn->bits&DECNEG && !ISZERO(dn))); /* bad */
41672ac97cdSTom Musta else { /* is a finite integer with 10 or fewer digits */
41772ac97cdSTom Musta Int d; /* work */
41872ac97cdSTom Musta const Unit *up; /* .. */
41972ac97cdSTom Musta uInt hi=0, lo; /* .. */
42072ac97cdSTom Musta up=dn->lsu; /* -> lsu */
42172ac97cdSTom Musta lo=*up; /* get 1 to 9 digits */
42272ac97cdSTom Musta #if DECDPUN>1 /* split to higher */
42372ac97cdSTom Musta hi=lo/10;
42472ac97cdSTom Musta lo=lo%10;
42572ac97cdSTom Musta #endif
42672ac97cdSTom Musta up++;
42772ac97cdSTom Musta /* collect remaining Units, if any, into hi */
42872ac97cdSTom Musta for (d=DECDPUN; d<dn->digits; up++, d+=DECDPUN) hi+=*up*powers[d-1];
42972ac97cdSTom Musta
43072ac97cdSTom Musta /* now low has the lsd, hi the remainder */
43172ac97cdSTom Musta if (hi>429496729 || (hi==429496729 && lo>5)) ; /* no reprieve possible */
43272ac97cdSTom Musta else return X10(hi)+lo;
43372ac97cdSTom Musta } /* integer */
43472ac97cdSTom Musta decContextSetStatus(set, DEC_Invalid_operation); /* [may not return] */
43572ac97cdSTom Musta return 0;
43672ac97cdSTom Musta } /* decNumberToUInt32 */
43772ac97cdSTom Musta
decNumberFromInt64(decNumber * dn,int64_t in)4388e706db2STom Musta decNumber *decNumberFromInt64(decNumber *dn, int64_t in)
4398e706db2STom Musta {
4408e706db2STom Musta uint64_t unsig = in;
4418e706db2STom Musta if (in < 0) {
4428e706db2STom Musta unsig = -unsig;
4438e706db2STom Musta }
4448e706db2STom Musta
4458e706db2STom Musta decNumberFromUInt64(dn, unsig);
4468e706db2STom Musta if (in < 0) {
4478e706db2STom Musta dn->bits = DECNEG; /* sign needed */
4488e706db2STom Musta }
4498e706db2STom Musta return dn;
4508e706db2STom Musta } /* decNumberFromInt64 */
4518e706db2STom Musta
decNumberFromUInt64(decNumber * dn,uint64_t uin)4528e706db2STom Musta decNumber *decNumberFromUInt64(decNumber *dn, uint64_t uin)
4538e706db2STom Musta {
4548e706db2STom Musta Unit *up; /* work pointer */
4558e706db2STom Musta decNumberZero(dn); /* clean */
4568e706db2STom Musta if (uin == 0) {
4578e706db2STom Musta return dn; /* [or decGetDigits bad call] */
4588e706db2STom Musta }
4598e706db2STom Musta for (up = dn->lsu; uin > 0; up++) {
4608e706db2STom Musta *up = (Unit)(uin % (DECDPUNMAX + 1));
4618e706db2STom Musta uin = uin / (DECDPUNMAX + 1);
4628e706db2STom Musta }
4638e706db2STom Musta dn->digits = decGetDigits(dn->lsu, up-dn->lsu);
4648e706db2STom Musta return dn;
4658e706db2STom Musta } /* decNumberFromUInt64 */
4668e706db2STom Musta
decNumberFromInt128(decNumber * dn,uint64_t lo,int64_t hi)467727385c4SLuis Pires decNumber *decNumberFromInt128(decNumber *dn, uint64_t lo, int64_t hi)
468727385c4SLuis Pires {
469727385c4SLuis Pires uint64_t unsig_hi = hi;
470727385c4SLuis Pires if (hi < 0) {
471727385c4SLuis Pires if (lo == 0) {
472727385c4SLuis Pires unsig_hi = -unsig_hi;
473727385c4SLuis Pires } else {
474727385c4SLuis Pires unsig_hi = ~unsig_hi;
475727385c4SLuis Pires lo = -lo;
476727385c4SLuis Pires }
477727385c4SLuis Pires }
478727385c4SLuis Pires
479727385c4SLuis Pires decNumberFromUInt128(dn, lo, unsig_hi);
480727385c4SLuis Pires if (hi < 0) {
481727385c4SLuis Pires dn->bits = DECNEG; /* sign needed */
482727385c4SLuis Pires }
483727385c4SLuis Pires return dn;
484727385c4SLuis Pires } /* decNumberFromInt128 */
485727385c4SLuis Pires
decNumberFromUInt128(decNumber * dn,uint64_t lo,uint64_t hi)486727385c4SLuis Pires decNumber *decNumberFromUInt128(decNumber *dn, uint64_t lo, uint64_t hi)
487727385c4SLuis Pires {
488727385c4SLuis Pires uint64_t rem;
489727385c4SLuis Pires Unit *up; /* work pointer */
490727385c4SLuis Pires decNumberZero(dn); /* clean */
491727385c4SLuis Pires if (lo == 0 && hi == 0) {
492727385c4SLuis Pires return dn; /* [or decGetDigits bad call] */
493727385c4SLuis Pires }
494727385c4SLuis Pires for (up = dn->lsu; hi > 0 || lo > 0; up++) {
495727385c4SLuis Pires rem = divu128(&lo, &hi, DECDPUNMAX + 1);
496727385c4SLuis Pires *up = (Unit)rem;
497727385c4SLuis Pires }
498727385c4SLuis Pires dn->digits = decGetDigits(dn->lsu, up - dn->lsu);
499727385c4SLuis Pires return dn;
500727385c4SLuis Pires } /* decNumberFromUInt128 */
501727385c4SLuis Pires
50279af3572STom Musta /* ------------------------------------------------------------------ */
50379af3572STom Musta /* to-int64 -- conversion to int64 */
50479af3572STom Musta /* */
50579af3572STom Musta /* dn is the decNumber to convert. dn is assumed to have been */
50679af3572STom Musta /* rounded to a floating point integer value. */
50779af3572STom Musta /* set is the context for reporting errors */
50879af3572STom Musta /* returns the converted decNumber, or 0 if Invalid is set */
50979af3572STom Musta /* */
51079af3572STom Musta /* Invalid is set if the decNumber is a NaN, Infinite or is out of */
51179af3572STom Musta /* range for a signed 64 bit integer. */
51279af3572STom Musta /* ------------------------------------------------------------------ */
51379af3572STom Musta
decNumberIntegralToInt64(const decNumber * dn,decContext * set)51479af3572STom Musta int64_t decNumberIntegralToInt64(const decNumber *dn, decContext *set)
51579af3572STom Musta {
51679af3572STom Musta if (decNumberIsSpecial(dn) || (dn->exponent < 0) ||
51779af3572STom Musta (dn->digits + dn->exponent > 19)) {
51879af3572STom Musta goto Invalid;
51979af3572STom Musta } else {
52079af3572STom Musta int64_t d; /* work */
52179af3572STom Musta const Unit *up; /* .. */
52279af3572STom Musta uint64_t hi = 0;
52379af3572STom Musta up = dn->lsu; /* -> lsu */
52479af3572STom Musta
52579af3572STom Musta for (d = 1; d <= dn->digits; up++, d += DECDPUN) {
52679af3572STom Musta uint64_t prev = hi;
52779af3572STom Musta hi += *up * powers[d-1];
52879af3572STom Musta if ((hi < prev) || (hi > INT64_MAX)) {
52979af3572STom Musta goto Invalid;
53079af3572STom Musta }
53179af3572STom Musta }
53279af3572STom Musta
53379af3572STom Musta uint64_t prev = hi;
53479af3572STom Musta hi *= (uint64_t)powers[dn->exponent];
53579af3572STom Musta if ((hi < prev) || (hi > INT64_MAX)) {
53679af3572STom Musta goto Invalid;
53779af3572STom Musta }
53879af3572STom Musta return (decNumberIsNegative(dn)) ? -((int64_t)hi) : (int64_t)hi;
53979af3572STom Musta }
54079af3572STom Musta
54179af3572STom Musta Invalid:
54279af3572STom Musta decContextSetStatus(set, DEC_Invalid_operation);
54379af3572STom Musta return 0;
54479af3572STom Musta } /* decNumberIntegralToInt64 */
54579af3572STom Musta
546*21d7826fSLuis Pires /* ------------------------------------------------------------------ */
547*21d7826fSLuis Pires /* decNumberIntegralToInt128 -- conversion to int128 */
548*21d7826fSLuis Pires /* */
549*21d7826fSLuis Pires /* dn is the decNumber to convert. dn is assumed to have been */
550*21d7826fSLuis Pires /* rounded to a floating point integer value. */
551*21d7826fSLuis Pires /* set is the context for reporting errors */
552*21d7826fSLuis Pires /* returns the converted decNumber via plow and phigh */
553*21d7826fSLuis Pires /* */
554*21d7826fSLuis Pires /* Invalid is set if the decNumber is a NaN, Infinite or is out of */
555*21d7826fSLuis Pires /* range for a signed 128 bit integer. */
556*21d7826fSLuis Pires /* ------------------------------------------------------------------ */
557*21d7826fSLuis Pires
decNumberIntegralToInt128(const decNumber * dn,decContext * set,uint64_t * plow,uint64_t * phigh)558*21d7826fSLuis Pires void decNumberIntegralToInt128(const decNumber *dn, decContext *set,
559*21d7826fSLuis Pires uint64_t *plow, uint64_t *phigh)
560*21d7826fSLuis Pires {
561*21d7826fSLuis Pires int d; /* work */
562*21d7826fSLuis Pires const Unit *up; /* .. */
563*21d7826fSLuis Pires uint64_t lo = 0, hi = 0;
564*21d7826fSLuis Pires
565*21d7826fSLuis Pires if (decNumberIsSpecial(dn) || (dn->exponent < 0) ||
566*21d7826fSLuis Pires (dn->digits + dn->exponent > 39)) {
567*21d7826fSLuis Pires goto Invalid;
568*21d7826fSLuis Pires }
569*21d7826fSLuis Pires
570*21d7826fSLuis Pires up = dn->lsu; /* -> lsu */
571*21d7826fSLuis Pires
572*21d7826fSLuis Pires for (d = (dn->digits - 1) / DECDPUN; d >= 0; d--) {
573*21d7826fSLuis Pires if (mulu128(&lo, &hi, DECDPUNMAX + 1)) {
574*21d7826fSLuis Pires /* overflow */
575*21d7826fSLuis Pires goto Invalid;
576*21d7826fSLuis Pires }
577*21d7826fSLuis Pires if (uadd64_overflow(lo, up[d], &lo)) {
578*21d7826fSLuis Pires if (uadd64_overflow(hi, 1, &hi)) {
579*21d7826fSLuis Pires /* overflow */
580*21d7826fSLuis Pires goto Invalid;
581*21d7826fSLuis Pires }
582*21d7826fSLuis Pires }
583*21d7826fSLuis Pires }
584*21d7826fSLuis Pires
585*21d7826fSLuis Pires if (mulUInt128ByPowOf10(&lo, &hi, dn->exponent)) {
586*21d7826fSLuis Pires /* overflow */
587*21d7826fSLuis Pires goto Invalid;
588*21d7826fSLuis Pires }
589*21d7826fSLuis Pires
590*21d7826fSLuis Pires if (decNumberIsNegative(dn)) {
591*21d7826fSLuis Pires if (lo == 0) {
592*21d7826fSLuis Pires *phigh = -hi;
593*21d7826fSLuis Pires *plow = 0;
594*21d7826fSLuis Pires } else {
595*21d7826fSLuis Pires *phigh = ~hi;
596*21d7826fSLuis Pires *plow = -lo;
597*21d7826fSLuis Pires }
598*21d7826fSLuis Pires } else {
599*21d7826fSLuis Pires *plow = lo;
600*21d7826fSLuis Pires *phigh = hi;
601*21d7826fSLuis Pires }
602*21d7826fSLuis Pires
603*21d7826fSLuis Pires return;
604*21d7826fSLuis Pires
605*21d7826fSLuis Pires Invalid:
606*21d7826fSLuis Pires decContextSetStatus(set, DEC_Invalid_operation);
607*21d7826fSLuis Pires } /* decNumberIntegralToInt128 */
6088e706db2STom Musta
60972ac97cdSTom Musta /* ------------------------------------------------------------------ */
61072ac97cdSTom Musta /* to-scientific-string -- conversion to numeric string */
61172ac97cdSTom Musta /* to-engineering-string -- conversion to numeric string */
61272ac97cdSTom Musta /* */
61372ac97cdSTom Musta /* decNumberToString(dn, string); */
61472ac97cdSTom Musta /* decNumberToEngString(dn, string); */
61572ac97cdSTom Musta /* */
61672ac97cdSTom Musta /* dn is the decNumber to convert */
61772ac97cdSTom Musta /* string is the string where the result will be laid out */
61872ac97cdSTom Musta /* */
61972ac97cdSTom Musta /* string must be at least dn->digits+14 characters long */
62072ac97cdSTom Musta /* */
62172ac97cdSTom Musta /* No error is possible, and no status can be set. */
62272ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberToString(const decNumber * dn,char * string)62372ac97cdSTom Musta char * decNumberToString(const decNumber *dn, char *string){
62472ac97cdSTom Musta decToString(dn, string, 0);
62572ac97cdSTom Musta return string;
62672ac97cdSTom Musta } /* DecNumberToString */
62772ac97cdSTom Musta
decNumberToEngString(const decNumber * dn,char * string)62872ac97cdSTom Musta char * decNumberToEngString(const decNumber *dn, char *string){
62972ac97cdSTom Musta decToString(dn, string, 1);
63072ac97cdSTom Musta return string;
63172ac97cdSTom Musta } /* DecNumberToEngString */
63272ac97cdSTom Musta
63372ac97cdSTom Musta /* ------------------------------------------------------------------ */
63472ac97cdSTom Musta /* to-number -- conversion from numeric string */
63572ac97cdSTom Musta /* */
63672ac97cdSTom Musta /* decNumberFromString -- convert string to decNumber */
63772ac97cdSTom Musta /* dn -- the number structure to fill */
63872ac97cdSTom Musta /* chars[] -- the string to convert ('\0' terminated) */
63972ac97cdSTom Musta /* set -- the context used for processing any error, */
64072ac97cdSTom Musta /* determining the maximum precision available */
64172ac97cdSTom Musta /* (set.digits), determining the maximum and minimum */
64272ac97cdSTom Musta /* exponent (set.emax and set.emin), determining if */
64372ac97cdSTom Musta /* extended values are allowed, and checking the */
64472ac97cdSTom Musta /* rounding mode if overflow occurs or rounding is */
64572ac97cdSTom Musta /* needed. */
64672ac97cdSTom Musta /* */
64772ac97cdSTom Musta /* The length of the coefficient and the size of the exponent are */
64872ac97cdSTom Musta /* checked by this routine, so the correct error (Underflow or */
64972ac97cdSTom Musta /* Overflow) can be reported or rounding applied, as necessary. */
65072ac97cdSTom Musta /* */
65172ac97cdSTom Musta /* If bad syntax is detected, the result will be a quiet NaN. */
65272ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberFromString(decNumber * dn,const char chars[],decContext * set)65372ac97cdSTom Musta decNumber * decNumberFromString(decNumber *dn, const char chars[],
65472ac97cdSTom Musta decContext *set) {
65572ac97cdSTom Musta Int exponent=0; /* working exponent [assume 0] */
65672ac97cdSTom Musta uByte bits=0; /* working flags [assume +ve] */
65772ac97cdSTom Musta Unit *res; /* where result will be built */
65872ac97cdSTom Musta Unit resbuff[SD2U(DECBUFFER+9)];/* local buffer in case need temporary */
65972ac97cdSTom Musta /* [+9 allows for ln() constants] */
66072ac97cdSTom Musta Unit *allocres=NULL; /* -> allocated result, iff allocated */
66172ac97cdSTom Musta Int d=0; /* count of digits found in decimal part */
66272ac97cdSTom Musta const char *dotchar=NULL; /* where dot was found */
66372ac97cdSTom Musta const char *cfirst=chars; /* -> first character of decimal part */
66472ac97cdSTom Musta const char *last=NULL; /* -> last digit of decimal part */
66572ac97cdSTom Musta const char *c; /* work */
66672ac97cdSTom Musta Unit *up; /* .. */
66772ac97cdSTom Musta #if DECDPUN>1
66872ac97cdSTom Musta Int cut, out; /* .. */
66972ac97cdSTom Musta #endif
67072ac97cdSTom Musta Int residue; /* rounding residue */
67172ac97cdSTom Musta uInt status=0; /* error code */
67272ac97cdSTom Musta
67372ac97cdSTom Musta #if DECCHECK
67472ac97cdSTom Musta if (decCheckOperands(DECUNRESU, DECUNUSED, DECUNUSED, set))
67572ac97cdSTom Musta return decNumberZero(dn);
67672ac97cdSTom Musta #endif
67772ac97cdSTom Musta
67872ac97cdSTom Musta do { /* status & malloc protection */
67972ac97cdSTom Musta for (c=chars;; c++) { /* -> input character */
68072ac97cdSTom Musta if (*c>='0' && *c<='9') { /* test for Arabic digit */
68172ac97cdSTom Musta last=c;
68272ac97cdSTom Musta d++; /* count of real digits */
68372ac97cdSTom Musta continue; /* still in decimal part */
68472ac97cdSTom Musta }
68572ac97cdSTom Musta if (*c=='.' && dotchar==NULL) { /* first '.' */
68672ac97cdSTom Musta dotchar=c; /* record offset into decimal part */
68772ac97cdSTom Musta if (c==cfirst) cfirst++; /* first digit must follow */
68872ac97cdSTom Musta continue;}
68972ac97cdSTom Musta if (c==chars) { /* first in string... */
69072ac97cdSTom Musta if (*c=='-') { /* valid - sign */
69172ac97cdSTom Musta cfirst++;
69272ac97cdSTom Musta bits=DECNEG;
69372ac97cdSTom Musta continue;}
69472ac97cdSTom Musta if (*c=='+') { /* valid + sign */
69572ac97cdSTom Musta cfirst++;
69672ac97cdSTom Musta continue;}
69772ac97cdSTom Musta }
69872ac97cdSTom Musta /* *c is not a digit, or a valid +, -, or '.' */
69972ac97cdSTom Musta break;
70072ac97cdSTom Musta } /* c */
70172ac97cdSTom Musta
70272ac97cdSTom Musta if (last==NULL) { /* no digits yet */
70372ac97cdSTom Musta status=DEC_Conversion_syntax;/* assume the worst */
70472ac97cdSTom Musta if (*c=='\0') break; /* and no more to come... */
70572ac97cdSTom Musta #if DECSUBSET
70672ac97cdSTom Musta /* if subset then infinities and NaNs are not allowed */
70772ac97cdSTom Musta if (!set->extended) break; /* hopeless */
70872ac97cdSTom Musta #endif
70972ac97cdSTom Musta /* Infinities and NaNs are possible, here */
71072ac97cdSTom Musta if (dotchar!=NULL) break; /* .. unless had a dot */
71172ac97cdSTom Musta decNumberZero(dn); /* be optimistic */
71272ac97cdSTom Musta if (decBiStr(c, "infinity", "INFINITY")
71372ac97cdSTom Musta || decBiStr(c, "inf", "INF")) {
71472ac97cdSTom Musta dn->bits=bits | DECINF;
71572ac97cdSTom Musta status=0; /* is OK */
71672ac97cdSTom Musta break; /* all done */
71772ac97cdSTom Musta }
71872ac97cdSTom Musta /* a NaN expected */
71972ac97cdSTom Musta /* 2003.09.10 NaNs are now permitted to have a sign */
72072ac97cdSTom Musta dn->bits=bits | DECNAN; /* assume simple NaN */
72172ac97cdSTom Musta if (*c=='s' || *c=='S') { /* looks like an sNaN */
72272ac97cdSTom Musta c++;
72372ac97cdSTom Musta dn->bits=bits | DECSNAN;
72472ac97cdSTom Musta }
72572ac97cdSTom Musta if (*c!='n' && *c!='N') break; /* check caseless "NaN" */
72672ac97cdSTom Musta c++;
72772ac97cdSTom Musta if (*c!='a' && *c!='A') break; /* .. */
72872ac97cdSTom Musta c++;
72972ac97cdSTom Musta if (*c!='n' && *c!='N') break; /* .. */
73072ac97cdSTom Musta c++;
73172ac97cdSTom Musta /* now either nothing, or nnnn payload, expected */
73272ac97cdSTom Musta /* -> start of integer and skip leading 0s [including plain 0] */
73372ac97cdSTom Musta for (cfirst=c; *cfirst=='0';) cfirst++;
73472ac97cdSTom Musta if (*cfirst=='\0') { /* "NaN" or "sNaN", maybe with all 0s */
73572ac97cdSTom Musta status=0; /* it's good */
73672ac97cdSTom Musta break; /* .. */
73772ac97cdSTom Musta }
73872ac97cdSTom Musta /* something other than 0s; setup last and d as usual [no dots] */
73972ac97cdSTom Musta for (c=cfirst;; c++, d++) {
74072ac97cdSTom Musta if (*c<'0' || *c>'9') break; /* test for Arabic digit */
74172ac97cdSTom Musta last=c;
74272ac97cdSTom Musta }
74372ac97cdSTom Musta if (*c!='\0') break; /* not all digits */
74472ac97cdSTom Musta if (d>set->digits-1) {
74572ac97cdSTom Musta /* [NB: payload in a decNumber can be full length unless */
74672ac97cdSTom Musta /* clamped, in which case can only be digits-1] */
74772ac97cdSTom Musta if (set->clamp) break;
74872ac97cdSTom Musta if (d>set->digits) break;
74972ac97cdSTom Musta } /* too many digits? */
75072ac97cdSTom Musta /* good; drop through to convert the integer to coefficient */
75172ac97cdSTom Musta status=0; /* syntax is OK */
75272ac97cdSTom Musta bits=dn->bits; /* for copy-back */
75372ac97cdSTom Musta } /* last==NULL */
75472ac97cdSTom Musta
75572ac97cdSTom Musta else if (*c!='\0') { /* more to process... */
75672ac97cdSTom Musta /* had some digits; exponent is only valid sequence now */
75772ac97cdSTom Musta Flag nege; /* 1=negative exponent */
75872ac97cdSTom Musta const char *firstexp; /* -> first significant exponent digit */
75972ac97cdSTom Musta status=DEC_Conversion_syntax;/* assume the worst */
76072ac97cdSTom Musta if (*c!='e' && *c!='E') break;
76172ac97cdSTom Musta /* Found 'e' or 'E' -- now process explicit exponent */
76272ac97cdSTom Musta /* 1998.07.11: sign no longer required */
76372ac97cdSTom Musta nege=0;
76472ac97cdSTom Musta c++; /* to (possible) sign */
76572ac97cdSTom Musta if (*c=='-') {nege=1; c++;}
76672ac97cdSTom Musta else if (*c=='+') c++;
76772ac97cdSTom Musta if (*c=='\0') break;
76872ac97cdSTom Musta
76972ac97cdSTom Musta for (; *c=='0' && *(c+1)!='\0';) c++; /* strip insignificant zeros */
77072ac97cdSTom Musta firstexp=c; /* save exponent digit place */
77172ac97cdSTom Musta for (; ;c++) {
77272ac97cdSTom Musta if (*c<'0' || *c>'9') break; /* not a digit */
77372ac97cdSTom Musta exponent=X10(exponent)+(Int)*c-(Int)'0';
77472ac97cdSTom Musta } /* c */
77572ac97cdSTom Musta /* if not now on a '\0', *c must not be a digit */
77672ac97cdSTom Musta if (*c!='\0') break;
77772ac97cdSTom Musta
77872ac97cdSTom Musta /* (this next test must be after the syntax checks) */
77972ac97cdSTom Musta /* if it was too long the exponent may have wrapped, so check */
78072ac97cdSTom Musta /* carefully and set it to a certain overflow if wrap possible */
78172ac97cdSTom Musta if (c>=firstexp+9+1) {
78272ac97cdSTom Musta if (c>firstexp+9+1 || *firstexp>'1') exponent=DECNUMMAXE*2;
78372ac97cdSTom Musta /* [up to 1999999999 is OK, for example 1E-1000000998] */
78472ac97cdSTom Musta }
78572ac97cdSTom Musta if (nege) exponent=-exponent; /* was negative */
78672ac97cdSTom Musta status=0; /* is OK */
78772ac97cdSTom Musta } /* stuff after digits */
78872ac97cdSTom Musta
78972ac97cdSTom Musta /* Here when whole string has been inspected; syntax is good */
79072ac97cdSTom Musta /* cfirst->first digit (never dot), last->last digit (ditto) */
79172ac97cdSTom Musta
79272ac97cdSTom Musta /* strip leading zeros/dot [leave final 0 if all 0's] */
79372ac97cdSTom Musta if (*cfirst=='0') { /* [cfirst has stepped over .] */
79472ac97cdSTom Musta for (c=cfirst; c<last; c++, cfirst++) {
79572ac97cdSTom Musta if (*c=='.') continue; /* ignore dots */
79672ac97cdSTom Musta if (*c!='0') break; /* non-zero found */
79772ac97cdSTom Musta d--; /* 0 stripped */
79872ac97cdSTom Musta } /* c */
79972ac97cdSTom Musta #if DECSUBSET
80072ac97cdSTom Musta /* make a rapid exit for easy zeros if !extended */
80172ac97cdSTom Musta if (*cfirst=='0' && !set->extended) {
80272ac97cdSTom Musta decNumberZero(dn); /* clean result */
80372ac97cdSTom Musta break; /* [could be return] */
80472ac97cdSTom Musta }
80572ac97cdSTom Musta #endif
80672ac97cdSTom Musta } /* at least one leading 0 */
80772ac97cdSTom Musta
80872ac97cdSTom Musta /* Handle decimal point... */
80972ac97cdSTom Musta if (dotchar!=NULL && dotchar<last) /* non-trailing '.' found? */
81072ac97cdSTom Musta exponent-=(last-dotchar); /* adjust exponent */
81172ac97cdSTom Musta /* [we can now ignore the .] */
81272ac97cdSTom Musta
81372ac97cdSTom Musta /* OK, the digits string is good. Assemble in the decNumber, or in */
81472ac97cdSTom Musta /* a temporary units array if rounding is needed */
81572ac97cdSTom Musta if (d<=set->digits) res=dn->lsu; /* fits into supplied decNumber */
81672ac97cdSTom Musta else { /* rounding needed */
81772ac97cdSTom Musta Int needbytes=D2U(d)*sizeof(Unit);/* bytes needed */
81872ac97cdSTom Musta res=resbuff; /* assume use local buffer */
81972ac97cdSTom Musta if (needbytes>(Int)sizeof(resbuff)) { /* too big for local */
82072ac97cdSTom Musta allocres=(Unit *)malloc(needbytes);
82172ac97cdSTom Musta if (allocres==NULL) {status|=DEC_Insufficient_storage; break;}
82272ac97cdSTom Musta res=allocres;
82372ac97cdSTom Musta }
82472ac97cdSTom Musta }
82572ac97cdSTom Musta /* res now -> number lsu, buffer, or allocated storage for Unit array */
82672ac97cdSTom Musta
82772ac97cdSTom Musta /* Place the coefficient into the selected Unit array */
82872ac97cdSTom Musta /* [this is often 70% of the cost of this function when DECDPUN>1] */
82972ac97cdSTom Musta #if DECDPUN>1
83072ac97cdSTom Musta out=0; /* accumulator */
83172ac97cdSTom Musta up=res+D2U(d)-1; /* -> msu */
83272ac97cdSTom Musta cut=d-(up-res)*DECDPUN; /* digits in top unit */
83372ac97cdSTom Musta for (c=cfirst;; c++) { /* along the digits */
83472ac97cdSTom Musta if (*c=='.') continue; /* ignore '.' [don't decrement cut] */
83572ac97cdSTom Musta out=X10(out)+(Int)*c-(Int)'0';
83672ac97cdSTom Musta if (c==last) break; /* done [never get to trailing '.'] */
83772ac97cdSTom Musta cut--;
83872ac97cdSTom Musta if (cut>0) continue; /* more for this unit */
83972ac97cdSTom Musta *up=(Unit)out; /* write unit */
84072ac97cdSTom Musta up--; /* prepare for unit below.. */
84172ac97cdSTom Musta cut=DECDPUN; /* .. */
84272ac97cdSTom Musta out=0; /* .. */
84372ac97cdSTom Musta } /* c */
84472ac97cdSTom Musta *up=(Unit)out; /* write lsu */
84572ac97cdSTom Musta
84672ac97cdSTom Musta #else
84772ac97cdSTom Musta /* DECDPUN==1 */
84872ac97cdSTom Musta up=res; /* -> lsu */
84972ac97cdSTom Musta for (c=last; c>=cfirst; c--) { /* over each character, from least */
85072ac97cdSTom Musta if (*c=='.') continue; /* ignore . [don't step up] */
85172ac97cdSTom Musta *up=(Unit)((Int)*c-(Int)'0');
85272ac97cdSTom Musta up++;
85372ac97cdSTom Musta } /* c */
85472ac97cdSTom Musta #endif
85572ac97cdSTom Musta
85672ac97cdSTom Musta dn->bits=bits;
85772ac97cdSTom Musta dn->exponent=exponent;
85872ac97cdSTom Musta dn->digits=d;
85972ac97cdSTom Musta
86072ac97cdSTom Musta /* if not in number (too long) shorten into the number */
86172ac97cdSTom Musta if (d>set->digits) {
86272ac97cdSTom Musta residue=0;
86372ac97cdSTom Musta decSetCoeff(dn, set, res, d, &residue, &status);
86472ac97cdSTom Musta /* always check for overflow or subnormal and round as needed */
86572ac97cdSTom Musta decFinalize(dn, set, &residue, &status);
86672ac97cdSTom Musta }
86772ac97cdSTom Musta else { /* no rounding, but may still have overflow or subnormal */
86872ac97cdSTom Musta /* [these tests are just for performance; finalize repeats them] */
86972ac97cdSTom Musta if ((dn->exponent-1<set->emin-dn->digits)
87072ac97cdSTom Musta || (dn->exponent-1>set->emax-set->digits)) {
87172ac97cdSTom Musta residue=0;
87272ac97cdSTom Musta decFinalize(dn, set, &residue, &status);
87372ac97cdSTom Musta }
87472ac97cdSTom Musta }
87572ac97cdSTom Musta /* decNumberShow(dn); */
87672ac97cdSTom Musta } while(0); /* [for break] */
87772ac97cdSTom Musta
87872ac97cdSTom Musta if (allocres!=NULL) free(allocres); /* drop any storage used */
87972ac97cdSTom Musta if (status!=0) decStatus(dn, status, set);
88072ac97cdSTom Musta return dn;
88172ac97cdSTom Musta } /* decNumberFromString */
88272ac97cdSTom Musta
88372ac97cdSTom Musta /* ================================================================== */
88472ac97cdSTom Musta /* Operators */
88572ac97cdSTom Musta /* ================================================================== */
88672ac97cdSTom Musta
88772ac97cdSTom Musta /* ------------------------------------------------------------------ */
88872ac97cdSTom Musta /* decNumberAbs -- absolute value operator */
88972ac97cdSTom Musta /* */
89072ac97cdSTom Musta /* This computes C = abs(A) */
89172ac97cdSTom Musta /* */
89272ac97cdSTom Musta /* res is C, the result. C may be A */
89372ac97cdSTom Musta /* rhs is A */
89472ac97cdSTom Musta /* set is the context */
89572ac97cdSTom Musta /* */
89672ac97cdSTom Musta /* See also decNumberCopyAbs for a quiet bitwise version of this. */
89772ac97cdSTom Musta /* C must have space for set->digits digits. */
89872ac97cdSTom Musta /* ------------------------------------------------------------------ */
89972ac97cdSTom Musta /* This has the same effect as decNumberPlus unless A is negative, */
90072ac97cdSTom Musta /* in which case it has the same effect as decNumberMinus. */
90172ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberAbs(decNumber * res,const decNumber * rhs,decContext * set)90272ac97cdSTom Musta decNumber * decNumberAbs(decNumber *res, const decNumber *rhs,
90372ac97cdSTom Musta decContext *set) {
90472ac97cdSTom Musta decNumber dzero; /* for 0 */
90572ac97cdSTom Musta uInt status=0; /* accumulator */
90672ac97cdSTom Musta
90772ac97cdSTom Musta #if DECCHECK
90872ac97cdSTom Musta if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
90972ac97cdSTom Musta #endif
91072ac97cdSTom Musta
91172ac97cdSTom Musta decNumberZero(&dzero); /* set 0 */
91272ac97cdSTom Musta dzero.exponent=rhs->exponent; /* [no coefficient expansion] */
91372ac97cdSTom Musta decAddOp(res, &dzero, rhs, set, (uByte)(rhs->bits & DECNEG), &status);
91472ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
91572ac97cdSTom Musta #if DECCHECK
91672ac97cdSTom Musta decCheckInexact(res, set);
91772ac97cdSTom Musta #endif
91872ac97cdSTom Musta return res;
91972ac97cdSTom Musta } /* decNumberAbs */
92072ac97cdSTom Musta
92172ac97cdSTom Musta /* ------------------------------------------------------------------ */
92272ac97cdSTom Musta /* decNumberAdd -- add two Numbers */
92372ac97cdSTom Musta /* */
92472ac97cdSTom Musta /* This computes C = A + B */
92572ac97cdSTom Musta /* */
92672ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X+X) */
92772ac97cdSTom Musta /* lhs is A */
92872ac97cdSTom Musta /* rhs is B */
92972ac97cdSTom Musta /* set is the context */
93072ac97cdSTom Musta /* */
93172ac97cdSTom Musta /* C must have space for set->digits digits. */
93272ac97cdSTom Musta /* ------------------------------------------------------------------ */
93372ac97cdSTom Musta /* This just calls the routine shared with Subtract */
decNumberAdd(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)93472ac97cdSTom Musta decNumber * decNumberAdd(decNumber *res, const decNumber *lhs,
93572ac97cdSTom Musta const decNumber *rhs, decContext *set) {
93672ac97cdSTom Musta uInt status=0; /* accumulator */
93772ac97cdSTom Musta decAddOp(res, lhs, rhs, set, 0, &status);
93872ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
93972ac97cdSTom Musta #if DECCHECK
94072ac97cdSTom Musta decCheckInexact(res, set);
94172ac97cdSTom Musta #endif
94272ac97cdSTom Musta return res;
94372ac97cdSTom Musta } /* decNumberAdd */
94472ac97cdSTom Musta
94572ac97cdSTom Musta /* ------------------------------------------------------------------ */
94672ac97cdSTom Musta /* decNumberAnd -- AND two Numbers, digitwise */
94772ac97cdSTom Musta /* */
94872ac97cdSTom Musta /* This computes C = A & B */
94972ac97cdSTom Musta /* */
95072ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X&X) */
95172ac97cdSTom Musta /* lhs is A */
95272ac97cdSTom Musta /* rhs is B */
95372ac97cdSTom Musta /* set is the context (used for result length and error report) */
95472ac97cdSTom Musta /* */
95572ac97cdSTom Musta /* C must have space for set->digits digits. */
95672ac97cdSTom Musta /* */
95772ac97cdSTom Musta /* Logical function restrictions apply (see above); a NaN is */
95872ac97cdSTom Musta /* returned with Invalid_operation if a restriction is violated. */
95972ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberAnd(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)96072ac97cdSTom Musta decNumber * decNumberAnd(decNumber *res, const decNumber *lhs,
96172ac97cdSTom Musta const decNumber *rhs, decContext *set) {
96272ac97cdSTom Musta const Unit *ua, *ub; /* -> operands */
96372ac97cdSTom Musta const Unit *msua, *msub; /* -> operand msus */
96472ac97cdSTom Musta Unit *uc, *msuc; /* -> result and its msu */
96572ac97cdSTom Musta Int msudigs; /* digits in res msu */
96672ac97cdSTom Musta #if DECCHECK
96772ac97cdSTom Musta if (decCheckOperands(res, lhs, rhs, set)) return res;
96872ac97cdSTom Musta #endif
96972ac97cdSTom Musta
97072ac97cdSTom Musta if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs)
97172ac97cdSTom Musta || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
97272ac97cdSTom Musta decStatus(res, DEC_Invalid_operation, set);
97372ac97cdSTom Musta return res;
97472ac97cdSTom Musta }
97572ac97cdSTom Musta
97672ac97cdSTom Musta /* operands are valid */
97772ac97cdSTom Musta ua=lhs->lsu; /* bottom-up */
97872ac97cdSTom Musta ub=rhs->lsu; /* .. */
97972ac97cdSTom Musta uc=res->lsu; /* .. */
98072ac97cdSTom Musta msua=ua+D2U(lhs->digits)-1; /* -> msu of lhs */
98172ac97cdSTom Musta msub=ub+D2U(rhs->digits)-1; /* -> msu of rhs */
98272ac97cdSTom Musta msuc=uc+D2U(set->digits)-1; /* -> msu of result */
98372ac97cdSTom Musta msudigs=MSUDIGITS(set->digits); /* [faster than remainder] */
98472ac97cdSTom Musta for (; uc<=msuc; ua++, ub++, uc++) { /* Unit loop */
98572ac97cdSTom Musta Unit a, b; /* extract units */
98672ac97cdSTom Musta if (ua>msua) a=0;
98772ac97cdSTom Musta else a=*ua;
98872ac97cdSTom Musta if (ub>msub) b=0;
98972ac97cdSTom Musta else b=*ub;
99072ac97cdSTom Musta *uc=0; /* can now write back */
99172ac97cdSTom Musta if (a|b) { /* maybe 1 bits to examine */
99272ac97cdSTom Musta Int i, j;
99372ac97cdSTom Musta *uc=0; /* can now write back */
99472ac97cdSTom Musta /* This loop could be unrolled and/or use BIN2BCD tables */
99572ac97cdSTom Musta for (i=0; i<DECDPUN; i++) {
99672ac97cdSTom Musta if (a&b&1) *uc=*uc+(Unit)powers[i]; /* effect AND */
99772ac97cdSTom Musta j=a%10;
99872ac97cdSTom Musta a=a/10;
99972ac97cdSTom Musta j|=b%10;
100072ac97cdSTom Musta b=b/10;
100172ac97cdSTom Musta if (j>1) {
100272ac97cdSTom Musta decStatus(res, DEC_Invalid_operation, set);
100372ac97cdSTom Musta return res;
100472ac97cdSTom Musta }
100572ac97cdSTom Musta if (uc==msuc && i==msudigs-1) break; /* just did final digit */
100672ac97cdSTom Musta } /* each digit */
100772ac97cdSTom Musta } /* both OK */
100872ac97cdSTom Musta } /* each unit */
100972ac97cdSTom Musta /* [here uc-1 is the msu of the result] */
101072ac97cdSTom Musta res->digits=decGetDigits(res->lsu, uc-res->lsu);
101172ac97cdSTom Musta res->exponent=0; /* integer */
101272ac97cdSTom Musta res->bits=0; /* sign=0 */
101372ac97cdSTom Musta return res; /* [no status to set] */
101472ac97cdSTom Musta } /* decNumberAnd */
101572ac97cdSTom Musta
101672ac97cdSTom Musta /* ------------------------------------------------------------------ */
101772ac97cdSTom Musta /* decNumberCompare -- compare two Numbers */
101872ac97cdSTom Musta /* */
101972ac97cdSTom Musta /* This computes C = A ? B */
102072ac97cdSTom Musta /* */
102172ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X?X) */
102272ac97cdSTom Musta /* lhs is A */
102372ac97cdSTom Musta /* rhs is B */
102472ac97cdSTom Musta /* set is the context */
102572ac97cdSTom Musta /* */
102672ac97cdSTom Musta /* C must have space for one digit (or NaN). */
102772ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberCompare(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)102872ac97cdSTom Musta decNumber * decNumberCompare(decNumber *res, const decNumber *lhs,
102972ac97cdSTom Musta const decNumber *rhs, decContext *set) {
103072ac97cdSTom Musta uInt status=0; /* accumulator */
103172ac97cdSTom Musta decCompareOp(res, lhs, rhs, set, COMPARE, &status);
103272ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
103372ac97cdSTom Musta return res;
103472ac97cdSTom Musta } /* decNumberCompare */
103572ac97cdSTom Musta
103672ac97cdSTom Musta /* ------------------------------------------------------------------ */
103772ac97cdSTom Musta /* decNumberCompareSignal -- compare, signalling on all NaNs */
103872ac97cdSTom Musta /* */
103972ac97cdSTom Musta /* This computes C = A ? B */
104072ac97cdSTom Musta /* */
104172ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X?X) */
104272ac97cdSTom Musta /* lhs is A */
104372ac97cdSTom Musta /* rhs is B */
104472ac97cdSTom Musta /* set is the context */
104572ac97cdSTom Musta /* */
104672ac97cdSTom Musta /* C must have space for one digit (or NaN). */
104772ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberCompareSignal(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)104872ac97cdSTom Musta decNumber * decNumberCompareSignal(decNumber *res, const decNumber *lhs,
104972ac97cdSTom Musta const decNumber *rhs, decContext *set) {
105072ac97cdSTom Musta uInt status=0; /* accumulator */
105172ac97cdSTom Musta decCompareOp(res, lhs, rhs, set, COMPSIG, &status);
105272ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
105372ac97cdSTom Musta return res;
105472ac97cdSTom Musta } /* decNumberCompareSignal */
105572ac97cdSTom Musta
105672ac97cdSTom Musta /* ------------------------------------------------------------------ */
105772ac97cdSTom Musta /* decNumberCompareTotal -- compare two Numbers, using total ordering */
105872ac97cdSTom Musta /* */
105972ac97cdSTom Musta /* This computes C = A ? B, under total ordering */
106072ac97cdSTom Musta /* */
106172ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X?X) */
106272ac97cdSTom Musta /* lhs is A */
106372ac97cdSTom Musta /* rhs is B */
106472ac97cdSTom Musta /* set is the context */
106572ac97cdSTom Musta /* */
106672ac97cdSTom Musta /* C must have space for one digit; the result will always be one of */
106772ac97cdSTom Musta /* -1, 0, or 1. */
106872ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberCompareTotal(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)106972ac97cdSTom Musta decNumber * decNumberCompareTotal(decNumber *res, const decNumber *lhs,
107072ac97cdSTom Musta const decNumber *rhs, decContext *set) {
107172ac97cdSTom Musta uInt status=0; /* accumulator */
107272ac97cdSTom Musta decCompareOp(res, lhs, rhs, set, COMPTOTAL, &status);
107372ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
107472ac97cdSTom Musta return res;
107572ac97cdSTom Musta } /* decNumberCompareTotal */
107672ac97cdSTom Musta
107772ac97cdSTom Musta /* ------------------------------------------------------------------ */
107872ac97cdSTom Musta /* decNumberCompareTotalMag -- compare, total ordering of magnitudes */
107972ac97cdSTom Musta /* */
108072ac97cdSTom Musta /* This computes C = |A| ? |B|, under total ordering */
108172ac97cdSTom Musta /* */
108272ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X?X) */
108372ac97cdSTom Musta /* lhs is A */
108472ac97cdSTom Musta /* rhs is B */
108572ac97cdSTom Musta /* set is the context */
108672ac97cdSTom Musta /* */
108772ac97cdSTom Musta /* C must have space for one digit; the result will always be one of */
108872ac97cdSTom Musta /* -1, 0, or 1. */
108972ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberCompareTotalMag(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)109072ac97cdSTom Musta decNumber * decNumberCompareTotalMag(decNumber *res, const decNumber *lhs,
109172ac97cdSTom Musta const decNumber *rhs, decContext *set) {
109272ac97cdSTom Musta uInt status=0; /* accumulator */
109372ac97cdSTom Musta uInt needbytes; /* for space calculations */
109472ac97cdSTom Musta decNumber bufa[D2N(DECBUFFER+1)];/* +1 in case DECBUFFER=0 */
109572ac97cdSTom Musta decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
109672ac97cdSTom Musta decNumber bufb[D2N(DECBUFFER+1)];
109772ac97cdSTom Musta decNumber *allocbufb=NULL; /* -> allocated bufb, iff allocated */
109872ac97cdSTom Musta decNumber *a, *b; /* temporary pointers */
109972ac97cdSTom Musta
110072ac97cdSTom Musta #if DECCHECK
110172ac97cdSTom Musta if (decCheckOperands(res, lhs, rhs, set)) return res;
110272ac97cdSTom Musta #endif
110372ac97cdSTom Musta
110472ac97cdSTom Musta do { /* protect allocated storage */
110572ac97cdSTom Musta /* if either is negative, take a copy and absolute */
110672ac97cdSTom Musta if (decNumberIsNegative(lhs)) { /* lhs<0 */
110772ac97cdSTom Musta a=bufa;
110872ac97cdSTom Musta needbytes=sizeof(decNumber)+(D2U(lhs->digits)-1)*sizeof(Unit);
110972ac97cdSTom Musta if (needbytes>sizeof(bufa)) { /* need malloc space */
111072ac97cdSTom Musta allocbufa=(decNumber *)malloc(needbytes);
111172ac97cdSTom Musta if (allocbufa==NULL) { /* hopeless -- abandon */
111272ac97cdSTom Musta status|=DEC_Insufficient_storage;
111372ac97cdSTom Musta break;}
111472ac97cdSTom Musta a=allocbufa; /* use the allocated space */
111572ac97cdSTom Musta }
111672ac97cdSTom Musta decNumberCopy(a, lhs); /* copy content */
111772ac97cdSTom Musta a->bits&=~DECNEG; /* .. and clear the sign */
111872ac97cdSTom Musta lhs=a; /* use copy from here on */
111972ac97cdSTom Musta }
112072ac97cdSTom Musta if (decNumberIsNegative(rhs)) { /* rhs<0 */
112172ac97cdSTom Musta b=bufb;
112272ac97cdSTom Musta needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit);
112372ac97cdSTom Musta if (needbytes>sizeof(bufb)) { /* need malloc space */
112472ac97cdSTom Musta allocbufb=(decNumber *)malloc(needbytes);
112572ac97cdSTom Musta if (allocbufb==NULL) { /* hopeless -- abandon */
112672ac97cdSTom Musta status|=DEC_Insufficient_storage;
112772ac97cdSTom Musta break;}
112872ac97cdSTom Musta b=allocbufb; /* use the allocated space */
112972ac97cdSTom Musta }
113072ac97cdSTom Musta decNumberCopy(b, rhs); /* copy content */
113172ac97cdSTom Musta b->bits&=~DECNEG; /* .. and clear the sign */
113272ac97cdSTom Musta rhs=b; /* use copy from here on */
113372ac97cdSTom Musta }
113472ac97cdSTom Musta decCompareOp(res, lhs, rhs, set, COMPTOTAL, &status);
113572ac97cdSTom Musta } while(0); /* end protected */
113672ac97cdSTom Musta
113772ac97cdSTom Musta if (allocbufa!=NULL) free(allocbufa); /* drop any storage used */
113872ac97cdSTom Musta if (allocbufb!=NULL) free(allocbufb); /* .. */
113972ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
114072ac97cdSTom Musta return res;
114172ac97cdSTom Musta } /* decNumberCompareTotalMag */
114272ac97cdSTom Musta
114372ac97cdSTom Musta /* ------------------------------------------------------------------ */
114472ac97cdSTom Musta /* decNumberDivide -- divide one number by another */
114572ac97cdSTom Musta /* */
114672ac97cdSTom Musta /* This computes C = A / B */
114772ac97cdSTom Musta /* */
114872ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X/X) */
114972ac97cdSTom Musta /* lhs is A */
115072ac97cdSTom Musta /* rhs is B */
115172ac97cdSTom Musta /* set is the context */
115272ac97cdSTom Musta /* */
115372ac97cdSTom Musta /* C must have space for set->digits digits. */
115472ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberDivide(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)115572ac97cdSTom Musta decNumber * decNumberDivide(decNumber *res, const decNumber *lhs,
115672ac97cdSTom Musta const decNumber *rhs, decContext *set) {
115772ac97cdSTom Musta uInt status=0; /* accumulator */
115872ac97cdSTom Musta decDivideOp(res, lhs, rhs, set, DIVIDE, &status);
115972ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
116072ac97cdSTom Musta #if DECCHECK
116172ac97cdSTom Musta decCheckInexact(res, set);
116272ac97cdSTom Musta #endif
116372ac97cdSTom Musta return res;
116472ac97cdSTom Musta } /* decNumberDivide */
116572ac97cdSTom Musta
116672ac97cdSTom Musta /* ------------------------------------------------------------------ */
116772ac97cdSTom Musta /* decNumberDivideInteger -- divide and return integer quotient */
116872ac97cdSTom Musta /* */
116972ac97cdSTom Musta /* This computes C = A # B, where # is the integer divide operator */
117072ac97cdSTom Musta /* */
117172ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X#X) */
117272ac97cdSTom Musta /* lhs is A */
117372ac97cdSTom Musta /* rhs is B */
117472ac97cdSTom Musta /* set is the context */
117572ac97cdSTom Musta /* */
117672ac97cdSTom Musta /* C must have space for set->digits digits. */
117772ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberDivideInteger(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)117872ac97cdSTom Musta decNumber * decNumberDivideInteger(decNumber *res, const decNumber *lhs,
117972ac97cdSTom Musta const decNumber *rhs, decContext *set) {
118072ac97cdSTom Musta uInt status=0; /* accumulator */
118172ac97cdSTom Musta decDivideOp(res, lhs, rhs, set, DIVIDEINT, &status);
118272ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
118372ac97cdSTom Musta return res;
118472ac97cdSTom Musta } /* decNumberDivideInteger */
118572ac97cdSTom Musta
118672ac97cdSTom Musta /* ------------------------------------------------------------------ */
118772ac97cdSTom Musta /* decNumberExp -- exponentiation */
118872ac97cdSTom Musta /* */
118972ac97cdSTom Musta /* This computes C = exp(A) */
119072ac97cdSTom Musta /* */
119172ac97cdSTom Musta /* res is C, the result. C may be A */
119272ac97cdSTom Musta /* rhs is A */
119372ac97cdSTom Musta /* set is the context; note that rounding mode has no effect */
119472ac97cdSTom Musta /* */
119572ac97cdSTom Musta /* C must have space for set->digits digits. */
119672ac97cdSTom Musta /* */
119772ac97cdSTom Musta /* Mathematical function restrictions apply (see above); a NaN is */
119872ac97cdSTom Musta /* returned with Invalid_operation if a restriction is violated. */
119972ac97cdSTom Musta /* */
120072ac97cdSTom Musta /* Finite results will always be full precision and Inexact, except */
120172ac97cdSTom Musta /* when A is a zero or -Infinity (giving 1 or 0 respectively). */
120272ac97cdSTom Musta /* */
120372ac97cdSTom Musta /* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */
120472ac97cdSTom Musta /* almost always be correctly rounded, but may be up to 1 ulp in */
120572ac97cdSTom Musta /* error in rare cases. */
120672ac97cdSTom Musta /* ------------------------------------------------------------------ */
120772ac97cdSTom Musta /* This is a wrapper for decExpOp which can handle the slightly wider */
120872ac97cdSTom Musta /* (double) range needed by Ln (which has to be able to calculate */
120972ac97cdSTom Musta /* exp(-a) where a can be the tiniest number (Ntiny). */
121072ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberExp(decNumber * res,const decNumber * rhs,decContext * set)121172ac97cdSTom Musta decNumber * decNumberExp(decNumber *res, const decNumber *rhs,
121272ac97cdSTom Musta decContext *set) {
121372ac97cdSTom Musta uInt status=0; /* accumulator */
121472ac97cdSTom Musta #if DECSUBSET
121572ac97cdSTom Musta decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
121672ac97cdSTom Musta #endif
121772ac97cdSTom Musta
121872ac97cdSTom Musta #if DECCHECK
121972ac97cdSTom Musta if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
122072ac97cdSTom Musta #endif
122172ac97cdSTom Musta
122272ac97cdSTom Musta /* Check restrictions; these restrictions ensure that if h=8 (see */
122372ac97cdSTom Musta /* decExpOp) then the result will either overflow or underflow to 0. */
122472ac97cdSTom Musta /* Other math functions restrict the input range, too, for inverses. */
122572ac97cdSTom Musta /* If not violated then carry out the operation. */
122672ac97cdSTom Musta if (!decCheckMath(rhs, set, &status)) do { /* protect allocation */
122772ac97cdSTom Musta #if DECSUBSET
122872ac97cdSTom Musta if (!set->extended) {
122972ac97cdSTom Musta /* reduce operand and set lostDigits status, as needed */
123072ac97cdSTom Musta if (rhs->digits>set->digits) {
123172ac97cdSTom Musta allocrhs=decRoundOperand(rhs, set, &status);
123272ac97cdSTom Musta if (allocrhs==NULL) break;
123372ac97cdSTom Musta rhs=allocrhs;
123472ac97cdSTom Musta }
123572ac97cdSTom Musta }
123672ac97cdSTom Musta #endif
123772ac97cdSTom Musta decExpOp(res, rhs, set, &status);
123872ac97cdSTom Musta } while(0); /* end protected */
123972ac97cdSTom Musta
124072ac97cdSTom Musta #if DECSUBSET
124172ac97cdSTom Musta if (allocrhs !=NULL) free(allocrhs); /* drop any storage used */
124272ac97cdSTom Musta #endif
124372ac97cdSTom Musta /* apply significant status */
124472ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
124572ac97cdSTom Musta #if DECCHECK
124672ac97cdSTom Musta decCheckInexact(res, set);
124772ac97cdSTom Musta #endif
124872ac97cdSTom Musta return res;
124972ac97cdSTom Musta } /* decNumberExp */
125072ac97cdSTom Musta
125172ac97cdSTom Musta /* ------------------------------------------------------------------ */
125272ac97cdSTom Musta /* decNumberFMA -- fused multiply add */
125372ac97cdSTom Musta /* */
125472ac97cdSTom Musta /* This computes D = (A * B) + C with only one rounding */
125572ac97cdSTom Musta /* */
125672ac97cdSTom Musta /* res is D, the result. D may be A or B or C (e.g., X=FMA(X,X,X)) */
125772ac97cdSTom Musta /* lhs is A */
125872ac97cdSTom Musta /* rhs is B */
125972ac97cdSTom Musta /* fhs is C [far hand side] */
126072ac97cdSTom Musta /* set is the context */
126172ac97cdSTom Musta /* */
126272ac97cdSTom Musta /* Mathematical function restrictions apply (see above); a NaN is */
126372ac97cdSTom Musta /* returned with Invalid_operation if a restriction is violated. */
126472ac97cdSTom Musta /* */
126572ac97cdSTom Musta /* C must have space for set->digits digits. */
126672ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberFMA(decNumber * res,const decNumber * lhs,const decNumber * rhs,const decNumber * fhs,decContext * set)126772ac97cdSTom Musta decNumber * decNumberFMA(decNumber *res, const decNumber *lhs,
126872ac97cdSTom Musta const decNumber *rhs, const decNumber *fhs,
126972ac97cdSTom Musta decContext *set) {
127072ac97cdSTom Musta uInt status=0; /* accumulator */
127172ac97cdSTom Musta decContext dcmul; /* context for the multiplication */
127272ac97cdSTom Musta uInt needbytes; /* for space calculations */
127372ac97cdSTom Musta decNumber bufa[D2N(DECBUFFER*2+1)];
127472ac97cdSTom Musta decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
127572ac97cdSTom Musta decNumber *acc; /* accumulator pointer */
127672ac97cdSTom Musta decNumber dzero; /* work */
127772ac97cdSTom Musta
127872ac97cdSTom Musta #if DECCHECK
127972ac97cdSTom Musta if (decCheckOperands(res, lhs, rhs, set)) return res;
128072ac97cdSTom Musta if (decCheckOperands(res, fhs, DECUNUSED, set)) return res;
128172ac97cdSTom Musta #endif
128272ac97cdSTom Musta
128372ac97cdSTom Musta do { /* protect allocated storage */
128472ac97cdSTom Musta #if DECSUBSET
128572ac97cdSTom Musta if (!set->extended) { /* [undefined if subset] */
128672ac97cdSTom Musta status|=DEC_Invalid_operation;
128772ac97cdSTom Musta break;}
128872ac97cdSTom Musta #endif
128972ac97cdSTom Musta /* Check math restrictions [these ensure no overflow or underflow] */
129072ac97cdSTom Musta if ((!decNumberIsSpecial(lhs) && decCheckMath(lhs, set, &status))
129172ac97cdSTom Musta || (!decNumberIsSpecial(rhs) && decCheckMath(rhs, set, &status))
129272ac97cdSTom Musta || (!decNumberIsSpecial(fhs) && decCheckMath(fhs, set, &status))) break;
129372ac97cdSTom Musta /* set up context for multiply */
129472ac97cdSTom Musta dcmul=*set;
129572ac97cdSTom Musta dcmul.digits=lhs->digits+rhs->digits; /* just enough */
129672ac97cdSTom Musta /* [The above may be an over-estimate for subset arithmetic, but that's OK] */
129772ac97cdSTom Musta dcmul.emax=DEC_MAX_EMAX; /* effectively unbounded .. */
129872ac97cdSTom Musta dcmul.emin=DEC_MIN_EMIN; /* [thanks to Math restrictions] */
129972ac97cdSTom Musta /* set up decNumber space to receive the result of the multiply */
130072ac97cdSTom Musta acc=bufa; /* may fit */
130172ac97cdSTom Musta needbytes=sizeof(decNumber)+(D2U(dcmul.digits)-1)*sizeof(Unit);
130272ac97cdSTom Musta if (needbytes>sizeof(bufa)) { /* need malloc space */
130372ac97cdSTom Musta allocbufa=(decNumber *)malloc(needbytes);
130472ac97cdSTom Musta if (allocbufa==NULL) { /* hopeless -- abandon */
130572ac97cdSTom Musta status|=DEC_Insufficient_storage;
130672ac97cdSTom Musta break;}
130772ac97cdSTom Musta acc=allocbufa; /* use the allocated space */
130872ac97cdSTom Musta }
130972ac97cdSTom Musta /* multiply with extended range and necessary precision */
131072ac97cdSTom Musta /*printf("emin=%ld\n", dcmul.emin); */
131172ac97cdSTom Musta decMultiplyOp(acc, lhs, rhs, &dcmul, &status);
131272ac97cdSTom Musta /* Only Invalid operation (from sNaN or Inf * 0) is possible in */
131372ac97cdSTom Musta /* status; if either is seen than ignore fhs (in case it is */
131472ac97cdSTom Musta /* another sNaN) and set acc to NaN unless we had an sNaN */
131572ac97cdSTom Musta /* [decMultiplyOp leaves that to caller] */
131672ac97cdSTom Musta /* Note sNaN has to go through addOp to shorten payload if */
131772ac97cdSTom Musta /* necessary */
131872ac97cdSTom Musta if ((status&DEC_Invalid_operation)!=0) {
131972ac97cdSTom Musta if (!(status&DEC_sNaN)) { /* but be true invalid */
132072ac97cdSTom Musta decNumberZero(res); /* acc not yet set */
132172ac97cdSTom Musta res->bits=DECNAN;
132272ac97cdSTom Musta break;
132372ac97cdSTom Musta }
132472ac97cdSTom Musta decNumberZero(&dzero); /* make 0 (any non-NaN would do) */
132572ac97cdSTom Musta fhs=&dzero; /* use that */
132672ac97cdSTom Musta }
132772ac97cdSTom Musta #if DECCHECK
132872ac97cdSTom Musta else { /* multiply was OK */
132972ac97cdSTom Musta if (status!=0) printf("Status=%08lx after FMA multiply\n", status);
133072ac97cdSTom Musta }
133172ac97cdSTom Musta #endif
133272ac97cdSTom Musta /* add the third operand and result -> res, and all is done */
133372ac97cdSTom Musta decAddOp(res, acc, fhs, set, 0, &status);
133472ac97cdSTom Musta } while(0); /* end protected */
133572ac97cdSTom Musta
133672ac97cdSTom Musta if (allocbufa!=NULL) free(allocbufa); /* drop any storage used */
133772ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
133872ac97cdSTom Musta #if DECCHECK
133972ac97cdSTom Musta decCheckInexact(res, set);
134072ac97cdSTom Musta #endif
134172ac97cdSTom Musta return res;
134272ac97cdSTom Musta } /* decNumberFMA */
134372ac97cdSTom Musta
134472ac97cdSTom Musta /* ------------------------------------------------------------------ */
134572ac97cdSTom Musta /* decNumberInvert -- invert a Number, digitwise */
134672ac97cdSTom Musta /* */
134772ac97cdSTom Musta /* This computes C = ~A */
134872ac97cdSTom Musta /* */
134972ac97cdSTom Musta /* res is C, the result. C may be A (e.g., X=~X) */
135072ac97cdSTom Musta /* rhs is A */
135172ac97cdSTom Musta /* set is the context (used for result length and error report) */
135272ac97cdSTom Musta /* */
135372ac97cdSTom Musta /* C must have space for set->digits digits. */
135472ac97cdSTom Musta /* */
135572ac97cdSTom Musta /* Logical function restrictions apply (see above); a NaN is */
135672ac97cdSTom Musta /* returned with Invalid_operation if a restriction is violated. */
135772ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberInvert(decNumber * res,const decNumber * rhs,decContext * set)135872ac97cdSTom Musta decNumber * decNumberInvert(decNumber *res, const decNumber *rhs,
135972ac97cdSTom Musta decContext *set) {
136072ac97cdSTom Musta const Unit *ua, *msua; /* -> operand and its msu */
136172ac97cdSTom Musta Unit *uc, *msuc; /* -> result and its msu */
136272ac97cdSTom Musta Int msudigs; /* digits in res msu */
136372ac97cdSTom Musta #if DECCHECK
136472ac97cdSTom Musta if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
136572ac97cdSTom Musta #endif
136672ac97cdSTom Musta
136772ac97cdSTom Musta if (rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
136872ac97cdSTom Musta decStatus(res, DEC_Invalid_operation, set);
136972ac97cdSTom Musta return res;
137072ac97cdSTom Musta }
137172ac97cdSTom Musta /* operand is valid */
137272ac97cdSTom Musta ua=rhs->lsu; /* bottom-up */
137372ac97cdSTom Musta uc=res->lsu; /* .. */
137472ac97cdSTom Musta msua=ua+D2U(rhs->digits)-1; /* -> msu of rhs */
137572ac97cdSTom Musta msuc=uc+D2U(set->digits)-1; /* -> msu of result */
137672ac97cdSTom Musta msudigs=MSUDIGITS(set->digits); /* [faster than remainder] */
137772ac97cdSTom Musta for (; uc<=msuc; ua++, uc++) { /* Unit loop */
137872ac97cdSTom Musta Unit a; /* extract unit */
137972ac97cdSTom Musta Int i, j; /* work */
138072ac97cdSTom Musta if (ua>msua) a=0;
138172ac97cdSTom Musta else a=*ua;
138272ac97cdSTom Musta *uc=0; /* can now write back */
138372ac97cdSTom Musta /* always need to examine all bits in rhs */
138472ac97cdSTom Musta /* This loop could be unrolled and/or use BIN2BCD tables */
138572ac97cdSTom Musta for (i=0; i<DECDPUN; i++) {
138672ac97cdSTom Musta if ((~a)&1) *uc=*uc+(Unit)powers[i]; /* effect INVERT */
138772ac97cdSTom Musta j=a%10;
138872ac97cdSTom Musta a=a/10;
138972ac97cdSTom Musta if (j>1) {
139072ac97cdSTom Musta decStatus(res, DEC_Invalid_operation, set);
139172ac97cdSTom Musta return res;
139272ac97cdSTom Musta }
139372ac97cdSTom Musta if (uc==msuc && i==msudigs-1) break; /* just did final digit */
139472ac97cdSTom Musta } /* each digit */
139572ac97cdSTom Musta } /* each unit */
139672ac97cdSTom Musta /* [here uc-1 is the msu of the result] */
139772ac97cdSTom Musta res->digits=decGetDigits(res->lsu, uc-res->lsu);
139872ac97cdSTom Musta res->exponent=0; /* integer */
139972ac97cdSTom Musta res->bits=0; /* sign=0 */
140072ac97cdSTom Musta return res; /* [no status to set] */
140172ac97cdSTom Musta } /* decNumberInvert */
140272ac97cdSTom Musta
140372ac97cdSTom Musta /* ------------------------------------------------------------------ */
140472ac97cdSTom Musta /* decNumberLn -- natural logarithm */
140572ac97cdSTom Musta /* */
140672ac97cdSTom Musta /* This computes C = ln(A) */
140772ac97cdSTom Musta /* */
140872ac97cdSTom Musta /* res is C, the result. C may be A */
140972ac97cdSTom Musta /* rhs is A */
141072ac97cdSTom Musta /* set is the context; note that rounding mode has no effect */
141172ac97cdSTom Musta /* */
141272ac97cdSTom Musta /* C must have space for set->digits digits. */
141372ac97cdSTom Musta /* */
141472ac97cdSTom Musta /* Notable cases: */
141572ac97cdSTom Musta /* A<0 -> Invalid */
141672ac97cdSTom Musta /* A=0 -> -Infinity (Exact) */
141772ac97cdSTom Musta /* A=+Infinity -> +Infinity (Exact) */
141872ac97cdSTom Musta /* A=1 exactly -> 0 (Exact) */
141972ac97cdSTom Musta /* */
142072ac97cdSTom Musta /* Mathematical function restrictions apply (see above); a NaN is */
142172ac97cdSTom Musta /* returned with Invalid_operation if a restriction is violated. */
142272ac97cdSTom Musta /* */
142372ac97cdSTom Musta /* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */
142472ac97cdSTom Musta /* almost always be correctly rounded, but may be up to 1 ulp in */
142572ac97cdSTom Musta /* error in rare cases. */
142672ac97cdSTom Musta /* ------------------------------------------------------------------ */
142772ac97cdSTom Musta /* This is a wrapper for decLnOp which can handle the slightly wider */
142872ac97cdSTom Musta /* (+11) range needed by Ln, Log10, etc. (which may have to be able */
142972ac97cdSTom Musta /* to calculate at p+e+2). */
143072ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberLn(decNumber * res,const decNumber * rhs,decContext * set)143172ac97cdSTom Musta decNumber * decNumberLn(decNumber *res, const decNumber *rhs,
143272ac97cdSTom Musta decContext *set) {
143372ac97cdSTom Musta uInt status=0; /* accumulator */
143472ac97cdSTom Musta #if DECSUBSET
143572ac97cdSTom Musta decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
143672ac97cdSTom Musta #endif
143772ac97cdSTom Musta
143872ac97cdSTom Musta #if DECCHECK
143972ac97cdSTom Musta if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
144072ac97cdSTom Musta #endif
144172ac97cdSTom Musta
144272ac97cdSTom Musta /* Check restrictions; this is a math function; if not violated */
144372ac97cdSTom Musta /* then carry out the operation. */
144472ac97cdSTom Musta if (!decCheckMath(rhs, set, &status)) do { /* protect allocation */
144572ac97cdSTom Musta #if DECSUBSET
144672ac97cdSTom Musta if (!set->extended) {
144772ac97cdSTom Musta /* reduce operand and set lostDigits status, as needed */
144872ac97cdSTom Musta if (rhs->digits>set->digits) {
144972ac97cdSTom Musta allocrhs=decRoundOperand(rhs, set, &status);
145072ac97cdSTom Musta if (allocrhs==NULL) break;
145172ac97cdSTom Musta rhs=allocrhs;
145272ac97cdSTom Musta }
145372ac97cdSTom Musta /* special check in subset for rhs=0 */
145472ac97cdSTom Musta if (ISZERO(rhs)) { /* +/- zeros -> error */
145572ac97cdSTom Musta status|=DEC_Invalid_operation;
145672ac97cdSTom Musta break;}
145772ac97cdSTom Musta } /* extended=0 */
145872ac97cdSTom Musta #endif
145972ac97cdSTom Musta decLnOp(res, rhs, set, &status);
146072ac97cdSTom Musta } while(0); /* end protected */
146172ac97cdSTom Musta
146272ac97cdSTom Musta #if DECSUBSET
146372ac97cdSTom Musta if (allocrhs !=NULL) free(allocrhs); /* drop any storage used */
146472ac97cdSTom Musta #endif
146572ac97cdSTom Musta /* apply significant status */
146672ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
146772ac97cdSTom Musta #if DECCHECK
146872ac97cdSTom Musta decCheckInexact(res, set);
146972ac97cdSTom Musta #endif
147072ac97cdSTom Musta return res;
147172ac97cdSTom Musta } /* decNumberLn */
147272ac97cdSTom Musta
147372ac97cdSTom Musta /* ------------------------------------------------------------------ */
147472ac97cdSTom Musta /* decNumberLogB - get adjusted exponent, by 754r rules */
147572ac97cdSTom Musta /* */
147672ac97cdSTom Musta /* This computes C = adjustedexponent(A) */
147772ac97cdSTom Musta /* */
147872ac97cdSTom Musta /* res is C, the result. C may be A */
147972ac97cdSTom Musta /* rhs is A */
148072ac97cdSTom Musta /* set is the context, used only for digits and status */
148172ac97cdSTom Musta /* */
148272ac97cdSTom Musta /* C must have space for 10 digits (A might have 10**9 digits and */
148372ac97cdSTom Musta /* an exponent of +999999999, or one digit and an exponent of */
148472ac97cdSTom Musta /* -1999999999). */
148572ac97cdSTom Musta /* */
148672ac97cdSTom Musta /* This returns the adjusted exponent of A after (in theory) padding */
148772ac97cdSTom Musta /* with zeros on the right to set->digits digits while keeping the */
148872ac97cdSTom Musta /* same value. The exponent is not limited by emin/emax. */
148972ac97cdSTom Musta /* */
149072ac97cdSTom Musta /* Notable cases: */
149172ac97cdSTom Musta /* A<0 -> Use |A| */
149272ac97cdSTom Musta /* A=0 -> -Infinity (Division by zero) */
149372ac97cdSTom Musta /* A=Infinite -> +Infinity (Exact) */
149472ac97cdSTom Musta /* A=1 exactly -> 0 (Exact) */
149572ac97cdSTom Musta /* NaNs are propagated as usual */
149672ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberLogB(decNumber * res,const decNumber * rhs,decContext * set)149772ac97cdSTom Musta decNumber * decNumberLogB(decNumber *res, const decNumber *rhs,
149872ac97cdSTom Musta decContext *set) {
149972ac97cdSTom Musta uInt status=0; /* accumulator */
150072ac97cdSTom Musta
150172ac97cdSTom Musta #if DECCHECK
150272ac97cdSTom Musta if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
150372ac97cdSTom Musta #endif
150472ac97cdSTom Musta
150572ac97cdSTom Musta /* NaNs as usual; Infinities return +Infinity; 0->oops */
150672ac97cdSTom Musta if (decNumberIsNaN(rhs)) decNaNs(res, rhs, NULL, set, &status);
150772ac97cdSTom Musta else if (decNumberIsInfinite(rhs)) decNumberCopyAbs(res, rhs);
150872ac97cdSTom Musta else if (decNumberIsZero(rhs)) {
150972ac97cdSTom Musta decNumberZero(res); /* prepare for Infinity */
151072ac97cdSTom Musta res->bits=DECNEG|DECINF; /* -Infinity */
151172ac97cdSTom Musta status|=DEC_Division_by_zero; /* as per 754r */
151272ac97cdSTom Musta }
151372ac97cdSTom Musta else { /* finite non-zero */
151472ac97cdSTom Musta Int ae=rhs->exponent+rhs->digits-1; /* adjusted exponent */
151572ac97cdSTom Musta decNumberFromInt32(res, ae); /* lay it out */
151672ac97cdSTom Musta }
151772ac97cdSTom Musta
151872ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
151972ac97cdSTom Musta return res;
152072ac97cdSTom Musta } /* decNumberLogB */
152172ac97cdSTom Musta
152272ac97cdSTom Musta /* ------------------------------------------------------------------ */
152372ac97cdSTom Musta /* decNumberLog10 -- logarithm in base 10 */
152472ac97cdSTom Musta /* */
152572ac97cdSTom Musta /* This computes C = log10(A) */
152672ac97cdSTom Musta /* */
152772ac97cdSTom Musta /* res is C, the result. C may be A */
152872ac97cdSTom Musta /* rhs is A */
152972ac97cdSTom Musta /* set is the context; note that rounding mode has no effect */
153072ac97cdSTom Musta /* */
153172ac97cdSTom Musta /* C must have space for set->digits digits. */
153272ac97cdSTom Musta /* */
153372ac97cdSTom Musta /* Notable cases: */
153472ac97cdSTom Musta /* A<0 -> Invalid */
153572ac97cdSTom Musta /* A=0 -> -Infinity (Exact) */
153672ac97cdSTom Musta /* A=+Infinity -> +Infinity (Exact) */
153772ac97cdSTom Musta /* A=10**n (if n is an integer) -> n (Exact) */
153872ac97cdSTom Musta /* */
153972ac97cdSTom Musta /* Mathematical function restrictions apply (see above); a NaN is */
154072ac97cdSTom Musta /* returned with Invalid_operation if a restriction is violated. */
154172ac97cdSTom Musta /* */
154272ac97cdSTom Musta /* An Inexact result is rounded using DEC_ROUND_HALF_EVEN; it will */
154372ac97cdSTom Musta /* almost always be correctly rounded, but may be up to 1 ulp in */
154472ac97cdSTom Musta /* error in rare cases. */
154572ac97cdSTom Musta /* ------------------------------------------------------------------ */
154672ac97cdSTom Musta /* This calculates ln(A)/ln(10) using appropriate precision. For */
154772ac97cdSTom Musta /* ln(A) this is the max(p, rhs->digits + t) + 3, where p is the */
154872ac97cdSTom Musta /* requested digits and t is the number of digits in the exponent */
154972ac97cdSTom Musta /* (maximum 6). For ln(10) it is p + 3; this is often handled by the */
155072ac97cdSTom Musta /* fastpath in decLnOp. The final division is done to the requested */
155172ac97cdSTom Musta /* precision. */
155272ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberLog10(decNumber * res,const decNumber * rhs,decContext * set)155372ac97cdSTom Musta decNumber * decNumberLog10(decNumber *res, const decNumber *rhs,
155472ac97cdSTom Musta decContext *set) {
155572ac97cdSTom Musta uInt status=0, ignore=0; /* status accumulators */
155672ac97cdSTom Musta uInt needbytes; /* for space calculations */
155772ac97cdSTom Musta Int p; /* working precision */
155872ac97cdSTom Musta Int t; /* digits in exponent of A */
155972ac97cdSTom Musta
156072ac97cdSTom Musta /* buffers for a and b working decimals */
156172ac97cdSTom Musta /* (adjustment calculator, same size) */
156272ac97cdSTom Musta decNumber bufa[D2N(DECBUFFER+2)];
156372ac97cdSTom Musta decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
156472ac97cdSTom Musta decNumber *a=bufa; /* temporary a */
156572ac97cdSTom Musta decNumber bufb[D2N(DECBUFFER+2)];
156672ac97cdSTom Musta decNumber *allocbufb=NULL; /* -> allocated bufb, iff allocated */
156772ac97cdSTom Musta decNumber *b=bufb; /* temporary b */
156872ac97cdSTom Musta decNumber bufw[D2N(10)]; /* working 2-10 digit number */
156972ac97cdSTom Musta decNumber *w=bufw; /* .. */
157072ac97cdSTom Musta #if DECSUBSET
157172ac97cdSTom Musta decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
157272ac97cdSTom Musta #endif
157372ac97cdSTom Musta
157472ac97cdSTom Musta decContext aset; /* working context */
157572ac97cdSTom Musta
157672ac97cdSTom Musta #if DECCHECK
157772ac97cdSTom Musta if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
157872ac97cdSTom Musta #endif
157972ac97cdSTom Musta
158072ac97cdSTom Musta /* Check restrictions; this is a math function; if not violated */
158172ac97cdSTom Musta /* then carry out the operation. */
158272ac97cdSTom Musta if (!decCheckMath(rhs, set, &status)) do { /* protect malloc */
158372ac97cdSTom Musta #if DECSUBSET
158472ac97cdSTom Musta if (!set->extended) {
158572ac97cdSTom Musta /* reduce operand and set lostDigits status, as needed */
158672ac97cdSTom Musta if (rhs->digits>set->digits) {
158772ac97cdSTom Musta allocrhs=decRoundOperand(rhs, set, &status);
158872ac97cdSTom Musta if (allocrhs==NULL) break;
158972ac97cdSTom Musta rhs=allocrhs;
159072ac97cdSTom Musta }
159172ac97cdSTom Musta /* special check in subset for rhs=0 */
159272ac97cdSTom Musta if (ISZERO(rhs)) { /* +/- zeros -> error */
159372ac97cdSTom Musta status|=DEC_Invalid_operation;
159472ac97cdSTom Musta break;}
159572ac97cdSTom Musta } /* extended=0 */
159672ac97cdSTom Musta #endif
159772ac97cdSTom Musta
159872ac97cdSTom Musta decContextDefault(&aset, DEC_INIT_DECIMAL64); /* clean context */
159972ac97cdSTom Musta
160072ac97cdSTom Musta /* handle exact powers of 10; only check if +ve finite */
160172ac97cdSTom Musta if (!(rhs->bits&(DECNEG|DECSPECIAL)) && !ISZERO(rhs)) {
160272ac97cdSTom Musta Int residue=0; /* (no residue) */
160372ac97cdSTom Musta uInt copystat=0; /* clean status */
160472ac97cdSTom Musta
160572ac97cdSTom Musta /* round to a single digit... */
160672ac97cdSTom Musta aset.digits=1;
160772ac97cdSTom Musta decCopyFit(w, rhs, &aset, &residue, ©stat); /* copy & shorten */
160872ac97cdSTom Musta /* if exact and the digit is 1, rhs is a power of 10 */
160972ac97cdSTom Musta if (!(copystat&DEC_Inexact) && w->lsu[0]==1) {
161072ac97cdSTom Musta /* the exponent, conveniently, is the power of 10; making */
161172ac97cdSTom Musta /* this the result needs a little care as it might not fit, */
161272ac97cdSTom Musta /* so first convert it into the working number, and then move */
161372ac97cdSTom Musta /* to res */
161472ac97cdSTom Musta decNumberFromInt32(w, w->exponent);
161572ac97cdSTom Musta residue=0;
161672ac97cdSTom Musta decCopyFit(res, w, set, &residue, &status); /* copy & round */
161772ac97cdSTom Musta decFinish(res, set, &residue, &status); /* cleanup/set flags */
161872ac97cdSTom Musta break;
161972ac97cdSTom Musta } /* not a power of 10 */
162072ac97cdSTom Musta } /* not a candidate for exact */
162172ac97cdSTom Musta
162272ac97cdSTom Musta /* simplify the information-content calculation to use 'total */
162372ac97cdSTom Musta /* number of digits in a, including exponent' as compared to the */
162472ac97cdSTom Musta /* requested digits, as increasing this will only rarely cost an */
162572ac97cdSTom Musta /* iteration in ln(a) anyway */
162672ac97cdSTom Musta t=6; /* it can never be >6 */
162772ac97cdSTom Musta
162872ac97cdSTom Musta /* allocate space when needed... */
162972ac97cdSTom Musta p=(rhs->digits+t>set->digits?rhs->digits+t:set->digits)+3;
163072ac97cdSTom Musta needbytes=sizeof(decNumber)+(D2U(p)-1)*sizeof(Unit);
163172ac97cdSTom Musta if (needbytes>sizeof(bufa)) { /* need malloc space */
163272ac97cdSTom Musta allocbufa=(decNumber *)malloc(needbytes);
163372ac97cdSTom Musta if (allocbufa==NULL) { /* hopeless -- abandon */
163472ac97cdSTom Musta status|=DEC_Insufficient_storage;
163572ac97cdSTom Musta break;}
163672ac97cdSTom Musta a=allocbufa; /* use the allocated space */
163772ac97cdSTom Musta }
163872ac97cdSTom Musta aset.digits=p; /* as calculated */
163972ac97cdSTom Musta aset.emax=DEC_MAX_MATH; /* usual bounds */
164072ac97cdSTom Musta aset.emin=-DEC_MAX_MATH; /* .. */
164172ac97cdSTom Musta aset.clamp=0; /* and no concrete format */
164272ac97cdSTom Musta decLnOp(a, rhs, &aset, &status); /* a=ln(rhs) */
164372ac97cdSTom Musta
164472ac97cdSTom Musta /* skip the division if the result so far is infinite, NaN, or */
164572ac97cdSTom Musta /* zero, or there was an error; note NaN from sNaN needs copy */
164672ac97cdSTom Musta if (status&DEC_NaNs && !(status&DEC_sNaN)) break;
164772ac97cdSTom Musta if (a->bits&DECSPECIAL || ISZERO(a)) {
164872ac97cdSTom Musta decNumberCopy(res, a); /* [will fit] */
164972ac97cdSTom Musta break;}
165072ac97cdSTom Musta
165172ac97cdSTom Musta /* for ln(10) an extra 3 digits of precision are needed */
165272ac97cdSTom Musta p=set->digits+3;
165372ac97cdSTom Musta needbytes=sizeof(decNumber)+(D2U(p)-1)*sizeof(Unit);
165472ac97cdSTom Musta if (needbytes>sizeof(bufb)) { /* need malloc space */
165572ac97cdSTom Musta allocbufb=(decNumber *)malloc(needbytes);
165672ac97cdSTom Musta if (allocbufb==NULL) { /* hopeless -- abandon */
165772ac97cdSTom Musta status|=DEC_Insufficient_storage;
165872ac97cdSTom Musta break;}
165972ac97cdSTom Musta b=allocbufb; /* use the allocated space */
166072ac97cdSTom Musta }
166172ac97cdSTom Musta decNumberZero(w); /* set up 10... */
166272ac97cdSTom Musta #if DECDPUN==1
166372ac97cdSTom Musta w->lsu[1]=1; w->lsu[0]=0; /* .. */
166472ac97cdSTom Musta #else
166572ac97cdSTom Musta w->lsu[0]=10; /* .. */
166672ac97cdSTom Musta #endif
166772ac97cdSTom Musta w->digits=2; /* .. */
166872ac97cdSTom Musta
166972ac97cdSTom Musta aset.digits=p;
167072ac97cdSTom Musta decLnOp(b, w, &aset, &ignore); /* b=ln(10) */
167172ac97cdSTom Musta
167272ac97cdSTom Musta aset.digits=set->digits; /* for final divide */
167372ac97cdSTom Musta decDivideOp(res, a, b, &aset, DIVIDE, &status); /* into result */
167472ac97cdSTom Musta } while(0); /* [for break] */
167572ac97cdSTom Musta
167672ac97cdSTom Musta if (allocbufa!=NULL) free(allocbufa); /* drop any storage used */
167772ac97cdSTom Musta if (allocbufb!=NULL) free(allocbufb); /* .. */
167872ac97cdSTom Musta #if DECSUBSET
167972ac97cdSTom Musta if (allocrhs !=NULL) free(allocrhs); /* .. */
168072ac97cdSTom Musta #endif
168172ac97cdSTom Musta /* apply significant status */
168272ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
168372ac97cdSTom Musta #if DECCHECK
168472ac97cdSTom Musta decCheckInexact(res, set);
168572ac97cdSTom Musta #endif
168672ac97cdSTom Musta return res;
168772ac97cdSTom Musta } /* decNumberLog10 */
168872ac97cdSTom Musta
168972ac97cdSTom Musta /* ------------------------------------------------------------------ */
169072ac97cdSTom Musta /* decNumberMax -- compare two Numbers and return the maximum */
169172ac97cdSTom Musta /* */
169272ac97cdSTom Musta /* This computes C = A ? B, returning the maximum by 754R rules */
169372ac97cdSTom Musta /* */
169472ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X?X) */
169572ac97cdSTom Musta /* lhs is A */
169672ac97cdSTom Musta /* rhs is B */
169772ac97cdSTom Musta /* set is the context */
169872ac97cdSTom Musta /* */
169972ac97cdSTom Musta /* C must have space for set->digits digits. */
170072ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberMax(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)170172ac97cdSTom Musta decNumber * decNumberMax(decNumber *res, const decNumber *lhs,
170272ac97cdSTom Musta const decNumber *rhs, decContext *set) {
170372ac97cdSTom Musta uInt status=0; /* accumulator */
170472ac97cdSTom Musta decCompareOp(res, lhs, rhs, set, COMPMAX, &status);
170572ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
170672ac97cdSTom Musta #if DECCHECK
170772ac97cdSTom Musta decCheckInexact(res, set);
170872ac97cdSTom Musta #endif
170972ac97cdSTom Musta return res;
171072ac97cdSTom Musta } /* decNumberMax */
171172ac97cdSTom Musta
171272ac97cdSTom Musta /* ------------------------------------------------------------------ */
171372ac97cdSTom Musta /* decNumberMaxMag -- compare and return the maximum by magnitude */
171472ac97cdSTom Musta /* */
171572ac97cdSTom Musta /* This computes C = A ? B, returning the maximum by 754R rules */
171672ac97cdSTom Musta /* */
171772ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X?X) */
171872ac97cdSTom Musta /* lhs is A */
171972ac97cdSTom Musta /* rhs is B */
172072ac97cdSTom Musta /* set is the context */
172172ac97cdSTom Musta /* */
172272ac97cdSTom Musta /* C must have space for set->digits digits. */
172372ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberMaxMag(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)172472ac97cdSTom Musta decNumber * decNumberMaxMag(decNumber *res, const decNumber *lhs,
172572ac97cdSTom Musta const decNumber *rhs, decContext *set) {
172672ac97cdSTom Musta uInt status=0; /* accumulator */
172772ac97cdSTom Musta decCompareOp(res, lhs, rhs, set, COMPMAXMAG, &status);
172872ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
172972ac97cdSTom Musta #if DECCHECK
173072ac97cdSTom Musta decCheckInexact(res, set);
173172ac97cdSTom Musta #endif
173272ac97cdSTom Musta return res;
173372ac97cdSTom Musta } /* decNumberMaxMag */
173472ac97cdSTom Musta
173572ac97cdSTom Musta /* ------------------------------------------------------------------ */
173672ac97cdSTom Musta /* decNumberMin -- compare two Numbers and return the minimum */
173772ac97cdSTom Musta /* */
173872ac97cdSTom Musta /* This computes C = A ? B, returning the minimum by 754R rules */
173972ac97cdSTom Musta /* */
174072ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X?X) */
174172ac97cdSTom Musta /* lhs is A */
174272ac97cdSTom Musta /* rhs is B */
174372ac97cdSTom Musta /* set is the context */
174472ac97cdSTom Musta /* */
174572ac97cdSTom Musta /* C must have space for set->digits digits. */
174672ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberMin(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)174772ac97cdSTom Musta decNumber * decNumberMin(decNumber *res, const decNumber *lhs,
174872ac97cdSTom Musta const decNumber *rhs, decContext *set) {
174972ac97cdSTom Musta uInt status=0; /* accumulator */
175072ac97cdSTom Musta decCompareOp(res, lhs, rhs, set, COMPMIN, &status);
175172ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
175272ac97cdSTom Musta #if DECCHECK
175372ac97cdSTom Musta decCheckInexact(res, set);
175472ac97cdSTom Musta #endif
175572ac97cdSTom Musta return res;
175672ac97cdSTom Musta } /* decNumberMin */
175772ac97cdSTom Musta
175872ac97cdSTom Musta /* ------------------------------------------------------------------ */
175972ac97cdSTom Musta /* decNumberMinMag -- compare and return the minimum by magnitude */
176072ac97cdSTom Musta /* */
176172ac97cdSTom Musta /* This computes C = A ? B, returning the minimum by 754R rules */
176272ac97cdSTom Musta /* */
176372ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X?X) */
176472ac97cdSTom Musta /* lhs is A */
176572ac97cdSTom Musta /* rhs is B */
176672ac97cdSTom Musta /* set is the context */
176772ac97cdSTom Musta /* */
176872ac97cdSTom Musta /* C must have space for set->digits digits. */
176972ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberMinMag(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)177072ac97cdSTom Musta decNumber * decNumberMinMag(decNumber *res, const decNumber *lhs,
177172ac97cdSTom Musta const decNumber *rhs, decContext *set) {
177272ac97cdSTom Musta uInt status=0; /* accumulator */
177372ac97cdSTom Musta decCompareOp(res, lhs, rhs, set, COMPMINMAG, &status);
177472ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
177572ac97cdSTom Musta #if DECCHECK
177672ac97cdSTom Musta decCheckInexact(res, set);
177772ac97cdSTom Musta #endif
177872ac97cdSTom Musta return res;
177972ac97cdSTom Musta } /* decNumberMinMag */
178072ac97cdSTom Musta
178172ac97cdSTom Musta /* ------------------------------------------------------------------ */
178272ac97cdSTom Musta /* decNumberMinus -- prefix minus operator */
178372ac97cdSTom Musta /* */
178472ac97cdSTom Musta /* This computes C = 0 - A */
178572ac97cdSTom Musta /* */
178672ac97cdSTom Musta /* res is C, the result. C may be A */
178772ac97cdSTom Musta /* rhs is A */
178872ac97cdSTom Musta /* set is the context */
178972ac97cdSTom Musta /* */
179072ac97cdSTom Musta /* See also decNumberCopyNegate for a quiet bitwise version of this. */
179172ac97cdSTom Musta /* C must have space for set->digits digits. */
179272ac97cdSTom Musta /* ------------------------------------------------------------------ */
179372ac97cdSTom Musta /* Simply use AddOp for the subtract, which will do the necessary. */
179472ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberMinus(decNumber * res,const decNumber * rhs,decContext * set)179572ac97cdSTom Musta decNumber * decNumberMinus(decNumber *res, const decNumber *rhs,
179672ac97cdSTom Musta decContext *set) {
179772ac97cdSTom Musta decNumber dzero;
179872ac97cdSTom Musta uInt status=0; /* accumulator */
179972ac97cdSTom Musta
180072ac97cdSTom Musta #if DECCHECK
180172ac97cdSTom Musta if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
180272ac97cdSTom Musta #endif
180372ac97cdSTom Musta
180472ac97cdSTom Musta decNumberZero(&dzero); /* make 0 */
180572ac97cdSTom Musta dzero.exponent=rhs->exponent; /* [no coefficient expansion] */
180672ac97cdSTom Musta decAddOp(res, &dzero, rhs, set, DECNEG, &status);
180772ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
180872ac97cdSTom Musta #if DECCHECK
180972ac97cdSTom Musta decCheckInexact(res, set);
181072ac97cdSTom Musta #endif
181172ac97cdSTom Musta return res;
181272ac97cdSTom Musta } /* decNumberMinus */
181372ac97cdSTom Musta
181472ac97cdSTom Musta /* ------------------------------------------------------------------ */
181572ac97cdSTom Musta /* decNumberNextMinus -- next towards -Infinity */
181672ac97cdSTom Musta /* */
181772ac97cdSTom Musta /* This computes C = A - infinitesimal, rounded towards -Infinity */
181872ac97cdSTom Musta /* */
181972ac97cdSTom Musta /* res is C, the result. C may be A */
182072ac97cdSTom Musta /* rhs is A */
182172ac97cdSTom Musta /* set is the context */
182272ac97cdSTom Musta /* */
182372ac97cdSTom Musta /* This is a generalization of 754r NextDown. */
182472ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberNextMinus(decNumber * res,const decNumber * rhs,decContext * set)182572ac97cdSTom Musta decNumber * decNumberNextMinus(decNumber *res, const decNumber *rhs,
182672ac97cdSTom Musta decContext *set) {
182772ac97cdSTom Musta decNumber dtiny; /* constant */
182872ac97cdSTom Musta decContext workset=*set; /* work */
182972ac97cdSTom Musta uInt status=0; /* accumulator */
183072ac97cdSTom Musta #if DECCHECK
183172ac97cdSTom Musta if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
183272ac97cdSTom Musta #endif
183372ac97cdSTom Musta
183472ac97cdSTom Musta /* +Infinity is the special case */
183572ac97cdSTom Musta if ((rhs->bits&(DECINF|DECNEG))==DECINF) {
183672ac97cdSTom Musta decSetMaxValue(res, set); /* is +ve */
183772ac97cdSTom Musta /* there is no status to set */
183872ac97cdSTom Musta return res;
183972ac97cdSTom Musta }
184072ac97cdSTom Musta decNumberZero(&dtiny); /* start with 0 */
184172ac97cdSTom Musta dtiny.lsu[0]=1; /* make number that is .. */
184272ac97cdSTom Musta dtiny.exponent=DEC_MIN_EMIN-1; /* .. smaller than tiniest */
184372ac97cdSTom Musta workset.round=DEC_ROUND_FLOOR;
184472ac97cdSTom Musta decAddOp(res, rhs, &dtiny, &workset, DECNEG, &status);
184572ac97cdSTom Musta status&=DEC_Invalid_operation|DEC_sNaN; /* only sNaN Invalid please */
184672ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
184772ac97cdSTom Musta return res;
184872ac97cdSTom Musta } /* decNumberNextMinus */
184972ac97cdSTom Musta
185072ac97cdSTom Musta /* ------------------------------------------------------------------ */
185172ac97cdSTom Musta /* decNumberNextPlus -- next towards +Infinity */
185272ac97cdSTom Musta /* */
185372ac97cdSTom Musta /* This computes C = A + infinitesimal, rounded towards +Infinity */
185472ac97cdSTom Musta /* */
185572ac97cdSTom Musta /* res is C, the result. C may be A */
185672ac97cdSTom Musta /* rhs is A */
185772ac97cdSTom Musta /* set is the context */
185872ac97cdSTom Musta /* */
185972ac97cdSTom Musta /* This is a generalization of 754r NextUp. */
186072ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberNextPlus(decNumber * res,const decNumber * rhs,decContext * set)186172ac97cdSTom Musta decNumber * decNumberNextPlus(decNumber *res, const decNumber *rhs,
186272ac97cdSTom Musta decContext *set) {
186372ac97cdSTom Musta decNumber dtiny; /* constant */
186472ac97cdSTom Musta decContext workset=*set; /* work */
186572ac97cdSTom Musta uInt status=0; /* accumulator */
186672ac97cdSTom Musta #if DECCHECK
186772ac97cdSTom Musta if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
186872ac97cdSTom Musta #endif
186972ac97cdSTom Musta
187072ac97cdSTom Musta /* -Infinity is the special case */
187172ac97cdSTom Musta if ((rhs->bits&(DECINF|DECNEG))==(DECINF|DECNEG)) {
187272ac97cdSTom Musta decSetMaxValue(res, set);
187372ac97cdSTom Musta res->bits=DECNEG; /* negative */
187472ac97cdSTom Musta /* there is no status to set */
187572ac97cdSTom Musta return res;
187672ac97cdSTom Musta }
187772ac97cdSTom Musta decNumberZero(&dtiny); /* start with 0 */
187872ac97cdSTom Musta dtiny.lsu[0]=1; /* make number that is .. */
187972ac97cdSTom Musta dtiny.exponent=DEC_MIN_EMIN-1; /* .. smaller than tiniest */
188072ac97cdSTom Musta workset.round=DEC_ROUND_CEILING;
188172ac97cdSTom Musta decAddOp(res, rhs, &dtiny, &workset, 0, &status);
188272ac97cdSTom Musta status&=DEC_Invalid_operation|DEC_sNaN; /* only sNaN Invalid please */
188372ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
188472ac97cdSTom Musta return res;
188572ac97cdSTom Musta } /* decNumberNextPlus */
188672ac97cdSTom Musta
188772ac97cdSTom Musta /* ------------------------------------------------------------------ */
188872ac97cdSTom Musta /* decNumberNextToward -- next towards rhs */
188972ac97cdSTom Musta /* */
189072ac97cdSTom Musta /* This computes C = A +/- infinitesimal, rounded towards */
189172ac97cdSTom Musta /* +/-Infinity in the direction of B, as per 754r nextafter rules */
189272ac97cdSTom Musta /* */
189372ac97cdSTom Musta /* res is C, the result. C may be A or B. */
189472ac97cdSTom Musta /* lhs is A */
189572ac97cdSTom Musta /* rhs is B */
189672ac97cdSTom Musta /* set is the context */
189772ac97cdSTom Musta /* */
189872ac97cdSTom Musta /* This is a generalization of 754r NextAfter. */
189972ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberNextToward(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)190072ac97cdSTom Musta decNumber * decNumberNextToward(decNumber *res, const decNumber *lhs,
190172ac97cdSTom Musta const decNumber *rhs, decContext *set) {
190272ac97cdSTom Musta decNumber dtiny; /* constant */
190372ac97cdSTom Musta decContext workset=*set; /* work */
190472ac97cdSTom Musta Int result; /* .. */
190572ac97cdSTom Musta uInt status=0; /* accumulator */
190672ac97cdSTom Musta #if DECCHECK
190772ac97cdSTom Musta if (decCheckOperands(res, lhs, rhs, set)) return res;
190872ac97cdSTom Musta #endif
190972ac97cdSTom Musta
191072ac97cdSTom Musta if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) {
191172ac97cdSTom Musta decNaNs(res, lhs, rhs, set, &status);
191272ac97cdSTom Musta }
191372ac97cdSTom Musta else { /* Is numeric, so no chance of sNaN Invalid, etc. */
191472ac97cdSTom Musta result=decCompare(lhs, rhs, 0); /* sign matters */
191572ac97cdSTom Musta if (result==BADINT) status|=DEC_Insufficient_storage; /* rare */
191672ac97cdSTom Musta else { /* valid compare */
191772ac97cdSTom Musta if (result==0) decNumberCopySign(res, lhs, rhs); /* easy */
191872ac97cdSTom Musta else { /* differ: need NextPlus or NextMinus */
191972ac97cdSTom Musta uByte sub; /* add or subtract */
192072ac97cdSTom Musta if (result<0) { /* lhs<rhs, do nextplus */
192172ac97cdSTom Musta /* -Infinity is the special case */
192272ac97cdSTom Musta if ((lhs->bits&(DECINF|DECNEG))==(DECINF|DECNEG)) {
192372ac97cdSTom Musta decSetMaxValue(res, set);
192472ac97cdSTom Musta res->bits=DECNEG; /* negative */
192572ac97cdSTom Musta return res; /* there is no status to set */
192672ac97cdSTom Musta }
192772ac97cdSTom Musta workset.round=DEC_ROUND_CEILING;
192872ac97cdSTom Musta sub=0; /* add, please */
192972ac97cdSTom Musta } /* plus */
193072ac97cdSTom Musta else { /* lhs>rhs, do nextminus */
193172ac97cdSTom Musta /* +Infinity is the special case */
193272ac97cdSTom Musta if ((lhs->bits&(DECINF|DECNEG))==DECINF) {
193372ac97cdSTom Musta decSetMaxValue(res, set);
193472ac97cdSTom Musta return res; /* there is no status to set */
193572ac97cdSTom Musta }
193672ac97cdSTom Musta workset.round=DEC_ROUND_FLOOR;
193772ac97cdSTom Musta sub=DECNEG; /* subtract, please */
193872ac97cdSTom Musta } /* minus */
193972ac97cdSTom Musta decNumberZero(&dtiny); /* start with 0 */
194072ac97cdSTom Musta dtiny.lsu[0]=1; /* make number that is .. */
194172ac97cdSTom Musta dtiny.exponent=DEC_MIN_EMIN-1; /* .. smaller than tiniest */
194272ac97cdSTom Musta decAddOp(res, lhs, &dtiny, &workset, sub, &status); /* + or - */
194372ac97cdSTom Musta /* turn off exceptions if the result is a normal number */
194472ac97cdSTom Musta /* (including Nmin), otherwise let all status through */
194572ac97cdSTom Musta if (decNumberIsNormal(res, set)) status=0;
194672ac97cdSTom Musta } /* unequal */
194772ac97cdSTom Musta } /* compare OK */
194872ac97cdSTom Musta } /* numeric */
194972ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
195072ac97cdSTom Musta return res;
195172ac97cdSTom Musta } /* decNumberNextToward */
195272ac97cdSTom Musta
195372ac97cdSTom Musta /* ------------------------------------------------------------------ */
195472ac97cdSTom Musta /* decNumberOr -- OR two Numbers, digitwise */
195572ac97cdSTom Musta /* */
195672ac97cdSTom Musta /* This computes C = A | B */
195772ac97cdSTom Musta /* */
195872ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X|X) */
195972ac97cdSTom Musta /* lhs is A */
196072ac97cdSTom Musta /* rhs is B */
196172ac97cdSTom Musta /* set is the context (used for result length and error report) */
196272ac97cdSTom Musta /* */
196372ac97cdSTom Musta /* C must have space for set->digits digits. */
196472ac97cdSTom Musta /* */
196572ac97cdSTom Musta /* Logical function restrictions apply (see above); a NaN is */
196672ac97cdSTom Musta /* returned with Invalid_operation if a restriction is violated. */
196772ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberOr(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)196872ac97cdSTom Musta decNumber * decNumberOr(decNumber *res, const decNumber *lhs,
196972ac97cdSTom Musta const decNumber *rhs, decContext *set) {
197072ac97cdSTom Musta const Unit *ua, *ub; /* -> operands */
197172ac97cdSTom Musta const Unit *msua, *msub; /* -> operand msus */
197272ac97cdSTom Musta Unit *uc, *msuc; /* -> result and its msu */
197372ac97cdSTom Musta Int msudigs; /* digits in res msu */
197472ac97cdSTom Musta #if DECCHECK
197572ac97cdSTom Musta if (decCheckOperands(res, lhs, rhs, set)) return res;
197672ac97cdSTom Musta #endif
197772ac97cdSTom Musta
197872ac97cdSTom Musta if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs)
197972ac97cdSTom Musta || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
198072ac97cdSTom Musta decStatus(res, DEC_Invalid_operation, set);
198172ac97cdSTom Musta return res;
198272ac97cdSTom Musta }
198372ac97cdSTom Musta /* operands are valid */
198472ac97cdSTom Musta ua=lhs->lsu; /* bottom-up */
198572ac97cdSTom Musta ub=rhs->lsu; /* .. */
198672ac97cdSTom Musta uc=res->lsu; /* .. */
198772ac97cdSTom Musta msua=ua+D2U(lhs->digits)-1; /* -> msu of lhs */
198872ac97cdSTom Musta msub=ub+D2U(rhs->digits)-1; /* -> msu of rhs */
198972ac97cdSTom Musta msuc=uc+D2U(set->digits)-1; /* -> msu of result */
199072ac97cdSTom Musta msudigs=MSUDIGITS(set->digits); /* [faster than remainder] */
199172ac97cdSTom Musta for (; uc<=msuc; ua++, ub++, uc++) { /* Unit loop */
199272ac97cdSTom Musta Unit a, b; /* extract units */
199372ac97cdSTom Musta if (ua>msua) a=0;
199472ac97cdSTom Musta else a=*ua;
199572ac97cdSTom Musta if (ub>msub) b=0;
199672ac97cdSTom Musta else b=*ub;
199772ac97cdSTom Musta *uc=0; /* can now write back */
199872ac97cdSTom Musta if (a|b) { /* maybe 1 bits to examine */
199972ac97cdSTom Musta Int i, j;
200072ac97cdSTom Musta /* This loop could be unrolled and/or use BIN2BCD tables */
200172ac97cdSTom Musta for (i=0; i<DECDPUN; i++) {
200272ac97cdSTom Musta if ((a|b)&1) *uc=*uc+(Unit)powers[i]; /* effect OR */
200372ac97cdSTom Musta j=a%10;
200472ac97cdSTom Musta a=a/10;
200572ac97cdSTom Musta j|=b%10;
200672ac97cdSTom Musta b=b/10;
200772ac97cdSTom Musta if (j>1) {
200872ac97cdSTom Musta decStatus(res, DEC_Invalid_operation, set);
200972ac97cdSTom Musta return res;
201072ac97cdSTom Musta }
201172ac97cdSTom Musta if (uc==msuc && i==msudigs-1) break; /* just did final digit */
201272ac97cdSTom Musta } /* each digit */
201372ac97cdSTom Musta } /* non-zero */
201472ac97cdSTom Musta } /* each unit */
201572ac97cdSTom Musta /* [here uc-1 is the msu of the result] */
201672ac97cdSTom Musta res->digits=decGetDigits(res->lsu, uc-res->lsu);
201772ac97cdSTom Musta res->exponent=0; /* integer */
201872ac97cdSTom Musta res->bits=0; /* sign=0 */
201972ac97cdSTom Musta return res; /* [no status to set] */
202072ac97cdSTom Musta } /* decNumberOr */
202172ac97cdSTom Musta
202272ac97cdSTom Musta /* ------------------------------------------------------------------ */
202372ac97cdSTom Musta /* decNumberPlus -- prefix plus operator */
202472ac97cdSTom Musta /* */
202572ac97cdSTom Musta /* This computes C = 0 + A */
202672ac97cdSTom Musta /* */
202772ac97cdSTom Musta /* res is C, the result. C may be A */
202872ac97cdSTom Musta /* rhs is A */
202972ac97cdSTom Musta /* set is the context */
203072ac97cdSTom Musta /* */
203172ac97cdSTom Musta /* See also decNumberCopy for a quiet bitwise version of this. */
203272ac97cdSTom Musta /* C must have space for set->digits digits. */
203372ac97cdSTom Musta /* ------------------------------------------------------------------ */
203472ac97cdSTom Musta /* This simply uses AddOp; Add will take fast path after preparing A. */
203572ac97cdSTom Musta /* Performance is a concern here, as this routine is often used to */
203672ac97cdSTom Musta /* check operands and apply rounding and overflow/underflow testing. */
203772ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberPlus(decNumber * res,const decNumber * rhs,decContext * set)203872ac97cdSTom Musta decNumber * decNumberPlus(decNumber *res, const decNumber *rhs,
203972ac97cdSTom Musta decContext *set) {
204072ac97cdSTom Musta decNumber dzero;
204172ac97cdSTom Musta uInt status=0; /* accumulator */
204272ac97cdSTom Musta #if DECCHECK
204372ac97cdSTom Musta if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
204472ac97cdSTom Musta #endif
204572ac97cdSTom Musta
204672ac97cdSTom Musta decNumberZero(&dzero); /* make 0 */
204772ac97cdSTom Musta dzero.exponent=rhs->exponent; /* [no coefficient expansion] */
204872ac97cdSTom Musta decAddOp(res, &dzero, rhs, set, 0, &status);
204972ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
205072ac97cdSTom Musta #if DECCHECK
205172ac97cdSTom Musta decCheckInexact(res, set);
205272ac97cdSTom Musta #endif
205372ac97cdSTom Musta return res;
205472ac97cdSTom Musta } /* decNumberPlus */
205572ac97cdSTom Musta
205672ac97cdSTom Musta /* ------------------------------------------------------------------ */
205772ac97cdSTom Musta /* decNumberMultiply -- multiply two Numbers */
205872ac97cdSTom Musta /* */
205972ac97cdSTom Musta /* This computes C = A x B */
206072ac97cdSTom Musta /* */
206172ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X+X) */
206272ac97cdSTom Musta /* lhs is A */
206372ac97cdSTom Musta /* rhs is B */
206472ac97cdSTom Musta /* set is the context */
206572ac97cdSTom Musta /* */
206672ac97cdSTom Musta /* C must have space for set->digits digits. */
206772ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberMultiply(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)206872ac97cdSTom Musta decNumber * decNumberMultiply(decNumber *res, const decNumber *lhs,
206972ac97cdSTom Musta const decNumber *rhs, decContext *set) {
207072ac97cdSTom Musta uInt status=0; /* accumulator */
207172ac97cdSTom Musta decMultiplyOp(res, lhs, rhs, set, &status);
207272ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
207372ac97cdSTom Musta #if DECCHECK
207472ac97cdSTom Musta decCheckInexact(res, set);
207572ac97cdSTom Musta #endif
207672ac97cdSTom Musta return res;
207772ac97cdSTom Musta } /* decNumberMultiply */
207872ac97cdSTom Musta
207972ac97cdSTom Musta /* ------------------------------------------------------------------ */
208072ac97cdSTom Musta /* decNumberPower -- raise a number to a power */
208172ac97cdSTom Musta /* */
208272ac97cdSTom Musta /* This computes C = A ** B */
208372ac97cdSTom Musta /* */
208472ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X**X) */
208572ac97cdSTom Musta /* lhs is A */
208672ac97cdSTom Musta /* rhs is B */
208772ac97cdSTom Musta /* set is the context */
208872ac97cdSTom Musta /* */
208972ac97cdSTom Musta /* C must have space for set->digits digits. */
209072ac97cdSTom Musta /* */
209172ac97cdSTom Musta /* Mathematical function restrictions apply (see above); a NaN is */
209272ac97cdSTom Musta /* returned with Invalid_operation if a restriction is violated. */
209372ac97cdSTom Musta /* */
209472ac97cdSTom Musta /* However, if 1999999997<=B<=999999999 and B is an integer then the */
209572ac97cdSTom Musta /* restrictions on A and the context are relaxed to the usual bounds, */
209672ac97cdSTom Musta /* for compatibility with the earlier (integer power only) version */
209772ac97cdSTom Musta /* of this function. */
209872ac97cdSTom Musta /* */
209972ac97cdSTom Musta /* When B is an integer, the result may be exact, even if rounded. */
210072ac97cdSTom Musta /* */
210172ac97cdSTom Musta /* The final result is rounded according to the context; it will */
210272ac97cdSTom Musta /* almost always be correctly rounded, but may be up to 1 ulp in */
210372ac97cdSTom Musta /* error in rare cases. */
210472ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberPower(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)210572ac97cdSTom Musta decNumber * decNumberPower(decNumber *res, const decNumber *lhs,
210672ac97cdSTom Musta const decNumber *rhs, decContext *set) {
210772ac97cdSTom Musta #if DECSUBSET
210872ac97cdSTom Musta decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
210972ac97cdSTom Musta decNumber *allocrhs=NULL; /* .., rhs */
211072ac97cdSTom Musta #endif
211172ac97cdSTom Musta decNumber *allocdac=NULL; /* -> allocated acc buffer, iff used */
211272ac97cdSTom Musta decNumber *allocinv=NULL; /* -> allocated 1/x buffer, iff used */
211372ac97cdSTom Musta Int reqdigits=set->digits; /* requested DIGITS */
211472ac97cdSTom Musta Int n; /* rhs in binary */
211572ac97cdSTom Musta Flag rhsint=0; /* 1 if rhs is an integer */
211672ac97cdSTom Musta Flag useint=0; /* 1 if can use integer calculation */
211772ac97cdSTom Musta Flag isoddint=0; /* 1 if rhs is an integer and odd */
211872ac97cdSTom Musta Int i; /* work */
211972ac97cdSTom Musta #if DECSUBSET
212072ac97cdSTom Musta Int dropped; /* .. */
212172ac97cdSTom Musta #endif
212272ac97cdSTom Musta uInt needbytes; /* buffer size needed */
212372ac97cdSTom Musta Flag seenbit; /* seen a bit while powering */
212472ac97cdSTom Musta Int residue=0; /* rounding residue */
212572ac97cdSTom Musta uInt status=0; /* accumulators */
212672ac97cdSTom Musta uByte bits=0; /* result sign if errors */
212772ac97cdSTom Musta decContext aset; /* working context */
212872ac97cdSTom Musta decNumber dnOne; /* work value 1... */
212972ac97cdSTom Musta /* local accumulator buffer [a decNumber, with digits+elength+1 digits] */
213072ac97cdSTom Musta decNumber dacbuff[D2N(DECBUFFER+9)];
213172ac97cdSTom Musta decNumber *dac=dacbuff; /* -> result accumulator */
213272ac97cdSTom Musta /* same again for possible 1/lhs calculation */
213372ac97cdSTom Musta decNumber invbuff[D2N(DECBUFFER+9)];
213472ac97cdSTom Musta
213572ac97cdSTom Musta #if DECCHECK
213672ac97cdSTom Musta if (decCheckOperands(res, lhs, rhs, set)) return res;
213772ac97cdSTom Musta #endif
213872ac97cdSTom Musta
213972ac97cdSTom Musta do { /* protect allocated storage */
214072ac97cdSTom Musta #if DECSUBSET
214172ac97cdSTom Musta if (!set->extended) { /* reduce operands and set status, as needed */
214272ac97cdSTom Musta if (lhs->digits>reqdigits) {
214372ac97cdSTom Musta alloclhs=decRoundOperand(lhs, set, &status);
214472ac97cdSTom Musta if (alloclhs==NULL) break;
214572ac97cdSTom Musta lhs=alloclhs;
214672ac97cdSTom Musta }
214772ac97cdSTom Musta if (rhs->digits>reqdigits) {
214872ac97cdSTom Musta allocrhs=decRoundOperand(rhs, set, &status);
214972ac97cdSTom Musta if (allocrhs==NULL) break;
215072ac97cdSTom Musta rhs=allocrhs;
215172ac97cdSTom Musta }
215272ac97cdSTom Musta }
215372ac97cdSTom Musta #endif
215472ac97cdSTom Musta /* [following code does not require input rounding] */
215572ac97cdSTom Musta
215672ac97cdSTom Musta /* handle NaNs and rhs Infinity (lhs infinity is harder) */
215772ac97cdSTom Musta if (SPECIALARGS) {
215872ac97cdSTom Musta if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs)) { /* NaNs */
215972ac97cdSTom Musta decNaNs(res, lhs, rhs, set, &status);
216072ac97cdSTom Musta break;}
216172ac97cdSTom Musta if (decNumberIsInfinite(rhs)) { /* rhs Infinity */
216272ac97cdSTom Musta Flag rhsneg=rhs->bits&DECNEG; /* save rhs sign */
216372ac97cdSTom Musta if (decNumberIsNegative(lhs) /* lhs<0 */
216472ac97cdSTom Musta && !decNumberIsZero(lhs)) /* .. */
216572ac97cdSTom Musta status|=DEC_Invalid_operation;
216672ac97cdSTom Musta else { /* lhs >=0 */
216772ac97cdSTom Musta decNumberZero(&dnOne); /* set up 1 */
216872ac97cdSTom Musta dnOne.lsu[0]=1;
216972ac97cdSTom Musta decNumberCompare(dac, lhs, &dnOne, set); /* lhs ? 1 */
217072ac97cdSTom Musta decNumberZero(res); /* prepare for 0/1/Infinity */
217172ac97cdSTom Musta if (decNumberIsNegative(dac)) { /* lhs<1 */
217272ac97cdSTom Musta if (rhsneg) res->bits|=DECINF; /* +Infinity [else is +0] */
217372ac97cdSTom Musta }
217472ac97cdSTom Musta else if (dac->lsu[0]==0) { /* lhs=1 */
217572ac97cdSTom Musta /* 1**Infinity is inexact, so return fully-padded 1.0000 */
217672ac97cdSTom Musta Int shift=set->digits-1;
217772ac97cdSTom Musta *res->lsu=1; /* was 0, make int 1 */
217872ac97cdSTom Musta res->digits=decShiftToMost(res->lsu, 1, shift);
217972ac97cdSTom Musta res->exponent=-shift; /* make 1.0000... */
218072ac97cdSTom Musta status|=DEC_Inexact|DEC_Rounded; /* deemed inexact */
218172ac97cdSTom Musta }
218272ac97cdSTom Musta else { /* lhs>1 */
218372ac97cdSTom Musta if (!rhsneg) res->bits|=DECINF; /* +Infinity [else is +0] */
218472ac97cdSTom Musta }
218572ac97cdSTom Musta } /* lhs>=0 */
218672ac97cdSTom Musta break;}
218772ac97cdSTom Musta /* [lhs infinity drops through] */
218872ac97cdSTom Musta } /* specials */
218972ac97cdSTom Musta
219072ac97cdSTom Musta /* Original rhs may be an integer that fits and is in range */
219172ac97cdSTom Musta n=decGetInt(rhs);
219272ac97cdSTom Musta if (n!=BADINT) { /* it is an integer */
219372ac97cdSTom Musta rhsint=1; /* record the fact for 1**n */
219472ac97cdSTom Musta isoddint=(Flag)n&1; /* [works even if big] */
219572ac97cdSTom Musta if (n!=BIGEVEN && n!=BIGODD) /* can use integer path? */
219672ac97cdSTom Musta useint=1; /* looks good */
219772ac97cdSTom Musta }
219872ac97cdSTom Musta
219972ac97cdSTom Musta if (decNumberIsNegative(lhs) /* -x .. */
220072ac97cdSTom Musta && isoddint) bits=DECNEG; /* .. to an odd power */
220172ac97cdSTom Musta
220272ac97cdSTom Musta /* handle LHS infinity */
220372ac97cdSTom Musta if (decNumberIsInfinite(lhs)) { /* [NaNs already handled] */
220472ac97cdSTom Musta uByte rbits=rhs->bits; /* save */
220572ac97cdSTom Musta decNumberZero(res); /* prepare */
220672ac97cdSTom Musta if (n==0) *res->lsu=1; /* [-]Inf**0 => 1 */
220772ac97cdSTom Musta else {
220872ac97cdSTom Musta /* -Inf**nonint -> error */
220972ac97cdSTom Musta if (!rhsint && decNumberIsNegative(lhs)) {
221072ac97cdSTom Musta status|=DEC_Invalid_operation; /* -Inf**nonint is error */
221172ac97cdSTom Musta break;}
221272ac97cdSTom Musta if (!(rbits & DECNEG)) bits|=DECINF; /* was not a **-n */
221372ac97cdSTom Musta /* [otherwise will be 0 or -0] */
221472ac97cdSTom Musta res->bits=bits;
221572ac97cdSTom Musta }
221672ac97cdSTom Musta break;}
221772ac97cdSTom Musta
221872ac97cdSTom Musta /* similarly handle LHS zero */
221972ac97cdSTom Musta if (decNumberIsZero(lhs)) {
222072ac97cdSTom Musta if (n==0) { /* 0**0 => Error */
222172ac97cdSTom Musta #if DECSUBSET
222272ac97cdSTom Musta if (!set->extended) { /* [unless subset] */
222372ac97cdSTom Musta decNumberZero(res);
222472ac97cdSTom Musta *res->lsu=1; /* return 1 */
222572ac97cdSTom Musta break;}
222672ac97cdSTom Musta #endif
222772ac97cdSTom Musta status|=DEC_Invalid_operation;
222872ac97cdSTom Musta }
222972ac97cdSTom Musta else { /* 0**x */
223072ac97cdSTom Musta uByte rbits=rhs->bits; /* save */
223172ac97cdSTom Musta if (rbits & DECNEG) { /* was a 0**(-n) */
223272ac97cdSTom Musta #if DECSUBSET
223372ac97cdSTom Musta if (!set->extended) { /* [bad if subset] */
223472ac97cdSTom Musta status|=DEC_Invalid_operation;
223572ac97cdSTom Musta break;}
223672ac97cdSTom Musta #endif
223772ac97cdSTom Musta bits|=DECINF;
223872ac97cdSTom Musta }
223972ac97cdSTom Musta decNumberZero(res); /* prepare */
224072ac97cdSTom Musta /* [otherwise will be 0 or -0] */
224172ac97cdSTom Musta res->bits=bits;
224272ac97cdSTom Musta }
224372ac97cdSTom Musta break;}
224472ac97cdSTom Musta
224572ac97cdSTom Musta /* here both lhs and rhs are finite; rhs==0 is handled in the */
224672ac97cdSTom Musta /* integer path. Next handle the non-integer cases */
224772ac97cdSTom Musta if (!useint) { /* non-integral rhs */
224872ac97cdSTom Musta /* any -ve lhs is bad, as is either operand or context out of */
224972ac97cdSTom Musta /* bounds */
225072ac97cdSTom Musta if (decNumberIsNegative(lhs)) {
225172ac97cdSTom Musta status|=DEC_Invalid_operation;
225272ac97cdSTom Musta break;}
225372ac97cdSTom Musta if (decCheckMath(lhs, set, &status)
225472ac97cdSTom Musta || decCheckMath(rhs, set, &status)) break; /* variable status */
225572ac97cdSTom Musta
225672ac97cdSTom Musta decContextDefault(&aset, DEC_INIT_DECIMAL64); /* clean context */
225772ac97cdSTom Musta aset.emax=DEC_MAX_MATH; /* usual bounds */
225872ac97cdSTom Musta aset.emin=-DEC_MAX_MATH; /* .. */
225972ac97cdSTom Musta aset.clamp=0; /* and no concrete format */
226072ac97cdSTom Musta
226172ac97cdSTom Musta /* calculate the result using exp(ln(lhs)*rhs), which can */
226272ac97cdSTom Musta /* all be done into the accumulator, dac. The precision needed */
226372ac97cdSTom Musta /* is enough to contain the full information in the lhs (which */
226472ac97cdSTom Musta /* is the total digits, including exponent), or the requested */
226572ac97cdSTom Musta /* precision, if larger, + 4; 6 is used for the exponent */
226672ac97cdSTom Musta /* maximum length, and this is also used when it is shorter */
226772ac97cdSTom Musta /* than the requested digits as it greatly reduces the >0.5 ulp */
226872ac97cdSTom Musta /* cases at little cost (because Ln doubles digits each */
226972ac97cdSTom Musta /* iteration so a few extra digits rarely causes an extra */
227072ac97cdSTom Musta /* iteration) */
227172ac97cdSTom Musta aset.digits=MAXI(lhs->digits, set->digits)+6+4;
227272ac97cdSTom Musta } /* non-integer rhs */
227372ac97cdSTom Musta
227472ac97cdSTom Musta else { /* rhs is in-range integer */
227572ac97cdSTom Musta if (n==0) { /* x**0 = 1 */
227672ac97cdSTom Musta /* (0**0 was handled above) */
227772ac97cdSTom Musta decNumberZero(res); /* result=1 */
227872ac97cdSTom Musta *res->lsu=1; /* .. */
227972ac97cdSTom Musta break;}
228072ac97cdSTom Musta /* rhs is a non-zero integer */
228172ac97cdSTom Musta if (n<0) n=-n; /* use abs(n) */
228272ac97cdSTom Musta
228372ac97cdSTom Musta aset=*set; /* clone the context */
228472ac97cdSTom Musta aset.round=DEC_ROUND_HALF_EVEN; /* internally use balanced */
228572ac97cdSTom Musta /* calculate the working DIGITS */
228672ac97cdSTom Musta aset.digits=reqdigits+(rhs->digits+rhs->exponent)+2;
228772ac97cdSTom Musta #if DECSUBSET
228872ac97cdSTom Musta if (!set->extended) aset.digits--; /* use classic precision */
228972ac97cdSTom Musta #endif
229072ac97cdSTom Musta /* it's an error if this is more than can be handled */
229172ac97cdSTom Musta if (aset.digits>DECNUMMAXP) {status|=DEC_Invalid_operation; break;}
229272ac97cdSTom Musta } /* integer path */
229372ac97cdSTom Musta
229472ac97cdSTom Musta /* aset.digits is the count of digits for the accumulator needed */
229572ac97cdSTom Musta /* if accumulator is too long for local storage, then allocate */
229672ac97cdSTom Musta needbytes=sizeof(decNumber)+(D2U(aset.digits)-1)*sizeof(Unit);
229772ac97cdSTom Musta /* [needbytes also used below if 1/lhs needed] */
229872ac97cdSTom Musta if (needbytes>sizeof(dacbuff)) {
229972ac97cdSTom Musta allocdac=(decNumber *)malloc(needbytes);
230072ac97cdSTom Musta if (allocdac==NULL) { /* hopeless -- abandon */
230172ac97cdSTom Musta status|=DEC_Insufficient_storage;
230272ac97cdSTom Musta break;}
230372ac97cdSTom Musta dac=allocdac; /* use the allocated space */
230472ac97cdSTom Musta }
230572ac97cdSTom Musta /* here, aset is set up and accumulator is ready for use */
230672ac97cdSTom Musta
230772ac97cdSTom Musta if (!useint) { /* non-integral rhs */
230872ac97cdSTom Musta /* x ** y; special-case x=1 here as it will otherwise always */
230972ac97cdSTom Musta /* reduce to integer 1; decLnOp has a fastpath which detects */
231072ac97cdSTom Musta /* the case of x=1 */
231172ac97cdSTom Musta decLnOp(dac, lhs, &aset, &status); /* dac=ln(lhs) */
231272ac97cdSTom Musta /* [no error possible, as lhs 0 already handled] */
231372ac97cdSTom Musta if (ISZERO(dac)) { /* x==1, 1.0, etc. */
231472ac97cdSTom Musta /* need to return fully-padded 1.0000 etc., but rhsint->1 */
231572ac97cdSTom Musta *dac->lsu=1; /* was 0, make int 1 */
231672ac97cdSTom Musta if (!rhsint) { /* add padding */
231772ac97cdSTom Musta Int shift=set->digits-1;
231872ac97cdSTom Musta dac->digits=decShiftToMost(dac->lsu, 1, shift);
231972ac97cdSTom Musta dac->exponent=-shift; /* make 1.0000... */
232072ac97cdSTom Musta status|=DEC_Inexact|DEC_Rounded; /* deemed inexact */
232172ac97cdSTom Musta }
232272ac97cdSTom Musta }
232372ac97cdSTom Musta else {
232472ac97cdSTom Musta decMultiplyOp(dac, dac, rhs, &aset, &status); /* dac=dac*rhs */
232572ac97cdSTom Musta decExpOp(dac, dac, &aset, &status); /* dac=exp(dac) */
232672ac97cdSTom Musta }
232772ac97cdSTom Musta /* and drop through for final rounding */
232872ac97cdSTom Musta } /* non-integer rhs */
232972ac97cdSTom Musta
233072ac97cdSTom Musta else { /* carry on with integer */
233172ac97cdSTom Musta decNumberZero(dac); /* acc=1 */
233272ac97cdSTom Musta *dac->lsu=1; /* .. */
233372ac97cdSTom Musta
233472ac97cdSTom Musta /* if a negative power the constant 1 is needed, and if not subset */
233572ac97cdSTom Musta /* invert the lhs now rather than inverting the result later */
233672ac97cdSTom Musta if (decNumberIsNegative(rhs)) { /* was a **-n [hence digits>0] */
233767cc32ebSVeres Lajos decNumber *inv=invbuff; /* assume use fixed buffer */
233872ac97cdSTom Musta decNumberCopy(&dnOne, dac); /* dnOne=1; [needed now or later] */
233972ac97cdSTom Musta #if DECSUBSET
234072ac97cdSTom Musta if (set->extended) { /* need to calculate 1/lhs */
234172ac97cdSTom Musta #endif
234272ac97cdSTom Musta /* divide lhs into 1, putting result in dac [dac=1/dac] */
234372ac97cdSTom Musta decDivideOp(dac, &dnOne, lhs, &aset, DIVIDE, &status);
234472ac97cdSTom Musta /* now locate or allocate space for the inverted lhs */
234572ac97cdSTom Musta if (needbytes>sizeof(invbuff)) {
234672ac97cdSTom Musta allocinv=(decNumber *)malloc(needbytes);
234772ac97cdSTom Musta if (allocinv==NULL) { /* hopeless -- abandon */
234872ac97cdSTom Musta status|=DEC_Insufficient_storage;
234972ac97cdSTom Musta break;}
235072ac97cdSTom Musta inv=allocinv; /* use the allocated space */
235172ac97cdSTom Musta }
235272ac97cdSTom Musta /* [inv now points to big-enough buffer or allocated storage] */
235372ac97cdSTom Musta decNumberCopy(inv, dac); /* copy the 1/lhs */
235472ac97cdSTom Musta decNumberCopy(dac, &dnOne); /* restore acc=1 */
235572ac97cdSTom Musta lhs=inv; /* .. and go forward with new lhs */
235672ac97cdSTom Musta #if DECSUBSET
235772ac97cdSTom Musta }
235872ac97cdSTom Musta #endif
235972ac97cdSTom Musta }
236072ac97cdSTom Musta
236172ac97cdSTom Musta /* Raise-to-the-power loop... */
236272ac97cdSTom Musta seenbit=0; /* set once a 1-bit is encountered */
236372ac97cdSTom Musta for (i=1;;i++){ /* for each bit [top bit ignored] */
236472ac97cdSTom Musta /* abandon if had overflow or terminal underflow */
236572ac97cdSTom Musta if (status & (DEC_Overflow|DEC_Underflow)) { /* interesting? */
236672ac97cdSTom Musta if (status&DEC_Overflow || ISZERO(dac)) break;
236772ac97cdSTom Musta }
236872ac97cdSTom Musta /* [the following two lines revealed an optimizer bug in a C++ */
236972ac97cdSTom Musta /* compiler, with symptom: 5**3 -> 25, when n=n+n was used] */
237072ac97cdSTom Musta n=n<<1; /* move next bit to testable position */
237172ac97cdSTom Musta if (n<0) { /* top bit is set */
237272ac97cdSTom Musta seenbit=1; /* OK, significant bit seen */
237372ac97cdSTom Musta decMultiplyOp(dac, dac, lhs, &aset, &status); /* dac=dac*x */
237472ac97cdSTom Musta }
237572ac97cdSTom Musta if (i==31) break; /* that was the last bit */
237672ac97cdSTom Musta if (!seenbit) continue; /* no need to square 1 */
237772ac97cdSTom Musta decMultiplyOp(dac, dac, dac, &aset, &status); /* dac=dac*dac [square] */
237872ac97cdSTom Musta } /*i*/ /* 32 bits */
237972ac97cdSTom Musta
238072ac97cdSTom Musta /* complete internal overflow or underflow processing */
238172ac97cdSTom Musta if (status & (DEC_Overflow|DEC_Underflow)) {
238272ac97cdSTom Musta #if DECSUBSET
238372ac97cdSTom Musta /* If subset, and power was negative, reverse the kind of -erflow */
238472ac97cdSTom Musta /* [1/x not yet done] */
238572ac97cdSTom Musta if (!set->extended && decNumberIsNegative(rhs)) {
238672ac97cdSTom Musta if (status & DEC_Overflow)
238772ac97cdSTom Musta status^=DEC_Overflow | DEC_Underflow | DEC_Subnormal;
238872ac97cdSTom Musta else { /* trickier -- Underflow may or may not be set */
238972ac97cdSTom Musta status&=~(DEC_Underflow | DEC_Subnormal); /* [one or both] */
239072ac97cdSTom Musta status|=DEC_Overflow;
239172ac97cdSTom Musta }
239272ac97cdSTom Musta }
239372ac97cdSTom Musta #endif
239472ac97cdSTom Musta dac->bits=(dac->bits & ~DECNEG) | bits; /* force correct sign */
239572ac97cdSTom Musta /* round subnormals [to set.digits rather than aset.digits] */
239672ac97cdSTom Musta /* or set overflow result similarly as required */
239772ac97cdSTom Musta decFinalize(dac, set, &residue, &status);
239872ac97cdSTom Musta decNumberCopy(res, dac); /* copy to result (is now OK length) */
239972ac97cdSTom Musta break;
240072ac97cdSTom Musta }
240172ac97cdSTom Musta
240272ac97cdSTom Musta #if DECSUBSET
240372ac97cdSTom Musta if (!set->extended && /* subset math */
240472ac97cdSTom Musta decNumberIsNegative(rhs)) { /* was a **-n [hence digits>0] */
240572ac97cdSTom Musta /* so divide result into 1 [dac=1/dac] */
240672ac97cdSTom Musta decDivideOp(dac, &dnOne, dac, &aset, DIVIDE, &status);
240772ac97cdSTom Musta }
240872ac97cdSTom Musta #endif
240972ac97cdSTom Musta } /* rhs integer path */
241072ac97cdSTom Musta
241172ac97cdSTom Musta /* reduce result to the requested length and copy to result */
241272ac97cdSTom Musta decCopyFit(res, dac, set, &residue, &status);
241372ac97cdSTom Musta decFinish(res, set, &residue, &status); /* final cleanup */
241472ac97cdSTom Musta #if DECSUBSET
241572ac97cdSTom Musta if (!set->extended) decTrim(res, set, 0, &dropped); /* trailing zeros */
241672ac97cdSTom Musta #endif
241772ac97cdSTom Musta } while(0); /* end protected */
241872ac97cdSTom Musta
241972ac97cdSTom Musta if (allocdac!=NULL) free(allocdac); /* drop any storage used */
242072ac97cdSTom Musta if (allocinv!=NULL) free(allocinv); /* .. */
242172ac97cdSTom Musta #if DECSUBSET
242272ac97cdSTom Musta if (alloclhs!=NULL) free(alloclhs); /* .. */
242372ac97cdSTom Musta if (allocrhs!=NULL) free(allocrhs); /* .. */
242472ac97cdSTom Musta #endif
242572ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
242672ac97cdSTom Musta #if DECCHECK
242772ac97cdSTom Musta decCheckInexact(res, set);
242872ac97cdSTom Musta #endif
242972ac97cdSTom Musta return res;
243072ac97cdSTom Musta } /* decNumberPower */
243172ac97cdSTom Musta
243272ac97cdSTom Musta /* ------------------------------------------------------------------ */
243372ac97cdSTom Musta /* decNumberQuantize -- force exponent to requested value */
243472ac97cdSTom Musta /* */
243572ac97cdSTom Musta /* This computes C = op(A, B), where op adjusts the coefficient */
243672ac97cdSTom Musta /* of C (by rounding or shifting) such that the exponent (-scale) */
243772ac97cdSTom Musta /* of C has exponent of B. The numerical value of C will equal A, */
243872ac97cdSTom Musta /* except for the effects of any rounding that occurred. */
243972ac97cdSTom Musta /* */
244072ac97cdSTom Musta /* res is C, the result. C may be A or B */
244172ac97cdSTom Musta /* lhs is A, the number to adjust */
244272ac97cdSTom Musta /* rhs is B, the number with exponent to match */
244372ac97cdSTom Musta /* set is the context */
244472ac97cdSTom Musta /* */
244572ac97cdSTom Musta /* C must have space for set->digits digits. */
244672ac97cdSTom Musta /* */
244772ac97cdSTom Musta /* Unless there is an error or the result is infinite, the exponent */
244872ac97cdSTom Musta /* after the operation is guaranteed to be equal to that of B. */
244972ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberQuantize(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)245072ac97cdSTom Musta decNumber * decNumberQuantize(decNumber *res, const decNumber *lhs,
245172ac97cdSTom Musta const decNumber *rhs, decContext *set) {
245272ac97cdSTom Musta uInt status=0; /* accumulator */
245372ac97cdSTom Musta decQuantizeOp(res, lhs, rhs, set, 1, &status);
245472ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
245572ac97cdSTom Musta return res;
245672ac97cdSTom Musta } /* decNumberQuantize */
245772ac97cdSTom Musta
245872ac97cdSTom Musta /* ------------------------------------------------------------------ */
245972ac97cdSTom Musta /* decNumberReduce -- remove trailing zeros */
246072ac97cdSTom Musta /* */
246172ac97cdSTom Musta /* This computes C = 0 + A, and normalizes the result */
246272ac97cdSTom Musta /* */
246372ac97cdSTom Musta /* res is C, the result. C may be A */
246472ac97cdSTom Musta /* rhs is A */
246572ac97cdSTom Musta /* set is the context */
246672ac97cdSTom Musta /* */
246772ac97cdSTom Musta /* C must have space for set->digits digits. */
246872ac97cdSTom Musta /* ------------------------------------------------------------------ */
246972ac97cdSTom Musta /* Previously known as Normalize */
decNumberNormalize(decNumber * res,const decNumber * rhs,decContext * set)247072ac97cdSTom Musta decNumber * decNumberNormalize(decNumber *res, const decNumber *rhs,
247172ac97cdSTom Musta decContext *set) {
247272ac97cdSTom Musta return decNumberReduce(res, rhs, set);
247372ac97cdSTom Musta } /* decNumberNormalize */
247472ac97cdSTom Musta
decNumberReduce(decNumber * res,const decNumber * rhs,decContext * set)247572ac97cdSTom Musta decNumber * decNumberReduce(decNumber *res, const decNumber *rhs,
247672ac97cdSTom Musta decContext *set) {
247772ac97cdSTom Musta #if DECSUBSET
247872ac97cdSTom Musta decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
247972ac97cdSTom Musta #endif
248072ac97cdSTom Musta uInt status=0; /* as usual */
248172ac97cdSTom Musta Int residue=0; /* as usual */
248272ac97cdSTom Musta Int dropped; /* work */
248372ac97cdSTom Musta
248472ac97cdSTom Musta #if DECCHECK
248572ac97cdSTom Musta if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
248672ac97cdSTom Musta #endif
248772ac97cdSTom Musta
248872ac97cdSTom Musta do { /* protect allocated storage */
248972ac97cdSTom Musta #if DECSUBSET
249072ac97cdSTom Musta if (!set->extended) {
249172ac97cdSTom Musta /* reduce operand and set lostDigits status, as needed */
249272ac97cdSTom Musta if (rhs->digits>set->digits) {
249372ac97cdSTom Musta allocrhs=decRoundOperand(rhs, set, &status);
249472ac97cdSTom Musta if (allocrhs==NULL) break;
249572ac97cdSTom Musta rhs=allocrhs;
249672ac97cdSTom Musta }
249772ac97cdSTom Musta }
249872ac97cdSTom Musta #endif
249972ac97cdSTom Musta /* [following code does not require input rounding] */
250072ac97cdSTom Musta
250172ac97cdSTom Musta /* Infinities copy through; NaNs need usual treatment */
250272ac97cdSTom Musta if (decNumberIsNaN(rhs)) {
250372ac97cdSTom Musta decNaNs(res, rhs, NULL, set, &status);
250472ac97cdSTom Musta break;
250572ac97cdSTom Musta }
250672ac97cdSTom Musta
250772ac97cdSTom Musta /* reduce result to the requested length and copy to result */
250872ac97cdSTom Musta decCopyFit(res, rhs, set, &residue, &status); /* copy & round */
250972ac97cdSTom Musta decFinish(res, set, &residue, &status); /* cleanup/set flags */
251072ac97cdSTom Musta decTrim(res, set, 1, &dropped); /* normalize in place */
251172ac97cdSTom Musta } while(0); /* end protected */
251272ac97cdSTom Musta
251372ac97cdSTom Musta #if DECSUBSET
251472ac97cdSTom Musta if (allocrhs !=NULL) free(allocrhs); /* .. */
251572ac97cdSTom Musta #endif
251672ac97cdSTom Musta if (status!=0) decStatus(res, status, set);/* then report status */
251772ac97cdSTom Musta return res;
251872ac97cdSTom Musta } /* decNumberReduce */
251972ac97cdSTom Musta
252072ac97cdSTom Musta /* ------------------------------------------------------------------ */
252172ac97cdSTom Musta /* decNumberRescale -- force exponent to requested value */
252272ac97cdSTom Musta /* */
252372ac97cdSTom Musta /* This computes C = op(A, B), where op adjusts the coefficient */
252472ac97cdSTom Musta /* of C (by rounding or shifting) such that the exponent (-scale) */
252572ac97cdSTom Musta /* of C has the value B. The numerical value of C will equal A, */
252672ac97cdSTom Musta /* except for the effects of any rounding that occurred. */
252772ac97cdSTom Musta /* */
252872ac97cdSTom Musta /* res is C, the result. C may be A or B */
252972ac97cdSTom Musta /* lhs is A, the number to adjust */
253072ac97cdSTom Musta /* rhs is B, the requested exponent */
253172ac97cdSTom Musta /* set is the context */
253272ac97cdSTom Musta /* */
253372ac97cdSTom Musta /* C must have space for set->digits digits. */
253472ac97cdSTom Musta /* */
253572ac97cdSTom Musta /* Unless there is an error or the result is infinite, the exponent */
253672ac97cdSTom Musta /* after the operation is guaranteed to be equal to B. */
253772ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberRescale(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)253872ac97cdSTom Musta decNumber * decNumberRescale(decNumber *res, const decNumber *lhs,
253972ac97cdSTom Musta const decNumber *rhs, decContext *set) {
254072ac97cdSTom Musta uInt status=0; /* accumulator */
254172ac97cdSTom Musta decQuantizeOp(res, lhs, rhs, set, 0, &status);
254272ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
254372ac97cdSTom Musta return res;
254472ac97cdSTom Musta } /* decNumberRescale */
254572ac97cdSTom Musta
254672ac97cdSTom Musta /* ------------------------------------------------------------------ */
254772ac97cdSTom Musta /* decNumberRemainder -- divide and return remainder */
254872ac97cdSTom Musta /* */
254972ac97cdSTom Musta /* This computes C = A % B */
255072ac97cdSTom Musta /* */
255172ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X%X) */
255272ac97cdSTom Musta /* lhs is A */
255372ac97cdSTom Musta /* rhs is B */
255472ac97cdSTom Musta /* set is the context */
255572ac97cdSTom Musta /* */
255672ac97cdSTom Musta /* C must have space for set->digits digits. */
255772ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberRemainder(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)255872ac97cdSTom Musta decNumber * decNumberRemainder(decNumber *res, const decNumber *lhs,
255972ac97cdSTom Musta const decNumber *rhs, decContext *set) {
256072ac97cdSTom Musta uInt status=0; /* accumulator */
256172ac97cdSTom Musta decDivideOp(res, lhs, rhs, set, REMAINDER, &status);
256272ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
256372ac97cdSTom Musta #if DECCHECK
256472ac97cdSTom Musta decCheckInexact(res, set);
256572ac97cdSTom Musta #endif
256672ac97cdSTom Musta return res;
256772ac97cdSTom Musta } /* decNumberRemainder */
256872ac97cdSTom Musta
256972ac97cdSTom Musta /* ------------------------------------------------------------------ */
257072ac97cdSTom Musta /* decNumberRemainderNear -- divide and return remainder from nearest */
257172ac97cdSTom Musta /* */
257272ac97cdSTom Musta /* This computes C = A % B, where % is the IEEE remainder operator */
257372ac97cdSTom Musta /* */
257472ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X%X) */
257572ac97cdSTom Musta /* lhs is A */
257672ac97cdSTom Musta /* rhs is B */
257772ac97cdSTom Musta /* set is the context */
257872ac97cdSTom Musta /* */
257972ac97cdSTom Musta /* C must have space for set->digits digits. */
258072ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberRemainderNear(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)258172ac97cdSTom Musta decNumber * decNumberRemainderNear(decNumber *res, const decNumber *lhs,
258272ac97cdSTom Musta const decNumber *rhs, decContext *set) {
258372ac97cdSTom Musta uInt status=0; /* accumulator */
258472ac97cdSTom Musta decDivideOp(res, lhs, rhs, set, REMNEAR, &status);
258572ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
258672ac97cdSTom Musta #if DECCHECK
258772ac97cdSTom Musta decCheckInexact(res, set);
258872ac97cdSTom Musta #endif
258972ac97cdSTom Musta return res;
259072ac97cdSTom Musta } /* decNumberRemainderNear */
259172ac97cdSTom Musta
259272ac97cdSTom Musta /* ------------------------------------------------------------------ */
259372ac97cdSTom Musta /* decNumberRotate -- rotate the coefficient of a Number left/right */
259472ac97cdSTom Musta /* */
259572ac97cdSTom Musta /* This computes C = A rot B (in base ten and rotating set->digits */
259672ac97cdSTom Musta /* digits). */
259772ac97cdSTom Musta /* */
259872ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=XrotX) */
259972ac97cdSTom Musta /* lhs is A */
260072ac97cdSTom Musta /* rhs is B, the number of digits to rotate (-ve to right) */
260172ac97cdSTom Musta /* set is the context */
260272ac97cdSTom Musta /* */
260372ac97cdSTom Musta /* The digits of the coefficient of A are rotated to the left (if B */
260472ac97cdSTom Musta /* is positive) or to the right (if B is negative) without adjusting */
260572ac97cdSTom Musta /* the exponent or the sign of A. If lhs->digits is less than */
260672ac97cdSTom Musta /* set->digits the coefficient is padded with zeros on the left */
260772ac97cdSTom Musta /* before the rotate. Any leading zeros in the result are removed */
260872ac97cdSTom Musta /* as usual. */
260972ac97cdSTom Musta /* */
261072ac97cdSTom Musta /* B must be an integer (q=0) and in the range -set->digits through */
261172ac97cdSTom Musta /* +set->digits. */
261272ac97cdSTom Musta /* C must have space for set->digits digits. */
261372ac97cdSTom Musta /* NaNs are propagated as usual. Infinities are unaffected (but */
261472ac97cdSTom Musta /* B must be valid). No status is set unless B is invalid or an */
261572ac97cdSTom Musta /* operand is an sNaN. */
261672ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberRotate(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)261772ac97cdSTom Musta decNumber * decNumberRotate(decNumber *res, const decNumber *lhs,
261872ac97cdSTom Musta const decNumber *rhs, decContext *set) {
261972ac97cdSTom Musta uInt status=0; /* accumulator */
262072ac97cdSTom Musta Int rotate; /* rhs as an Int */
262172ac97cdSTom Musta
262272ac97cdSTom Musta #if DECCHECK
262372ac97cdSTom Musta if (decCheckOperands(res, lhs, rhs, set)) return res;
262472ac97cdSTom Musta #endif
262572ac97cdSTom Musta
262672ac97cdSTom Musta /* NaNs propagate as normal */
262772ac97cdSTom Musta if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs))
262872ac97cdSTom Musta decNaNs(res, lhs, rhs, set, &status);
262972ac97cdSTom Musta /* rhs must be an integer */
263072ac97cdSTom Musta else if (decNumberIsInfinite(rhs) || rhs->exponent!=0)
263172ac97cdSTom Musta status=DEC_Invalid_operation;
263272ac97cdSTom Musta else { /* both numeric, rhs is an integer */
263372ac97cdSTom Musta rotate=decGetInt(rhs); /* [cannot fail] */
263472ac97cdSTom Musta if (rotate==BADINT /* something bad .. */
263572ac97cdSTom Musta || rotate==BIGODD || rotate==BIGEVEN /* .. very big .. */
263672ac97cdSTom Musta || abs(rotate)>set->digits) /* .. or out of range */
263772ac97cdSTom Musta status=DEC_Invalid_operation;
263872ac97cdSTom Musta else { /* rhs is OK */
263972ac97cdSTom Musta decNumberCopy(res, lhs);
264072ac97cdSTom Musta /* convert -ve rotate to equivalent positive rotation */
264172ac97cdSTom Musta if (rotate<0) rotate=set->digits+rotate;
264272ac97cdSTom Musta if (rotate!=0 && rotate!=set->digits /* zero or full rotation */
264372ac97cdSTom Musta && !decNumberIsInfinite(res)) { /* lhs was infinite */
264472ac97cdSTom Musta /* left-rotate to do; 0 < rotate < set->digits */
264572ac97cdSTom Musta uInt units, shift; /* work */
264672ac97cdSTom Musta uInt msudigits; /* digits in result msu */
264772ac97cdSTom Musta Unit *msu=res->lsu+D2U(res->digits)-1; /* current msu */
264872ac97cdSTom Musta Unit *msumax=res->lsu+D2U(set->digits)-1; /* rotation msu */
264972ac97cdSTom Musta for (msu++; msu<=msumax; msu++) *msu=0; /* ensure high units=0 */
265072ac97cdSTom Musta res->digits=set->digits; /* now full-length */
265172ac97cdSTom Musta msudigits=MSUDIGITS(res->digits); /* actual digits in msu */
265272ac97cdSTom Musta
265372ac97cdSTom Musta /* rotation here is done in-place, in three steps */
265472ac97cdSTom Musta /* 1. shift all to least up to one unit to unit-align final */
265572ac97cdSTom Musta /* lsd [any digits shifted out are rotated to the left, */
265672ac97cdSTom Musta /* abutted to the original msd (which may require split)] */
265772ac97cdSTom Musta /* */
265872ac97cdSTom Musta /* [if there are no whole units left to rotate, the */
265972ac97cdSTom Musta /* rotation is now complete] */
266072ac97cdSTom Musta /* */
266172ac97cdSTom Musta /* 2. shift to least, from below the split point only, so that */
266272ac97cdSTom Musta /* the final msd is in the right place in its Unit [any */
266372ac97cdSTom Musta /* digits shifted out will fit exactly in the current msu, */
266472ac97cdSTom Musta /* left aligned, no split required] */
266572ac97cdSTom Musta /* */
266672ac97cdSTom Musta /* 3. rotate all the units by reversing left part, right */
266772ac97cdSTom Musta /* part, and then whole */
266872ac97cdSTom Musta /* */
266972ac97cdSTom Musta /* example: rotate right 8 digits (2 units + 2), DECDPUN=3. */
267072ac97cdSTom Musta /* */
267172ac97cdSTom Musta /* start: 00a bcd efg hij klm npq */
267272ac97cdSTom Musta /* */
267372ac97cdSTom Musta /* 1a 000 0ab cde fgh|ijk lmn [pq saved] */
267472ac97cdSTom Musta /* 1b 00p qab cde fgh|ijk lmn */
267572ac97cdSTom Musta /* */
267672ac97cdSTom Musta /* 2a 00p qab cde fgh|00i jkl [mn saved] */
267772ac97cdSTom Musta /* 2b mnp qab cde fgh|00i jkl */
267872ac97cdSTom Musta /* */
267972ac97cdSTom Musta /* 3a fgh cde qab mnp|00i jkl */
268072ac97cdSTom Musta /* 3b fgh cde qab mnp|jkl 00i */
268172ac97cdSTom Musta /* 3c 00i jkl mnp qab cde fgh */
268272ac97cdSTom Musta
268372ac97cdSTom Musta /* Step 1: amount to shift is the partial right-rotate count */
268472ac97cdSTom Musta rotate=set->digits-rotate; /* make it right-rotate */
268572ac97cdSTom Musta units=rotate/DECDPUN; /* whole units to rotate */
268672ac97cdSTom Musta shift=rotate%DECDPUN; /* left-over digits count */
268772ac97cdSTom Musta if (shift>0) { /* not an exact number of units */
268872ac97cdSTom Musta uInt save=res->lsu[0]%powers[shift]; /* save low digit(s) */
268972ac97cdSTom Musta decShiftToLeast(res->lsu, D2U(res->digits), shift);
269072ac97cdSTom Musta if (shift>msudigits) { /* msumax-1 needs >0 digits */
269172ac97cdSTom Musta uInt rem=save%powers[shift-msudigits];/* split save */
269272ac97cdSTom Musta *msumax=(Unit)(save/powers[shift-msudigits]); /* and insert */
269372ac97cdSTom Musta *(msumax-1)=*(msumax-1)
269472ac97cdSTom Musta +(Unit)(rem*powers[DECDPUN-(shift-msudigits)]); /* .. */
269572ac97cdSTom Musta }
269672ac97cdSTom Musta else { /* all fits in msumax */
269772ac97cdSTom Musta *msumax=*msumax+(Unit)(save*powers[msudigits-shift]); /* [maybe *1] */
269872ac97cdSTom Musta }
269972ac97cdSTom Musta } /* digits shift needed */
270072ac97cdSTom Musta
270172ac97cdSTom Musta /* If whole units to rotate... */
270272ac97cdSTom Musta if (units>0) { /* some to do */
270372ac97cdSTom Musta /* Step 2: the units to touch are the whole ones in rotate, */
270472ac97cdSTom Musta /* if any, and the shift is DECDPUN-msudigits (which may be */
270572ac97cdSTom Musta /* 0, again) */
270672ac97cdSTom Musta shift=DECDPUN-msudigits;
270772ac97cdSTom Musta if (shift>0) { /* not an exact number of units */
270872ac97cdSTom Musta uInt save=res->lsu[0]%powers[shift]; /* save low digit(s) */
270972ac97cdSTom Musta decShiftToLeast(res->lsu, units, shift);
271072ac97cdSTom Musta *msumax=*msumax+(Unit)(save*powers[msudigits]);
271172ac97cdSTom Musta } /* partial shift needed */
271272ac97cdSTom Musta
271372ac97cdSTom Musta /* Step 3: rotate the units array using triple reverse */
271472ac97cdSTom Musta /* (reversing is easy and fast) */
271572ac97cdSTom Musta decReverse(res->lsu+units, msumax); /* left part */
271672ac97cdSTom Musta decReverse(res->lsu, res->lsu+units-1); /* right part */
271772ac97cdSTom Musta decReverse(res->lsu, msumax); /* whole */
271872ac97cdSTom Musta } /* whole units to rotate */
271972ac97cdSTom Musta /* the rotation may have left an undetermined number of zeros */
272072ac97cdSTom Musta /* on the left, so true length needs to be calculated */
272172ac97cdSTom Musta res->digits=decGetDigits(res->lsu, msumax-res->lsu+1);
272272ac97cdSTom Musta } /* rotate needed */
272372ac97cdSTom Musta } /* rhs OK */
272472ac97cdSTom Musta } /* numerics */
272572ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
272672ac97cdSTom Musta return res;
272772ac97cdSTom Musta } /* decNumberRotate */
272872ac97cdSTom Musta
272972ac97cdSTom Musta /* ------------------------------------------------------------------ */
273072ac97cdSTom Musta /* decNumberSameQuantum -- test for equal exponents */
273172ac97cdSTom Musta /* */
273272ac97cdSTom Musta /* res is the result number, which will contain either 0 or 1 */
273372ac97cdSTom Musta /* lhs is a number to test */
273472ac97cdSTom Musta /* rhs is the second (usually a pattern) */
273572ac97cdSTom Musta /* */
273672ac97cdSTom Musta /* No errors are possible and no context is needed. */
273772ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberSameQuantum(decNumber * res,const decNumber * lhs,const decNumber * rhs)273872ac97cdSTom Musta decNumber * decNumberSameQuantum(decNumber *res, const decNumber *lhs,
273972ac97cdSTom Musta const decNumber *rhs) {
274072ac97cdSTom Musta Unit ret=0; /* return value */
274172ac97cdSTom Musta
274272ac97cdSTom Musta #if DECCHECK
274372ac97cdSTom Musta if (decCheckOperands(res, lhs, rhs, DECUNCONT)) return res;
274472ac97cdSTom Musta #endif
274572ac97cdSTom Musta
274672ac97cdSTom Musta if (SPECIALARGS) {
274772ac97cdSTom Musta if (decNumberIsNaN(lhs) && decNumberIsNaN(rhs)) ret=1;
274872ac97cdSTom Musta else if (decNumberIsInfinite(lhs) && decNumberIsInfinite(rhs)) ret=1;
274972ac97cdSTom Musta /* [anything else with a special gives 0] */
275072ac97cdSTom Musta }
275172ac97cdSTom Musta else if (lhs->exponent==rhs->exponent) ret=1;
275272ac97cdSTom Musta
275372ac97cdSTom Musta decNumberZero(res); /* OK to overwrite an operand now */
275472ac97cdSTom Musta *res->lsu=ret;
275572ac97cdSTom Musta return res;
275672ac97cdSTom Musta } /* decNumberSameQuantum */
275772ac97cdSTom Musta
275872ac97cdSTom Musta /* ------------------------------------------------------------------ */
275972ac97cdSTom Musta /* decNumberScaleB -- multiply by a power of 10 */
276072ac97cdSTom Musta /* */
276172ac97cdSTom Musta /* This computes C = A x 10**B where B is an integer (q=0) with */
276272ac97cdSTom Musta /* maximum magnitude 2*(emax+digits) */
276372ac97cdSTom Musta /* */
276472ac97cdSTom Musta /* res is C, the result. C may be A or B */
276572ac97cdSTom Musta /* lhs is A, the number to adjust */
276672ac97cdSTom Musta /* rhs is B, the requested power of ten to use */
276772ac97cdSTom Musta /* set is the context */
276872ac97cdSTom Musta /* */
276972ac97cdSTom Musta /* C must have space for set->digits digits. */
277072ac97cdSTom Musta /* */
277172ac97cdSTom Musta /* The result may underflow or overflow. */
277272ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberScaleB(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)277372ac97cdSTom Musta decNumber * decNumberScaleB(decNumber *res, const decNumber *lhs,
277472ac97cdSTom Musta const decNumber *rhs, decContext *set) {
277572ac97cdSTom Musta Int reqexp; /* requested exponent change [B] */
277672ac97cdSTom Musta uInt status=0; /* accumulator */
277772ac97cdSTom Musta Int residue; /* work */
277872ac97cdSTom Musta
277972ac97cdSTom Musta #if DECCHECK
278072ac97cdSTom Musta if (decCheckOperands(res, lhs, rhs, set)) return res;
278172ac97cdSTom Musta #endif
278272ac97cdSTom Musta
278372ac97cdSTom Musta /* Handle special values except lhs infinite */
278472ac97cdSTom Musta if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs))
278572ac97cdSTom Musta decNaNs(res, lhs, rhs, set, &status);
278672ac97cdSTom Musta /* rhs must be an integer */
278772ac97cdSTom Musta else if (decNumberIsInfinite(rhs) || rhs->exponent!=0)
278872ac97cdSTom Musta status=DEC_Invalid_operation;
278972ac97cdSTom Musta else {
279072ac97cdSTom Musta /* lhs is a number; rhs is a finite with q==0 */
279172ac97cdSTom Musta reqexp=decGetInt(rhs); /* [cannot fail] */
279272ac97cdSTom Musta if (reqexp==BADINT /* something bad .. */
279372ac97cdSTom Musta || reqexp==BIGODD || reqexp==BIGEVEN /* .. very big .. */
279472ac97cdSTom Musta || abs(reqexp)>(2*(set->digits+set->emax))) /* .. or out of range */
279572ac97cdSTom Musta status=DEC_Invalid_operation;
279672ac97cdSTom Musta else { /* rhs is OK */
279772ac97cdSTom Musta decNumberCopy(res, lhs); /* all done if infinite lhs */
279872ac97cdSTom Musta if (!decNumberIsInfinite(res)) { /* prepare to scale */
279972ac97cdSTom Musta res->exponent+=reqexp; /* adjust the exponent */
280072ac97cdSTom Musta residue=0;
280172ac97cdSTom Musta decFinalize(res, set, &residue, &status); /* .. and check */
280272ac97cdSTom Musta } /* finite LHS */
280372ac97cdSTom Musta } /* rhs OK */
280472ac97cdSTom Musta } /* rhs finite */
280572ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
280672ac97cdSTom Musta return res;
280772ac97cdSTom Musta } /* decNumberScaleB */
280872ac97cdSTom Musta
280972ac97cdSTom Musta /* ------------------------------------------------------------------ */
281072ac97cdSTom Musta /* decNumberShift -- shift the coefficient of a Number left or right */
281172ac97cdSTom Musta /* */
281272ac97cdSTom Musta /* This computes C = A << B or C = A >> -B (in base ten). */
281372ac97cdSTom Musta /* */
281472ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X<<X) */
281572ac97cdSTom Musta /* lhs is A */
281672ac97cdSTom Musta /* rhs is B, the number of digits to shift (-ve to right) */
281772ac97cdSTom Musta /* set is the context */
281872ac97cdSTom Musta /* */
281972ac97cdSTom Musta /* The digits of the coefficient of A are shifted to the left (if B */
282072ac97cdSTom Musta /* is positive) or to the right (if B is negative) without adjusting */
282172ac97cdSTom Musta /* the exponent or the sign of A. */
282272ac97cdSTom Musta /* */
282372ac97cdSTom Musta /* B must be an integer (q=0) and in the range -set->digits through */
282472ac97cdSTom Musta /* +set->digits. */
282572ac97cdSTom Musta /* C must have space for set->digits digits. */
282672ac97cdSTom Musta /* NaNs are propagated as usual. Infinities are unaffected (but */
282772ac97cdSTom Musta /* B must be valid). No status is set unless B is invalid or an */
282872ac97cdSTom Musta /* operand is an sNaN. */
282972ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberShift(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)283072ac97cdSTom Musta decNumber * decNumberShift(decNumber *res, const decNumber *lhs,
283172ac97cdSTom Musta const decNumber *rhs, decContext *set) {
283272ac97cdSTom Musta uInt status=0; /* accumulator */
283372ac97cdSTom Musta Int shift; /* rhs as an Int */
283472ac97cdSTom Musta
283572ac97cdSTom Musta #if DECCHECK
283672ac97cdSTom Musta if (decCheckOperands(res, lhs, rhs, set)) return res;
283772ac97cdSTom Musta #endif
283872ac97cdSTom Musta
283972ac97cdSTom Musta /* NaNs propagate as normal */
284072ac97cdSTom Musta if (decNumberIsNaN(lhs) || decNumberIsNaN(rhs))
284172ac97cdSTom Musta decNaNs(res, lhs, rhs, set, &status);
284272ac97cdSTom Musta /* rhs must be an integer */
284372ac97cdSTom Musta else if (decNumberIsInfinite(rhs) || rhs->exponent!=0)
284472ac97cdSTom Musta status=DEC_Invalid_operation;
284572ac97cdSTom Musta else { /* both numeric, rhs is an integer */
284672ac97cdSTom Musta shift=decGetInt(rhs); /* [cannot fail] */
284772ac97cdSTom Musta if (shift==BADINT /* something bad .. */
284872ac97cdSTom Musta || shift==BIGODD || shift==BIGEVEN /* .. very big .. */
284972ac97cdSTom Musta || abs(shift)>set->digits) /* .. or out of range */
285072ac97cdSTom Musta status=DEC_Invalid_operation;
285172ac97cdSTom Musta else { /* rhs is OK */
285272ac97cdSTom Musta decNumberCopy(res, lhs);
285372ac97cdSTom Musta if (shift!=0 && !decNumberIsInfinite(res)) { /* something to do */
285472ac97cdSTom Musta if (shift>0) { /* to left */
285572ac97cdSTom Musta if (shift==set->digits) { /* removing all */
285672ac97cdSTom Musta *res->lsu=0; /* so place 0 */
285772ac97cdSTom Musta res->digits=1; /* .. */
285872ac97cdSTom Musta }
285972ac97cdSTom Musta else { /* */
286072ac97cdSTom Musta /* first remove leading digits if necessary */
286172ac97cdSTom Musta if (res->digits+shift>set->digits) {
286272ac97cdSTom Musta decDecap(res, res->digits+shift-set->digits);
286372ac97cdSTom Musta /* that updated res->digits; may have gone to 1 (for a */
286472ac97cdSTom Musta /* single digit or for zero */
286572ac97cdSTom Musta }
286672ac97cdSTom Musta if (res->digits>1 || *res->lsu) /* if non-zero.. */
286772ac97cdSTom Musta res->digits=decShiftToMost(res->lsu, res->digits, shift);
286872ac97cdSTom Musta } /* partial left */
286972ac97cdSTom Musta } /* left */
287072ac97cdSTom Musta else { /* to right */
287172ac97cdSTom Musta if (-shift>=res->digits) { /* discarding all */
287272ac97cdSTom Musta *res->lsu=0; /* so place 0 */
287372ac97cdSTom Musta res->digits=1; /* .. */
287472ac97cdSTom Musta }
287572ac97cdSTom Musta else {
287672ac97cdSTom Musta decShiftToLeast(res->lsu, D2U(res->digits), -shift);
287772ac97cdSTom Musta res->digits-=(-shift);
287872ac97cdSTom Musta }
287972ac97cdSTom Musta } /* to right */
288072ac97cdSTom Musta } /* non-0 non-Inf shift */
288172ac97cdSTom Musta } /* rhs OK */
288272ac97cdSTom Musta } /* numerics */
288372ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
288472ac97cdSTom Musta return res;
288572ac97cdSTom Musta } /* decNumberShift */
288672ac97cdSTom Musta
288772ac97cdSTom Musta /* ------------------------------------------------------------------ */
288872ac97cdSTom Musta /* decNumberSquareRoot -- square root operator */
288972ac97cdSTom Musta /* */
289072ac97cdSTom Musta /* This computes C = squareroot(A) */
289172ac97cdSTom Musta /* */
289272ac97cdSTom Musta /* res is C, the result. C may be A */
289372ac97cdSTom Musta /* rhs is A */
289472ac97cdSTom Musta /* set is the context; note that rounding mode has no effect */
289572ac97cdSTom Musta /* */
289672ac97cdSTom Musta /* C must have space for set->digits digits. */
289772ac97cdSTom Musta /* ------------------------------------------------------------------ */
289872ac97cdSTom Musta /* This uses the following varying-precision algorithm in: */
289972ac97cdSTom Musta /* */
290072ac97cdSTom Musta /* Properly Rounded Variable Precision Square Root, T. E. Hull and */
290172ac97cdSTom Musta /* A. Abrham, ACM Transactions on Mathematical Software, Vol 11 #3, */
290272ac97cdSTom Musta /* pp229-237, ACM, September 1985. */
290372ac97cdSTom Musta /* */
290472ac97cdSTom Musta /* The square-root is calculated using Newton's method, after which */
290572ac97cdSTom Musta /* a check is made to ensure the result is correctly rounded. */
290672ac97cdSTom Musta /* */
290772ac97cdSTom Musta /* % [Reformatted original Numerical Turing source code follows.] */
290872ac97cdSTom Musta /* function sqrt(x : real) : real */
290972ac97cdSTom Musta /* % sqrt(x) returns the properly rounded approximation to the square */
291072ac97cdSTom Musta /* % root of x, in the precision of the calling environment, or it */
291172ac97cdSTom Musta /* % fails if x < 0. */
291272ac97cdSTom Musta /* % t e hull and a abrham, august, 1984 */
291372ac97cdSTom Musta /* if x <= 0 then */
291472ac97cdSTom Musta /* if x < 0 then */
291572ac97cdSTom Musta /* assert false */
291672ac97cdSTom Musta /* else */
291772ac97cdSTom Musta /* result 0 */
291872ac97cdSTom Musta /* end if */
291972ac97cdSTom Musta /* end if */
292072ac97cdSTom Musta /* var f := setexp(x, 0) % fraction part of x [0.1 <= x < 1] */
292172ac97cdSTom Musta /* var e := getexp(x) % exponent part of x */
292272ac97cdSTom Musta /* var approx : real */
292372ac97cdSTom Musta /* if e mod 2 = 0 then */
292472ac97cdSTom Musta /* approx := .259 + .819 * f % approx to root of f */
292572ac97cdSTom Musta /* else */
292672ac97cdSTom Musta /* f := f/l0 % adjustments */
292772ac97cdSTom Musta /* e := e + 1 % for odd */
292872ac97cdSTom Musta /* approx := .0819 + 2.59 * f % exponent */
292972ac97cdSTom Musta /* end if */
293072ac97cdSTom Musta /* */
293172ac97cdSTom Musta /* var p:= 3 */
293272ac97cdSTom Musta /* const maxp := currentprecision + 2 */
293372ac97cdSTom Musta /* loop */
293472ac97cdSTom Musta /* p := min(2*p - 2, maxp) % p = 4,6,10, . . . , maxp */
293572ac97cdSTom Musta /* precision p */
293672ac97cdSTom Musta /* approx := .5 * (approx + f/approx) */
293772ac97cdSTom Musta /* exit when p = maxp */
293872ac97cdSTom Musta /* end loop */
293972ac97cdSTom Musta /* */
294072ac97cdSTom Musta /* % approx is now within 1 ulp of the properly rounded square root */
294172ac97cdSTom Musta /* % of f; to ensure proper rounding, compare squares of (approx - */
294272ac97cdSTom Musta /* % l/2 ulp) and (approx + l/2 ulp) with f. */
294372ac97cdSTom Musta /* p := currentprecision */
294472ac97cdSTom Musta /* begin */
294572ac97cdSTom Musta /* precision p + 2 */
294672ac97cdSTom Musta /* const approxsubhalf := approx - setexp(.5, -p) */
294772ac97cdSTom Musta /* if mulru(approxsubhalf, approxsubhalf) > f then */
294872ac97cdSTom Musta /* approx := approx - setexp(.l, -p + 1) */
294972ac97cdSTom Musta /* else */
295072ac97cdSTom Musta /* const approxaddhalf := approx + setexp(.5, -p) */
295172ac97cdSTom Musta /* if mulrd(approxaddhalf, approxaddhalf) < f then */
295272ac97cdSTom Musta /* approx := approx + setexp(.l, -p + 1) */
295372ac97cdSTom Musta /* end if */
295472ac97cdSTom Musta /* end if */
295572ac97cdSTom Musta /* end */
295672ac97cdSTom Musta /* result setexp(approx, e div 2) % fix exponent */
295772ac97cdSTom Musta /* end sqrt */
295872ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberSquareRoot(decNumber * res,const decNumber * rhs,decContext * set)295972ac97cdSTom Musta decNumber * decNumberSquareRoot(decNumber *res, const decNumber *rhs,
296072ac97cdSTom Musta decContext *set) {
296172ac97cdSTom Musta decContext workset, approxset; /* work contexts */
296272ac97cdSTom Musta decNumber dzero; /* used for constant zero */
296372ac97cdSTom Musta Int maxp; /* largest working precision */
296472ac97cdSTom Musta Int workp; /* working precision */
296572ac97cdSTom Musta Int residue=0; /* rounding residue */
296672ac97cdSTom Musta uInt status=0, ignore=0; /* status accumulators */
296772ac97cdSTom Musta uInt rstatus; /* .. */
296872ac97cdSTom Musta Int exp; /* working exponent */
296972ac97cdSTom Musta Int ideal; /* ideal (preferred) exponent */
297072ac97cdSTom Musta Int needbytes; /* work */
297172ac97cdSTom Musta Int dropped; /* .. */
297272ac97cdSTom Musta
297372ac97cdSTom Musta #if DECSUBSET
297472ac97cdSTom Musta decNumber *allocrhs=NULL; /* non-NULL if rounded rhs allocated */
297572ac97cdSTom Musta #endif
297672ac97cdSTom Musta /* buffer for f [needs +1 in case DECBUFFER 0] */
297772ac97cdSTom Musta decNumber buff[D2N(DECBUFFER+1)];
297872ac97cdSTom Musta /* buffer for a [needs +2 to match likely maxp] */
297972ac97cdSTom Musta decNumber bufa[D2N(DECBUFFER+2)];
298072ac97cdSTom Musta /* buffer for temporary, b [must be same size as a] */
298172ac97cdSTom Musta decNumber bufb[D2N(DECBUFFER+2)];
298272ac97cdSTom Musta decNumber *allocbuff=NULL; /* -> allocated buff, iff allocated */
298372ac97cdSTom Musta decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
298472ac97cdSTom Musta decNumber *allocbufb=NULL; /* -> allocated bufb, iff allocated */
298572ac97cdSTom Musta decNumber *f=buff; /* reduced fraction */
298672ac97cdSTom Musta decNumber *a=bufa; /* approximation to result */
298772ac97cdSTom Musta decNumber *b=bufb; /* intermediate result */
298872ac97cdSTom Musta /* buffer for temporary variable, up to 3 digits */
298972ac97cdSTom Musta decNumber buft[D2N(3)];
299072ac97cdSTom Musta decNumber *t=buft; /* up-to-3-digit constant or work */
299172ac97cdSTom Musta
299272ac97cdSTom Musta #if DECCHECK
299372ac97cdSTom Musta if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
299472ac97cdSTom Musta #endif
299572ac97cdSTom Musta
299672ac97cdSTom Musta do { /* protect allocated storage */
299772ac97cdSTom Musta #if DECSUBSET
299872ac97cdSTom Musta if (!set->extended) {
299972ac97cdSTom Musta /* reduce operand and set lostDigits status, as needed */
300072ac97cdSTom Musta if (rhs->digits>set->digits) {
300172ac97cdSTom Musta allocrhs=decRoundOperand(rhs, set, &status);
300272ac97cdSTom Musta if (allocrhs==NULL) break;
300372ac97cdSTom Musta /* [Note: 'f' allocation below could reuse this buffer if */
300472ac97cdSTom Musta /* used, but as this is rare they are kept separate for clarity.] */
300572ac97cdSTom Musta rhs=allocrhs;
300672ac97cdSTom Musta }
300772ac97cdSTom Musta }
300872ac97cdSTom Musta #endif
300972ac97cdSTom Musta /* [following code does not require input rounding] */
301072ac97cdSTom Musta
301172ac97cdSTom Musta /* handle infinities and NaNs */
301272ac97cdSTom Musta if (SPECIALARG) {
301372ac97cdSTom Musta if (decNumberIsInfinite(rhs)) { /* an infinity */
301472ac97cdSTom Musta if (decNumberIsNegative(rhs)) status|=DEC_Invalid_operation;
301572ac97cdSTom Musta else decNumberCopy(res, rhs); /* +Infinity */
301672ac97cdSTom Musta }
301772ac97cdSTom Musta else decNaNs(res, rhs, NULL, set, &status); /* a NaN */
301872ac97cdSTom Musta break;
301972ac97cdSTom Musta }
302072ac97cdSTom Musta
302172ac97cdSTom Musta /* calculate the ideal (preferred) exponent [floor(exp/2)] */
302272ac97cdSTom Musta /* [We would like to write: ideal=rhs->exponent>>1, but this */
302372ac97cdSTom Musta /* generates a compiler warning. Generated code is the same.] */
302472ac97cdSTom Musta ideal=(rhs->exponent&~1)/2; /* target */
302572ac97cdSTom Musta
302672ac97cdSTom Musta /* handle zeros */
302772ac97cdSTom Musta if (ISZERO(rhs)) {
302872ac97cdSTom Musta decNumberCopy(res, rhs); /* could be 0 or -0 */
302972ac97cdSTom Musta res->exponent=ideal; /* use the ideal [safe] */
303072ac97cdSTom Musta /* use decFinish to clamp any out-of-range exponent, etc. */
303172ac97cdSTom Musta decFinish(res, set, &residue, &status);
303272ac97cdSTom Musta break;
303372ac97cdSTom Musta }
303472ac97cdSTom Musta
303572ac97cdSTom Musta /* any other -x is an oops */
303672ac97cdSTom Musta if (decNumberIsNegative(rhs)) {
303772ac97cdSTom Musta status|=DEC_Invalid_operation;
303872ac97cdSTom Musta break;
303972ac97cdSTom Musta }
304072ac97cdSTom Musta
304172ac97cdSTom Musta /* space is needed for three working variables */
304272ac97cdSTom Musta /* f -- the same precision as the RHS, reduced to 0.01->0.99... */
304372ac97cdSTom Musta /* a -- Hull's approximation -- precision, when assigned, is */
304472ac97cdSTom Musta /* currentprecision+1 or the input argument precision, */
304572ac97cdSTom Musta /* whichever is larger (+2 for use as temporary) */
304672ac97cdSTom Musta /* b -- intermediate temporary result (same size as a) */
304772ac97cdSTom Musta /* if any is too long for local storage, then allocate */
304872ac97cdSTom Musta workp=MAXI(set->digits+1, rhs->digits); /* actual rounding precision */
304972ac97cdSTom Musta maxp=workp+2; /* largest working precision */
305072ac97cdSTom Musta
305172ac97cdSTom Musta needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit);
305272ac97cdSTom Musta if (needbytes>(Int)sizeof(buff)) {
305372ac97cdSTom Musta allocbuff=(decNumber *)malloc(needbytes);
305472ac97cdSTom Musta if (allocbuff==NULL) { /* hopeless -- abandon */
305572ac97cdSTom Musta status|=DEC_Insufficient_storage;
305672ac97cdSTom Musta break;}
305772ac97cdSTom Musta f=allocbuff; /* use the allocated space */
305872ac97cdSTom Musta }
305972ac97cdSTom Musta /* a and b both need to be able to hold a maxp-length number */
306072ac97cdSTom Musta needbytes=sizeof(decNumber)+(D2U(maxp)-1)*sizeof(Unit);
306172ac97cdSTom Musta if (needbytes>(Int)sizeof(bufa)) { /* [same applies to b] */
306272ac97cdSTom Musta allocbufa=(decNumber *)malloc(needbytes);
306372ac97cdSTom Musta allocbufb=(decNumber *)malloc(needbytes);
306472ac97cdSTom Musta if (allocbufa==NULL || allocbufb==NULL) { /* hopeless */
306572ac97cdSTom Musta status|=DEC_Insufficient_storage;
306672ac97cdSTom Musta break;}
306772ac97cdSTom Musta a=allocbufa; /* use the allocated spaces */
306872ac97cdSTom Musta b=allocbufb; /* .. */
306972ac97cdSTom Musta }
307072ac97cdSTom Musta
307172ac97cdSTom Musta /* copy rhs -> f, save exponent, and reduce so 0.1 <= f < 1 */
307272ac97cdSTom Musta decNumberCopy(f, rhs);
307372ac97cdSTom Musta exp=f->exponent+f->digits; /* adjusted to Hull rules */
307472ac97cdSTom Musta f->exponent=-(f->digits); /* to range */
307572ac97cdSTom Musta
307672ac97cdSTom Musta /* set up working context */
307772ac97cdSTom Musta decContextDefault(&workset, DEC_INIT_DECIMAL64);
307872ac97cdSTom Musta
307972ac97cdSTom Musta /* [Until further notice, no error is possible and status bits */
308072ac97cdSTom Musta /* (Rounded, etc.) should be ignored, not accumulated.] */
308172ac97cdSTom Musta
308272ac97cdSTom Musta /* Calculate initial approximation, and allow for odd exponent */
308372ac97cdSTom Musta workset.digits=workp; /* p for initial calculation */
308472ac97cdSTom Musta t->bits=0; t->digits=3;
308572ac97cdSTom Musta a->bits=0; a->digits=3;
308672ac97cdSTom Musta if ((exp & 1)==0) { /* even exponent */
308772ac97cdSTom Musta /* Set t=0.259, a=0.819 */
308872ac97cdSTom Musta t->exponent=-3;
308972ac97cdSTom Musta a->exponent=-3;
309072ac97cdSTom Musta #if DECDPUN>=3
309172ac97cdSTom Musta t->lsu[0]=259;
309272ac97cdSTom Musta a->lsu[0]=819;
309372ac97cdSTom Musta #elif DECDPUN==2
309472ac97cdSTom Musta t->lsu[0]=59; t->lsu[1]=2;
309572ac97cdSTom Musta a->lsu[0]=19; a->lsu[1]=8;
309672ac97cdSTom Musta #else
309772ac97cdSTom Musta t->lsu[0]=9; t->lsu[1]=5; t->lsu[2]=2;
309872ac97cdSTom Musta a->lsu[0]=9; a->lsu[1]=1; a->lsu[2]=8;
309972ac97cdSTom Musta #endif
310072ac97cdSTom Musta }
310172ac97cdSTom Musta else { /* odd exponent */
310272ac97cdSTom Musta /* Set t=0.0819, a=2.59 */
310372ac97cdSTom Musta f->exponent--; /* f=f/10 */
310472ac97cdSTom Musta exp++; /* e=e+1 */
310572ac97cdSTom Musta t->exponent=-4;
310672ac97cdSTom Musta a->exponent=-2;
310772ac97cdSTom Musta #if DECDPUN>=3
310872ac97cdSTom Musta t->lsu[0]=819;
310972ac97cdSTom Musta a->lsu[0]=259;
311072ac97cdSTom Musta #elif DECDPUN==2
311172ac97cdSTom Musta t->lsu[0]=19; t->lsu[1]=8;
311272ac97cdSTom Musta a->lsu[0]=59; a->lsu[1]=2;
311372ac97cdSTom Musta #else
311472ac97cdSTom Musta t->lsu[0]=9; t->lsu[1]=1; t->lsu[2]=8;
311572ac97cdSTom Musta a->lsu[0]=9; a->lsu[1]=5; a->lsu[2]=2;
311672ac97cdSTom Musta #endif
311772ac97cdSTom Musta }
311872ac97cdSTom Musta decMultiplyOp(a, a, f, &workset, &ignore); /* a=a*f */
311972ac97cdSTom Musta decAddOp(a, a, t, &workset, 0, &ignore); /* ..+t */
312072ac97cdSTom Musta /* [a is now the initial approximation for sqrt(f), calculated with */
312172ac97cdSTom Musta /* currentprecision, which is also a's precision.] */
312272ac97cdSTom Musta
312372ac97cdSTom Musta /* the main calculation loop */
312472ac97cdSTom Musta decNumberZero(&dzero); /* make 0 */
312572ac97cdSTom Musta decNumberZero(t); /* set t = 0.5 */
312672ac97cdSTom Musta t->lsu[0]=5; /* .. */
312772ac97cdSTom Musta t->exponent=-1; /* .. */
312872ac97cdSTom Musta workset.digits=3; /* initial p */
312972ac97cdSTom Musta for (;;) {
313072ac97cdSTom Musta /* set p to min(2*p - 2, maxp) [hence 3; or: 4, 6, 10, ... , maxp] */
313172ac97cdSTom Musta workset.digits=workset.digits*2-2;
313272ac97cdSTom Musta if (workset.digits>maxp) workset.digits=maxp;
313372ac97cdSTom Musta /* a = 0.5 * (a + f/a) */
313472ac97cdSTom Musta /* [calculated at p then rounded to currentprecision] */
313572ac97cdSTom Musta decDivideOp(b, f, a, &workset, DIVIDE, &ignore); /* b=f/a */
313672ac97cdSTom Musta decAddOp(b, b, a, &workset, 0, &ignore); /* b=b+a */
313772ac97cdSTom Musta decMultiplyOp(a, b, t, &workset, &ignore); /* a=b*0.5 */
313872ac97cdSTom Musta if (a->digits==maxp) break; /* have required digits */
313972ac97cdSTom Musta } /* loop */
314072ac97cdSTom Musta
314172ac97cdSTom Musta /* Here, 0.1 <= a < 1 [Hull], and a has maxp digits */
314272ac97cdSTom Musta /* now reduce to length, etc.; this needs to be done with a */
314372ac97cdSTom Musta /* having the correct exponent so as to handle subnormals */
314472ac97cdSTom Musta /* correctly */
314572ac97cdSTom Musta approxset=*set; /* get emin, emax, etc. */
314672ac97cdSTom Musta approxset.round=DEC_ROUND_HALF_EVEN;
314772ac97cdSTom Musta a->exponent+=exp/2; /* set correct exponent */
314872ac97cdSTom Musta
314972ac97cdSTom Musta rstatus=0; /* clear status */
315072ac97cdSTom Musta residue=0; /* .. and accumulator */
315172ac97cdSTom Musta decCopyFit(a, a, &approxset, &residue, &rstatus); /* reduce (if needed) */
315272ac97cdSTom Musta decFinish(a, &approxset, &residue, &rstatus); /* clean and finalize */
315372ac97cdSTom Musta
315472ac97cdSTom Musta /* Overflow was possible if the input exponent was out-of-range, */
315572ac97cdSTom Musta /* in which case quit */
315672ac97cdSTom Musta if (rstatus&DEC_Overflow) {
315772ac97cdSTom Musta status=rstatus; /* use the status as-is */
315872ac97cdSTom Musta decNumberCopy(res, a); /* copy to result */
315972ac97cdSTom Musta break;
316072ac97cdSTom Musta }
316172ac97cdSTom Musta
316272ac97cdSTom Musta /* Preserve status except Inexact/Rounded */
316372ac97cdSTom Musta status|=(rstatus & ~(DEC_Rounded|DEC_Inexact));
316472ac97cdSTom Musta
316572ac97cdSTom Musta /* Carry out the Hull correction */
316672ac97cdSTom Musta a->exponent-=exp/2; /* back to 0.1->1 */
316772ac97cdSTom Musta
316872ac97cdSTom Musta /* a is now at final precision and within 1 ulp of the properly */
316972ac97cdSTom Musta /* rounded square root of f; to ensure proper rounding, compare */
317072ac97cdSTom Musta /* squares of (a - l/2 ulp) and (a + l/2 ulp) with f. */
317172ac97cdSTom Musta /* Here workset.digits=maxp and t=0.5, and a->digits determines */
317272ac97cdSTom Musta /* the ulp */
317372ac97cdSTom Musta workset.digits--; /* maxp-1 is OK now */
317472ac97cdSTom Musta t->exponent=-a->digits-1; /* make 0.5 ulp */
317572ac97cdSTom Musta decAddOp(b, a, t, &workset, DECNEG, &ignore); /* b = a - 0.5 ulp */
317672ac97cdSTom Musta workset.round=DEC_ROUND_UP;
317772ac97cdSTom Musta decMultiplyOp(b, b, b, &workset, &ignore); /* b = mulru(b, b) */
317872ac97cdSTom Musta decCompareOp(b, f, b, &workset, COMPARE, &ignore); /* b ? f, reversed */
317972ac97cdSTom Musta if (decNumberIsNegative(b)) { /* f < b [i.e., b > f] */
318072ac97cdSTom Musta /* this is the more common adjustment, though both are rare */
318172ac97cdSTom Musta t->exponent++; /* make 1.0 ulp */
318272ac97cdSTom Musta t->lsu[0]=1; /* .. */
318372ac97cdSTom Musta decAddOp(a, a, t, &workset, DECNEG, &ignore); /* a = a - 1 ulp */
318472ac97cdSTom Musta /* assign to approx [round to length] */
318572ac97cdSTom Musta approxset.emin-=exp/2; /* adjust to match a */
318672ac97cdSTom Musta approxset.emax-=exp/2;
318772ac97cdSTom Musta decAddOp(a, &dzero, a, &approxset, 0, &ignore);
318872ac97cdSTom Musta }
318972ac97cdSTom Musta else {
319072ac97cdSTom Musta decAddOp(b, a, t, &workset, 0, &ignore); /* b = a + 0.5 ulp */
319172ac97cdSTom Musta workset.round=DEC_ROUND_DOWN;
319272ac97cdSTom Musta decMultiplyOp(b, b, b, &workset, &ignore); /* b = mulrd(b, b) */
319372ac97cdSTom Musta decCompareOp(b, b, f, &workset, COMPARE, &ignore); /* b ? f */
319472ac97cdSTom Musta if (decNumberIsNegative(b)) { /* b < f */
319572ac97cdSTom Musta t->exponent++; /* make 1.0 ulp */
319672ac97cdSTom Musta t->lsu[0]=1; /* .. */
319772ac97cdSTom Musta decAddOp(a, a, t, &workset, 0, &ignore); /* a = a + 1 ulp */
319872ac97cdSTom Musta /* assign to approx [round to length] */
319972ac97cdSTom Musta approxset.emin-=exp/2; /* adjust to match a */
320072ac97cdSTom Musta approxset.emax-=exp/2;
320172ac97cdSTom Musta decAddOp(a, &dzero, a, &approxset, 0, &ignore);
320272ac97cdSTom Musta }
320372ac97cdSTom Musta }
320472ac97cdSTom Musta /* [no errors are possible in the above, and rounding/inexact during */
320572ac97cdSTom Musta /* estimation are irrelevant, so status was not accumulated] */
320672ac97cdSTom Musta
320772ac97cdSTom Musta /* Here, 0.1 <= a < 1 (still), so adjust back */
320872ac97cdSTom Musta a->exponent+=exp/2; /* set correct exponent */
320972ac97cdSTom Musta
321072ac97cdSTom Musta /* count droppable zeros [after any subnormal rounding] by */
321172ac97cdSTom Musta /* trimming a copy */
321272ac97cdSTom Musta decNumberCopy(b, a);
321372ac97cdSTom Musta decTrim(b, set, 1, &dropped); /* [drops trailing zeros] */
321472ac97cdSTom Musta
321572ac97cdSTom Musta /* Set Inexact and Rounded. The answer can only be exact if */
321672ac97cdSTom Musta /* it is short enough so that squaring it could fit in workp digits, */
321772ac97cdSTom Musta /* and it cannot have trailing zeros due to clamping, so these are */
321872ac97cdSTom Musta /* the only (relatively rare) conditions a careful check is needed */
321972ac97cdSTom Musta if (b->digits*2-1 > workp && !set->clamp) { /* cannot fit */
322072ac97cdSTom Musta status|=DEC_Inexact|DEC_Rounded;
322172ac97cdSTom Musta }
322272ac97cdSTom Musta else { /* could be exact/unrounded */
322372ac97cdSTom Musta uInt mstatus=0; /* local status */
322472ac97cdSTom Musta decMultiplyOp(b, b, b, &workset, &mstatus); /* try the multiply */
322572ac97cdSTom Musta if (mstatus&DEC_Overflow) { /* result just won't fit */
322672ac97cdSTom Musta status|=DEC_Inexact|DEC_Rounded;
322772ac97cdSTom Musta }
322872ac97cdSTom Musta else { /* plausible */
322972ac97cdSTom Musta decCompareOp(t, b, rhs, &workset, COMPARE, &mstatus); /* b ? rhs */
323072ac97cdSTom Musta if (!ISZERO(t)) status|=DEC_Inexact|DEC_Rounded; /* not equal */
323172ac97cdSTom Musta else { /* is Exact */
323272ac97cdSTom Musta /* here, dropped is the count of trailing zeros in 'a' */
323372ac97cdSTom Musta /* use closest exponent to ideal... */
323472ac97cdSTom Musta Int todrop=ideal-a->exponent; /* most that can be dropped */
323572ac97cdSTom Musta if (todrop<0) status|=DEC_Rounded; /* ideally would add 0s */
323672ac97cdSTom Musta else { /* unrounded */
323772ac97cdSTom Musta if (dropped<todrop) { /* clamp to those available */
323872ac97cdSTom Musta todrop=dropped;
323972ac97cdSTom Musta status|=DEC_Clamped;
324072ac97cdSTom Musta }
324172ac97cdSTom Musta if (todrop>0) { /* have some to drop */
324272ac97cdSTom Musta decShiftToLeast(a->lsu, D2U(a->digits), todrop);
324372ac97cdSTom Musta a->exponent+=todrop; /* maintain numerical value */
324472ac97cdSTom Musta a->digits-=todrop; /* new length */
324572ac97cdSTom Musta }
324672ac97cdSTom Musta }
324772ac97cdSTom Musta }
324872ac97cdSTom Musta }
324972ac97cdSTom Musta }
325072ac97cdSTom Musta
325172ac97cdSTom Musta /* double-check Underflow, as perhaps the result could not have */
325272ac97cdSTom Musta /* been subnormal (initial argument too big), or it is now Exact */
325372ac97cdSTom Musta if (status&DEC_Underflow) {
325472ac97cdSTom Musta Int ae=rhs->exponent+rhs->digits-1; /* adjusted exponent */
325572ac97cdSTom Musta /* check if truly subnormal */
325672ac97cdSTom Musta #if DECEXTFLAG /* DEC_Subnormal too */
325772ac97cdSTom Musta if (ae>=set->emin*2) status&=~(DEC_Subnormal|DEC_Underflow);
325872ac97cdSTom Musta #else
325972ac97cdSTom Musta if (ae>=set->emin*2) status&=~DEC_Underflow;
326072ac97cdSTom Musta #endif
326172ac97cdSTom Musta /* check if truly inexact */
326272ac97cdSTom Musta if (!(status&DEC_Inexact)) status&=~DEC_Underflow;
326372ac97cdSTom Musta }
326472ac97cdSTom Musta
326572ac97cdSTom Musta decNumberCopy(res, a); /* a is now the result */
326672ac97cdSTom Musta } while(0); /* end protected */
326772ac97cdSTom Musta
326872ac97cdSTom Musta if (allocbuff!=NULL) free(allocbuff); /* drop any storage used */
326972ac97cdSTom Musta if (allocbufa!=NULL) free(allocbufa); /* .. */
327072ac97cdSTom Musta if (allocbufb!=NULL) free(allocbufb); /* .. */
327172ac97cdSTom Musta #if DECSUBSET
327272ac97cdSTom Musta if (allocrhs !=NULL) free(allocrhs); /* .. */
327372ac97cdSTom Musta #endif
327472ac97cdSTom Musta if (status!=0) decStatus(res, status, set);/* then report status */
327572ac97cdSTom Musta #if DECCHECK
327672ac97cdSTom Musta decCheckInexact(res, set);
327772ac97cdSTom Musta #endif
327872ac97cdSTom Musta return res;
327972ac97cdSTom Musta } /* decNumberSquareRoot */
328072ac97cdSTom Musta
328172ac97cdSTom Musta /* ------------------------------------------------------------------ */
328272ac97cdSTom Musta /* decNumberSubtract -- subtract two Numbers */
328372ac97cdSTom Musta /* */
328472ac97cdSTom Musta /* This computes C = A - B */
328572ac97cdSTom Musta /* */
328672ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X-X) */
328772ac97cdSTom Musta /* lhs is A */
328872ac97cdSTom Musta /* rhs is B */
328972ac97cdSTom Musta /* set is the context */
329072ac97cdSTom Musta /* */
329172ac97cdSTom Musta /* C must have space for set->digits digits. */
329272ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberSubtract(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)329372ac97cdSTom Musta decNumber * decNumberSubtract(decNumber *res, const decNumber *lhs,
329472ac97cdSTom Musta const decNumber *rhs, decContext *set) {
329572ac97cdSTom Musta uInt status=0; /* accumulator */
329672ac97cdSTom Musta
329772ac97cdSTom Musta decAddOp(res, lhs, rhs, set, DECNEG, &status);
329872ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
329972ac97cdSTom Musta #if DECCHECK
330072ac97cdSTom Musta decCheckInexact(res, set);
330172ac97cdSTom Musta #endif
330272ac97cdSTom Musta return res;
330372ac97cdSTom Musta } /* decNumberSubtract */
330472ac97cdSTom Musta
330572ac97cdSTom Musta /* ------------------------------------------------------------------ */
330672ac97cdSTom Musta /* decNumberToIntegralExact -- round-to-integral-value with InExact */
330772ac97cdSTom Musta /* decNumberToIntegralValue -- round-to-integral-value */
330872ac97cdSTom Musta /* */
330972ac97cdSTom Musta /* res is the result */
331072ac97cdSTom Musta /* rhs is input number */
331172ac97cdSTom Musta /* set is the context */
331272ac97cdSTom Musta /* */
331372ac97cdSTom Musta /* res must have space for any value of rhs. */
331472ac97cdSTom Musta /* */
331572ac97cdSTom Musta /* This implements the IEEE special operators and therefore treats */
331672ac97cdSTom Musta /* special values as valid. For finite numbers it returns */
331772ac97cdSTom Musta /* rescale(rhs, 0) if rhs->exponent is <0. */
331872ac97cdSTom Musta /* Otherwise the result is rhs (so no error is possible, except for */
331972ac97cdSTom Musta /* sNaN). */
332072ac97cdSTom Musta /* */
332172ac97cdSTom Musta /* The context is used for rounding mode and status after sNaN, but */
332272ac97cdSTom Musta /* the digits setting is ignored. The Exact version will signal */
332372ac97cdSTom Musta /* Inexact if the result differs numerically from rhs; the other */
332472ac97cdSTom Musta /* never signals Inexact. */
332572ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberToIntegralExact(decNumber * res,const decNumber * rhs,decContext * set)332672ac97cdSTom Musta decNumber * decNumberToIntegralExact(decNumber *res, const decNumber *rhs,
332772ac97cdSTom Musta decContext *set) {
332872ac97cdSTom Musta decNumber dn;
332972ac97cdSTom Musta decContext workset; /* working context */
333072ac97cdSTom Musta uInt status=0; /* accumulator */
333172ac97cdSTom Musta
333272ac97cdSTom Musta #if DECCHECK
333372ac97cdSTom Musta if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
333472ac97cdSTom Musta #endif
333572ac97cdSTom Musta
333672ac97cdSTom Musta /* handle infinities and NaNs */
333772ac97cdSTom Musta if (SPECIALARG) {
333872ac97cdSTom Musta if (decNumberIsInfinite(rhs)) decNumberCopy(res, rhs); /* an Infinity */
333972ac97cdSTom Musta else decNaNs(res, rhs, NULL, set, &status); /* a NaN */
334072ac97cdSTom Musta }
334172ac97cdSTom Musta else { /* finite */
334272ac97cdSTom Musta /* have a finite number; no error possible (res must be big enough) */
334372ac97cdSTom Musta if (rhs->exponent>=0) return decNumberCopy(res, rhs);
334472ac97cdSTom Musta /* that was easy, but if negative exponent there is work to do... */
334572ac97cdSTom Musta workset=*set; /* clone rounding, etc. */
334672ac97cdSTom Musta workset.digits=rhs->digits; /* no length rounding */
334772ac97cdSTom Musta workset.traps=0; /* no traps */
334872ac97cdSTom Musta decNumberZero(&dn); /* make a number with exponent 0 */
334972ac97cdSTom Musta decNumberQuantize(res, rhs, &dn, &workset);
335072ac97cdSTom Musta status|=workset.status;
335172ac97cdSTom Musta }
335272ac97cdSTom Musta if (status!=0) decStatus(res, status, set);
335372ac97cdSTom Musta return res;
335472ac97cdSTom Musta } /* decNumberToIntegralExact */
335572ac97cdSTom Musta
decNumberToIntegralValue(decNumber * res,const decNumber * rhs,decContext * set)335672ac97cdSTom Musta decNumber * decNumberToIntegralValue(decNumber *res, const decNumber *rhs,
335772ac97cdSTom Musta decContext *set) {
335872ac97cdSTom Musta decContext workset=*set; /* working context */
335972ac97cdSTom Musta workset.traps=0; /* no traps */
336072ac97cdSTom Musta decNumberToIntegralExact(res, rhs, &workset);
336172ac97cdSTom Musta /* this never affects set, except for sNaNs; NaN will have been set */
336272ac97cdSTom Musta /* or propagated already, so no need to call decStatus */
336372ac97cdSTom Musta set->status|=workset.status&DEC_Invalid_operation;
336472ac97cdSTom Musta return res;
336572ac97cdSTom Musta } /* decNumberToIntegralValue */
336672ac97cdSTom Musta
336772ac97cdSTom Musta /* ------------------------------------------------------------------ */
336872ac97cdSTom Musta /* decNumberXor -- XOR two Numbers, digitwise */
336972ac97cdSTom Musta /* */
337072ac97cdSTom Musta /* This computes C = A ^ B */
337172ac97cdSTom Musta /* */
337272ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X^X) */
337372ac97cdSTom Musta /* lhs is A */
337472ac97cdSTom Musta /* rhs is B */
337572ac97cdSTom Musta /* set is the context (used for result length and error report) */
337672ac97cdSTom Musta /* */
337772ac97cdSTom Musta /* C must have space for set->digits digits. */
337872ac97cdSTom Musta /* */
337972ac97cdSTom Musta /* Logical function restrictions apply (see above); a NaN is */
338072ac97cdSTom Musta /* returned with Invalid_operation if a restriction is violated. */
338172ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberXor(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set)338272ac97cdSTom Musta decNumber * decNumberXor(decNumber *res, const decNumber *lhs,
338372ac97cdSTom Musta const decNumber *rhs, decContext *set) {
338472ac97cdSTom Musta const Unit *ua, *ub; /* -> operands */
338572ac97cdSTom Musta const Unit *msua, *msub; /* -> operand msus */
338672ac97cdSTom Musta Unit *uc, *msuc; /* -> result and its msu */
338772ac97cdSTom Musta Int msudigs; /* digits in res msu */
338872ac97cdSTom Musta #if DECCHECK
338972ac97cdSTom Musta if (decCheckOperands(res, lhs, rhs, set)) return res;
339072ac97cdSTom Musta #endif
339172ac97cdSTom Musta
339272ac97cdSTom Musta if (lhs->exponent!=0 || decNumberIsSpecial(lhs) || decNumberIsNegative(lhs)
339372ac97cdSTom Musta || rhs->exponent!=0 || decNumberIsSpecial(rhs) || decNumberIsNegative(rhs)) {
339472ac97cdSTom Musta decStatus(res, DEC_Invalid_operation, set);
339572ac97cdSTom Musta return res;
339672ac97cdSTom Musta }
339772ac97cdSTom Musta /* operands are valid */
339872ac97cdSTom Musta ua=lhs->lsu; /* bottom-up */
339972ac97cdSTom Musta ub=rhs->lsu; /* .. */
340072ac97cdSTom Musta uc=res->lsu; /* .. */
340172ac97cdSTom Musta msua=ua+D2U(lhs->digits)-1; /* -> msu of lhs */
340272ac97cdSTom Musta msub=ub+D2U(rhs->digits)-1; /* -> msu of rhs */
340372ac97cdSTom Musta msuc=uc+D2U(set->digits)-1; /* -> msu of result */
340472ac97cdSTom Musta msudigs=MSUDIGITS(set->digits); /* [faster than remainder] */
340572ac97cdSTom Musta for (; uc<=msuc; ua++, ub++, uc++) { /* Unit loop */
340672ac97cdSTom Musta Unit a, b; /* extract units */
340772ac97cdSTom Musta if (ua>msua) a=0;
340872ac97cdSTom Musta else a=*ua;
340972ac97cdSTom Musta if (ub>msub) b=0;
341072ac97cdSTom Musta else b=*ub;
341172ac97cdSTom Musta *uc=0; /* can now write back */
341272ac97cdSTom Musta if (a|b) { /* maybe 1 bits to examine */
341372ac97cdSTom Musta Int i, j;
341472ac97cdSTom Musta /* This loop could be unrolled and/or use BIN2BCD tables */
341572ac97cdSTom Musta for (i=0; i<DECDPUN; i++) {
341672ac97cdSTom Musta if ((a^b)&1) *uc=*uc+(Unit)powers[i]; /* effect XOR */
341772ac97cdSTom Musta j=a%10;
341872ac97cdSTom Musta a=a/10;
341972ac97cdSTom Musta j|=b%10;
342072ac97cdSTom Musta b=b/10;
342172ac97cdSTom Musta if (j>1) {
342272ac97cdSTom Musta decStatus(res, DEC_Invalid_operation, set);
342372ac97cdSTom Musta return res;
342472ac97cdSTom Musta }
342572ac97cdSTom Musta if (uc==msuc && i==msudigs-1) break; /* just did final digit */
342672ac97cdSTom Musta } /* each digit */
342772ac97cdSTom Musta } /* non-zero */
342872ac97cdSTom Musta } /* each unit */
342972ac97cdSTom Musta /* [here uc-1 is the msu of the result] */
343072ac97cdSTom Musta res->digits=decGetDigits(res->lsu, uc-res->lsu);
343172ac97cdSTom Musta res->exponent=0; /* integer */
343272ac97cdSTom Musta res->bits=0; /* sign=0 */
343372ac97cdSTom Musta return res; /* [no status to set] */
343472ac97cdSTom Musta } /* decNumberXor */
343572ac97cdSTom Musta
343672ac97cdSTom Musta
343772ac97cdSTom Musta /* ================================================================== */
343872ac97cdSTom Musta /* Utility routines */
343972ac97cdSTom Musta /* ================================================================== */
344072ac97cdSTom Musta
344172ac97cdSTom Musta /* ------------------------------------------------------------------ */
344272ac97cdSTom Musta /* decNumberClass -- return the decClass of a decNumber */
344372ac97cdSTom Musta /* dn -- the decNumber to test */
344472ac97cdSTom Musta /* set -- the context to use for Emin */
344572ac97cdSTom Musta /* returns the decClass enum */
344672ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberClass(const decNumber * dn,decContext * set)344772ac97cdSTom Musta enum decClass decNumberClass(const decNumber *dn, decContext *set) {
344872ac97cdSTom Musta if (decNumberIsSpecial(dn)) {
344972ac97cdSTom Musta if (decNumberIsQNaN(dn)) return DEC_CLASS_QNAN;
345072ac97cdSTom Musta if (decNumberIsSNaN(dn)) return DEC_CLASS_SNAN;
345172ac97cdSTom Musta /* must be an infinity */
345272ac97cdSTom Musta if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_INF;
345372ac97cdSTom Musta return DEC_CLASS_POS_INF;
345472ac97cdSTom Musta }
345572ac97cdSTom Musta /* is finite */
345672ac97cdSTom Musta if (decNumberIsNormal(dn, set)) { /* most common */
345772ac97cdSTom Musta if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_NORMAL;
345872ac97cdSTom Musta return DEC_CLASS_POS_NORMAL;
345972ac97cdSTom Musta }
346072ac97cdSTom Musta /* is subnormal or zero */
346172ac97cdSTom Musta if (decNumberIsZero(dn)) { /* most common */
346272ac97cdSTom Musta if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_ZERO;
346372ac97cdSTom Musta return DEC_CLASS_POS_ZERO;
346472ac97cdSTom Musta }
346572ac97cdSTom Musta if (decNumberIsNegative(dn)) return DEC_CLASS_NEG_SUBNORMAL;
346672ac97cdSTom Musta return DEC_CLASS_POS_SUBNORMAL;
346772ac97cdSTom Musta } /* decNumberClass */
346872ac97cdSTom Musta
346972ac97cdSTom Musta /* ------------------------------------------------------------------ */
347072ac97cdSTom Musta /* decNumberClassToString -- convert decClass to a string */
347172ac97cdSTom Musta /* */
347272ac97cdSTom Musta /* eclass is a valid decClass */
347372ac97cdSTom Musta /* returns a constant string describing the class (max 13+1 chars) */
347472ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberClassToString(enum decClass eclass)347572ac97cdSTom Musta const char *decNumberClassToString(enum decClass eclass) {
347672ac97cdSTom Musta if (eclass==DEC_CLASS_POS_NORMAL) return DEC_ClassString_PN;
347772ac97cdSTom Musta if (eclass==DEC_CLASS_NEG_NORMAL) return DEC_ClassString_NN;
347872ac97cdSTom Musta if (eclass==DEC_CLASS_POS_ZERO) return DEC_ClassString_PZ;
347972ac97cdSTom Musta if (eclass==DEC_CLASS_NEG_ZERO) return DEC_ClassString_NZ;
348072ac97cdSTom Musta if (eclass==DEC_CLASS_POS_SUBNORMAL) return DEC_ClassString_PS;
348172ac97cdSTom Musta if (eclass==DEC_CLASS_NEG_SUBNORMAL) return DEC_ClassString_NS;
348272ac97cdSTom Musta if (eclass==DEC_CLASS_POS_INF) return DEC_ClassString_PI;
348372ac97cdSTom Musta if (eclass==DEC_CLASS_NEG_INF) return DEC_ClassString_NI;
348472ac97cdSTom Musta if (eclass==DEC_CLASS_QNAN) return DEC_ClassString_QN;
348572ac97cdSTom Musta if (eclass==DEC_CLASS_SNAN) return DEC_ClassString_SN;
348672ac97cdSTom Musta return DEC_ClassString_UN; /* Unknown */
348772ac97cdSTom Musta } /* decNumberClassToString */
348872ac97cdSTom Musta
348972ac97cdSTom Musta /* ------------------------------------------------------------------ */
349072ac97cdSTom Musta /* decNumberCopy -- copy a number */
349172ac97cdSTom Musta /* */
349272ac97cdSTom Musta /* dest is the target decNumber */
349372ac97cdSTom Musta /* src is the source decNumber */
349472ac97cdSTom Musta /* returns dest */
349572ac97cdSTom Musta /* */
349672ac97cdSTom Musta /* (dest==src is allowed and is a no-op) */
349772ac97cdSTom Musta /* All fields are updated as required. This is a utility operation, */
349872ac97cdSTom Musta /* so special values are unchanged and no error is possible. */
349972ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberCopy(decNumber * dest,const decNumber * src)350072ac97cdSTom Musta decNumber * decNumberCopy(decNumber *dest, const decNumber *src) {
350172ac97cdSTom Musta
350272ac97cdSTom Musta #if DECCHECK
350372ac97cdSTom Musta if (src==NULL) return decNumberZero(dest);
350472ac97cdSTom Musta #endif
350572ac97cdSTom Musta
350672ac97cdSTom Musta if (dest==src) return dest; /* no copy required */
350772ac97cdSTom Musta
350872ac97cdSTom Musta /* Use explicit assignments here as structure assignment could copy */
350972ac97cdSTom Musta /* more than just the lsu (for small DECDPUN). This would not affect */
351072ac97cdSTom Musta /* the value of the results, but could disturb test harness spill */
351172ac97cdSTom Musta /* checking. */
351272ac97cdSTom Musta dest->bits=src->bits;
351372ac97cdSTom Musta dest->exponent=src->exponent;
351472ac97cdSTom Musta dest->digits=src->digits;
351572ac97cdSTom Musta dest->lsu[0]=src->lsu[0];
351672ac97cdSTom Musta if (src->digits>DECDPUN) { /* more Units to come */
351772ac97cdSTom Musta const Unit *smsup, *s; /* work */
351872ac97cdSTom Musta Unit *d; /* .. */
351972ac97cdSTom Musta /* memcpy for the remaining Units would be safe as they cannot */
352072ac97cdSTom Musta /* overlap. However, this explicit loop is faster in short cases. */
352172ac97cdSTom Musta d=dest->lsu+1; /* -> first destination */
352272ac97cdSTom Musta smsup=src->lsu+D2U(src->digits); /* -> source msu+1 */
352372ac97cdSTom Musta for (s=src->lsu+1; s<smsup; s++, d++) *d=*s;
352472ac97cdSTom Musta }
352572ac97cdSTom Musta return dest;
352672ac97cdSTom Musta } /* decNumberCopy */
352772ac97cdSTom Musta
352872ac97cdSTom Musta /* ------------------------------------------------------------------ */
352972ac97cdSTom Musta /* decNumberCopyAbs -- quiet absolute value operator */
353072ac97cdSTom Musta /* */
353172ac97cdSTom Musta /* This sets C = abs(A) */
353272ac97cdSTom Musta /* */
353372ac97cdSTom Musta /* res is C, the result. C may be A */
353472ac97cdSTom Musta /* rhs is A */
353572ac97cdSTom Musta /* */
353672ac97cdSTom Musta /* C must have space for set->digits digits. */
353772ac97cdSTom Musta /* No exception or error can occur; this is a quiet bitwise operation.*/
353872ac97cdSTom Musta /* See also decNumberAbs for a checking version of this. */
353972ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberCopyAbs(decNumber * res,const decNumber * rhs)354072ac97cdSTom Musta decNumber * decNumberCopyAbs(decNumber *res, const decNumber *rhs) {
354172ac97cdSTom Musta #if DECCHECK
354272ac97cdSTom Musta if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res;
354372ac97cdSTom Musta #endif
354472ac97cdSTom Musta decNumberCopy(res, rhs);
354572ac97cdSTom Musta res->bits&=~DECNEG; /* turn off sign */
354672ac97cdSTom Musta return res;
354772ac97cdSTom Musta } /* decNumberCopyAbs */
354872ac97cdSTom Musta
354972ac97cdSTom Musta /* ------------------------------------------------------------------ */
355072ac97cdSTom Musta /* decNumberCopyNegate -- quiet negate value operator */
355172ac97cdSTom Musta /* */
355272ac97cdSTom Musta /* This sets C = negate(A) */
355372ac97cdSTom Musta /* */
355472ac97cdSTom Musta /* res is C, the result. C may be A */
355572ac97cdSTom Musta /* rhs is A */
355672ac97cdSTom Musta /* */
355772ac97cdSTom Musta /* C must have space for set->digits digits. */
355872ac97cdSTom Musta /* No exception or error can occur; this is a quiet bitwise operation.*/
355972ac97cdSTom Musta /* See also decNumberMinus for a checking version of this. */
356072ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberCopyNegate(decNumber * res,const decNumber * rhs)356172ac97cdSTom Musta decNumber * decNumberCopyNegate(decNumber *res, const decNumber *rhs) {
356272ac97cdSTom Musta #if DECCHECK
356372ac97cdSTom Musta if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res;
356472ac97cdSTom Musta #endif
356572ac97cdSTom Musta decNumberCopy(res, rhs);
356672ac97cdSTom Musta res->bits^=DECNEG; /* invert the sign */
356772ac97cdSTom Musta return res;
356872ac97cdSTom Musta } /* decNumberCopyNegate */
356972ac97cdSTom Musta
357072ac97cdSTom Musta /* ------------------------------------------------------------------ */
357172ac97cdSTom Musta /* decNumberCopySign -- quiet copy and set sign operator */
357272ac97cdSTom Musta /* */
357372ac97cdSTom Musta /* This sets C = A with the sign of B */
357472ac97cdSTom Musta /* */
357572ac97cdSTom Musta /* res is C, the result. C may be A */
357672ac97cdSTom Musta /* lhs is A */
357772ac97cdSTom Musta /* rhs is B */
357872ac97cdSTom Musta /* */
357972ac97cdSTom Musta /* C must have space for set->digits digits. */
358072ac97cdSTom Musta /* No exception or error can occur; this is a quiet bitwise operation.*/
358172ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberCopySign(decNumber * res,const decNumber * lhs,const decNumber * rhs)358272ac97cdSTom Musta decNumber * decNumberCopySign(decNumber *res, const decNumber *lhs,
358372ac97cdSTom Musta const decNumber *rhs) {
358472ac97cdSTom Musta uByte sign; /* rhs sign */
358572ac97cdSTom Musta #if DECCHECK
358672ac97cdSTom Musta if (decCheckOperands(res, DECUNUSED, rhs, DECUNCONT)) return res;
358772ac97cdSTom Musta #endif
358872ac97cdSTom Musta sign=rhs->bits & DECNEG; /* save sign bit */
358972ac97cdSTom Musta decNumberCopy(res, lhs);
359072ac97cdSTom Musta res->bits&=~DECNEG; /* clear the sign */
359172ac97cdSTom Musta res->bits|=sign; /* set from rhs */
359272ac97cdSTom Musta return res;
359372ac97cdSTom Musta } /* decNumberCopySign */
359472ac97cdSTom Musta
359572ac97cdSTom Musta /* ------------------------------------------------------------------ */
359672ac97cdSTom Musta /* decNumberGetBCD -- get the coefficient in BCD8 */
359772ac97cdSTom Musta /* dn is the source decNumber */
359872ac97cdSTom Musta /* bcd is the uInt array that will receive dn->digits BCD bytes, */
359972ac97cdSTom Musta /* most-significant at offset 0 */
360072ac97cdSTom Musta /* returns bcd */
360172ac97cdSTom Musta /* */
360272ac97cdSTom Musta /* bcd must have at least dn->digits bytes. No error is possible; if */
360372ac97cdSTom Musta /* dn is a NaN or Infinite, digits must be 1 and the coefficient 0. */
360472ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberGetBCD(const decNumber * dn,uint8_t * bcd)360572ac97cdSTom Musta uByte * decNumberGetBCD(const decNumber *dn, uint8_t *bcd) {
360672ac97cdSTom Musta uByte *ub=bcd+dn->digits-1; /* -> lsd */
360772ac97cdSTom Musta const Unit *up=dn->lsu; /* Unit pointer, -> lsu */
360872ac97cdSTom Musta
360972ac97cdSTom Musta #if DECDPUN==1 /* trivial simple copy */
361072ac97cdSTom Musta for (; ub>=bcd; ub--, up++) *ub=*up;
361172ac97cdSTom Musta #else /* chopping needed */
361272ac97cdSTom Musta uInt u=*up; /* work */
361372ac97cdSTom Musta uInt cut=DECDPUN; /* downcounter through unit */
361472ac97cdSTom Musta for (; ub>=bcd; ub--) {
361572ac97cdSTom Musta *ub=(uByte)(u%10); /* [*6554 trick inhibits, here] */
361672ac97cdSTom Musta u=u/10;
361772ac97cdSTom Musta cut--;
361872ac97cdSTom Musta if (cut>0) continue; /* more in this unit */
361972ac97cdSTom Musta up++;
362072ac97cdSTom Musta u=*up;
362172ac97cdSTom Musta cut=DECDPUN;
362272ac97cdSTom Musta }
362372ac97cdSTom Musta #endif
362472ac97cdSTom Musta return bcd;
362572ac97cdSTom Musta } /* decNumberGetBCD */
362672ac97cdSTom Musta
362772ac97cdSTom Musta /* ------------------------------------------------------------------ */
362872ac97cdSTom Musta /* decNumberSetBCD -- set (replace) the coefficient from BCD8 */
362972ac97cdSTom Musta /* dn is the target decNumber */
363072ac97cdSTom Musta /* bcd is the uInt array that will source n BCD bytes, most- */
363172ac97cdSTom Musta /* significant at offset 0 */
363272ac97cdSTom Musta /* n is the number of digits in the source BCD array (bcd) */
363372ac97cdSTom Musta /* returns dn */
363472ac97cdSTom Musta /* */
363572ac97cdSTom Musta /* dn must have space for at least n digits. No error is possible; */
363672ac97cdSTom Musta /* if dn is a NaN, or Infinite, or is to become a zero, n must be 1 */
363772ac97cdSTom Musta /* and bcd[0] zero. */
363872ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberSetBCD(decNumber * dn,const uByte * bcd,uInt n)363972ac97cdSTom Musta decNumber * decNumberSetBCD(decNumber *dn, const uByte *bcd, uInt n) {
36400a322e7eSTom Musta Unit *up = dn->lsu + D2U(n) - 1; /* -> msu [target pointer] */
364172ac97cdSTom Musta const uByte *ub=bcd; /* -> source msd */
364272ac97cdSTom Musta
364372ac97cdSTom Musta #if DECDPUN==1 /* trivial simple copy */
364472ac97cdSTom Musta for (; ub<bcd+n; ub++, up--) *up=*ub;
364572ac97cdSTom Musta #else /* some assembly needed */
364672ac97cdSTom Musta /* calculate how many digits in msu, and hence first cut */
364772ac97cdSTom Musta Int cut=MSUDIGITS(n); /* [faster than remainder] */
364872ac97cdSTom Musta for (;up>=dn->lsu; up--) { /* each Unit from msu */
364972ac97cdSTom Musta *up=0; /* will take <=DECDPUN digits */
365072ac97cdSTom Musta for (; cut>0; ub++, cut--) *up=X10(*up)+*ub;
365172ac97cdSTom Musta cut=DECDPUN; /* next Unit has all digits */
365272ac97cdSTom Musta }
365372ac97cdSTom Musta #endif
365472ac97cdSTom Musta dn->digits=n; /* set digit count */
365572ac97cdSTom Musta return dn;
365672ac97cdSTom Musta } /* decNumberSetBCD */
365772ac97cdSTom Musta
365872ac97cdSTom Musta /* ------------------------------------------------------------------ */
365972ac97cdSTom Musta /* decNumberIsNormal -- test normality of a decNumber */
366072ac97cdSTom Musta /* dn is the decNumber to test */
366172ac97cdSTom Musta /* set is the context to use for Emin */
366272ac97cdSTom Musta /* returns 1 if |dn| is finite and >=Nmin, 0 otherwise */
366372ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberIsNormal(const decNumber * dn,decContext * set)366472ac97cdSTom Musta Int decNumberIsNormal(const decNumber *dn, decContext *set) {
366572ac97cdSTom Musta Int ae; /* adjusted exponent */
366672ac97cdSTom Musta #if DECCHECK
366772ac97cdSTom Musta if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
366872ac97cdSTom Musta #endif
366972ac97cdSTom Musta
367072ac97cdSTom Musta if (decNumberIsSpecial(dn)) return 0; /* not finite */
367172ac97cdSTom Musta if (decNumberIsZero(dn)) return 0; /* not non-zero */
367272ac97cdSTom Musta
367372ac97cdSTom Musta ae=dn->exponent+dn->digits-1; /* adjusted exponent */
367472ac97cdSTom Musta if (ae<set->emin) return 0; /* is subnormal */
367572ac97cdSTom Musta return 1;
367672ac97cdSTom Musta } /* decNumberIsNormal */
367772ac97cdSTom Musta
367872ac97cdSTom Musta /* ------------------------------------------------------------------ */
367972ac97cdSTom Musta /* decNumberIsSubnormal -- test subnormality of a decNumber */
368072ac97cdSTom Musta /* dn is the decNumber to test */
368172ac97cdSTom Musta /* set is the context to use for Emin */
368272ac97cdSTom Musta /* returns 1 if |dn| is finite, non-zero, and <Nmin, 0 otherwise */
368372ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberIsSubnormal(const decNumber * dn,decContext * set)368472ac97cdSTom Musta Int decNumberIsSubnormal(const decNumber *dn, decContext *set) {
368572ac97cdSTom Musta Int ae; /* adjusted exponent */
368672ac97cdSTom Musta #if DECCHECK
368772ac97cdSTom Musta if (decCheckOperands(DECUNRESU, DECUNUSED, dn, set)) return 0;
368872ac97cdSTom Musta #endif
368972ac97cdSTom Musta
369072ac97cdSTom Musta if (decNumberIsSpecial(dn)) return 0; /* not finite */
369172ac97cdSTom Musta if (decNumberIsZero(dn)) return 0; /* not non-zero */
369272ac97cdSTom Musta
369372ac97cdSTom Musta ae=dn->exponent+dn->digits-1; /* adjusted exponent */
369472ac97cdSTom Musta if (ae<set->emin) return 1; /* is subnormal */
369572ac97cdSTom Musta return 0;
369672ac97cdSTom Musta } /* decNumberIsSubnormal */
369772ac97cdSTom Musta
369872ac97cdSTom Musta /* ------------------------------------------------------------------ */
369972ac97cdSTom Musta /* decNumberTrim -- remove insignificant zeros */
370072ac97cdSTom Musta /* */
370172ac97cdSTom Musta /* dn is the number to trim */
370272ac97cdSTom Musta /* returns dn */
370372ac97cdSTom Musta /* */
370472ac97cdSTom Musta /* All fields are updated as required. This is a utility operation, */
370572ac97cdSTom Musta /* so special values are unchanged and no error is possible. */
370672ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberTrim(decNumber * dn)370772ac97cdSTom Musta decNumber * decNumberTrim(decNumber *dn) {
370872ac97cdSTom Musta Int dropped; /* work */
370972ac97cdSTom Musta decContext set; /* .. */
371072ac97cdSTom Musta #if DECCHECK
371172ac97cdSTom Musta if (decCheckOperands(DECUNRESU, DECUNUSED, dn, DECUNCONT)) return dn;
371272ac97cdSTom Musta #endif
371372ac97cdSTom Musta decContextDefault(&set, DEC_INIT_BASE); /* clamp=0 */
371472ac97cdSTom Musta return decTrim(dn, &set, 0, &dropped);
371572ac97cdSTom Musta } /* decNumberTrim */
371672ac97cdSTom Musta
371772ac97cdSTom Musta /* ------------------------------------------------------------------ */
371872ac97cdSTom Musta /* decNumberVersion -- return the name and version of this module */
371972ac97cdSTom Musta /* */
372072ac97cdSTom Musta /* No error is possible. */
372172ac97cdSTom Musta /* ------------------------------------------------------------------ */
decNumberVersion(void)372272ac97cdSTom Musta const char * decNumberVersion(void) {
372372ac97cdSTom Musta return DECVERSION;
372472ac97cdSTom Musta } /* decNumberVersion */
372572ac97cdSTom Musta
372672ac97cdSTom Musta /* ------------------------------------------------------------------ */
372772ac97cdSTom Musta /* decNumberZero -- set a number to 0 */
372872ac97cdSTom Musta /* */
372972ac97cdSTom Musta /* dn is the number to set, with space for one digit */
373072ac97cdSTom Musta /* returns dn */
373172ac97cdSTom Musta /* */
373272ac97cdSTom Musta /* No error is possible. */
373372ac97cdSTom Musta /* ------------------------------------------------------------------ */
373472ac97cdSTom Musta /* Memset is not used as it is much slower in some environments. */
decNumberZero(decNumber * dn)373572ac97cdSTom Musta decNumber * decNumberZero(decNumber *dn) {
373672ac97cdSTom Musta
373772ac97cdSTom Musta #if DECCHECK
373872ac97cdSTom Musta if (decCheckOperands(dn, DECUNUSED, DECUNUSED, DECUNCONT)) return dn;
373972ac97cdSTom Musta #endif
374072ac97cdSTom Musta
374172ac97cdSTom Musta dn->bits=0;
374272ac97cdSTom Musta dn->exponent=0;
374372ac97cdSTom Musta dn->digits=1;
374472ac97cdSTom Musta dn->lsu[0]=0;
374572ac97cdSTom Musta return dn;
374672ac97cdSTom Musta } /* decNumberZero */
374772ac97cdSTom Musta
374872ac97cdSTom Musta /* ================================================================== */
374972ac97cdSTom Musta /* Local routines */
375072ac97cdSTom Musta /* ================================================================== */
375172ac97cdSTom Musta
375272ac97cdSTom Musta /* ------------------------------------------------------------------ */
375372ac97cdSTom Musta /* decToString -- lay out a number into a string */
375472ac97cdSTom Musta /* */
375572ac97cdSTom Musta /* dn is the number to lay out */
375672ac97cdSTom Musta /* string is where to lay out the number */
375772ac97cdSTom Musta /* eng is 1 if Engineering, 0 if Scientific */
375872ac97cdSTom Musta /* */
375972ac97cdSTom Musta /* string must be at least dn->digits+14 characters long */
376072ac97cdSTom Musta /* No error is possible. */
376172ac97cdSTom Musta /* */
376272ac97cdSTom Musta /* Note that this routine can generate a -0 or 0.000. These are */
376372ac97cdSTom Musta /* never generated in subset to-number or arithmetic, but can occur */
376472ac97cdSTom Musta /* in non-subset arithmetic (e.g., -1*0 or 1.234-1.234). */
376572ac97cdSTom Musta /* ------------------------------------------------------------------ */
376672ac97cdSTom Musta /* If DECCHECK is enabled the string "?" is returned if a number is */
376772ac97cdSTom Musta /* invalid. */
decToString(const decNumber * dn,char * string,Flag eng)376872ac97cdSTom Musta static void decToString(const decNumber *dn, char *string, Flag eng) {
376972ac97cdSTom Musta Int exp=dn->exponent; /* local copy */
377072ac97cdSTom Musta Int e; /* E-part value */
377172ac97cdSTom Musta Int pre; /* digits before the '.' */
377272ac97cdSTom Musta Int cut; /* for counting digits in a Unit */
377372ac97cdSTom Musta char *c=string; /* work [output pointer] */
377472ac97cdSTom Musta const Unit *up=dn->lsu+D2U(dn->digits)-1; /* -> msu [input pointer] */
377572ac97cdSTom Musta uInt u, pow; /* work */
377672ac97cdSTom Musta
377772ac97cdSTom Musta #if DECCHECK
377872ac97cdSTom Musta if (decCheckOperands(DECUNRESU, dn, DECUNUSED, DECUNCONT)) {
377972ac97cdSTom Musta strcpy(string, "?");
378072ac97cdSTom Musta return;}
378172ac97cdSTom Musta #endif
378272ac97cdSTom Musta
378372ac97cdSTom Musta if (decNumberIsNegative(dn)) { /* Negatives get a minus */
378472ac97cdSTom Musta *c='-';
378572ac97cdSTom Musta c++;
378672ac97cdSTom Musta }
378772ac97cdSTom Musta if (dn->bits&DECSPECIAL) { /* Is a special value */
378872ac97cdSTom Musta if (decNumberIsInfinite(dn)) {
378972ac97cdSTom Musta strcpy(c, "Inf");
379072ac97cdSTom Musta strcpy(c+3, "inity");
379172ac97cdSTom Musta return;}
379272ac97cdSTom Musta /* a NaN */
379372ac97cdSTom Musta if (dn->bits&DECSNAN) { /* signalling NaN */
379472ac97cdSTom Musta *c='s';
379572ac97cdSTom Musta c++;
379672ac97cdSTom Musta }
379772ac97cdSTom Musta strcpy(c, "NaN");
379872ac97cdSTom Musta c+=3; /* step past */
379972ac97cdSTom Musta /* if not a clean non-zero coefficient, that's all there is in a */
380072ac97cdSTom Musta /* NaN string */
380172ac97cdSTom Musta if (exp!=0 || (*dn->lsu==0 && dn->digits==1)) return;
380272ac97cdSTom Musta /* [drop through to add integer] */
380372ac97cdSTom Musta }
380472ac97cdSTom Musta
380572ac97cdSTom Musta /* calculate how many digits in msu, and hence first cut */
380672ac97cdSTom Musta cut=MSUDIGITS(dn->digits); /* [faster than remainder] */
380772ac97cdSTom Musta cut--; /* power of ten for digit */
380872ac97cdSTom Musta
380972ac97cdSTom Musta if (exp==0) { /* simple integer [common fastpath] */
381072ac97cdSTom Musta for (;up>=dn->lsu; up--) { /* each Unit from msu */
381172ac97cdSTom Musta u=*up; /* contains DECDPUN digits to lay out */
381272ac97cdSTom Musta for (; cut>=0; c++, cut--) TODIGIT(u, cut, c, pow);
381372ac97cdSTom Musta cut=DECDPUN-1; /* next Unit has all digits */
381472ac97cdSTom Musta }
381572ac97cdSTom Musta *c='\0'; /* terminate the string */
381672ac97cdSTom Musta return;}
381772ac97cdSTom Musta
381872ac97cdSTom Musta /* non-0 exponent -- assume plain form */
381972ac97cdSTom Musta pre=dn->digits+exp; /* digits before '.' */
382072ac97cdSTom Musta e=0; /* no E */
382172ac97cdSTom Musta if ((exp>0) || (pre<-5)) { /* need exponential form */
382272ac97cdSTom Musta e=exp+dn->digits-1; /* calculate E value */
382372ac97cdSTom Musta pre=1; /* assume one digit before '.' */
382472ac97cdSTom Musta if (eng && (e!=0)) { /* engineering: may need to adjust */
382572ac97cdSTom Musta Int adj; /* adjustment */
382672ac97cdSTom Musta /* The C remainder operator is undefined for negative numbers, so */
382772ac97cdSTom Musta /* a positive remainder calculation must be used here */
382872ac97cdSTom Musta if (e<0) {
382972ac97cdSTom Musta adj=(-e)%3;
383072ac97cdSTom Musta if (adj!=0) adj=3-adj;
383172ac97cdSTom Musta }
383272ac97cdSTom Musta else { /* e>0 */
383372ac97cdSTom Musta adj=e%3;
383472ac97cdSTom Musta }
383572ac97cdSTom Musta e=e-adj;
383672ac97cdSTom Musta /* if dealing with zero still produce an exponent which is a */
383772ac97cdSTom Musta /* multiple of three, as expected, but there will only be the */
383872ac97cdSTom Musta /* one zero before the E, still. Otherwise note the padding. */
383972ac97cdSTom Musta if (!ISZERO(dn)) pre+=adj;
384072ac97cdSTom Musta else { /* is zero */
384172ac97cdSTom Musta if (adj!=0) { /* 0.00Esnn needed */
384272ac97cdSTom Musta e=e+3;
384372ac97cdSTom Musta pre=-(2-adj);
384472ac97cdSTom Musta }
384572ac97cdSTom Musta } /* zero */
384672ac97cdSTom Musta } /* eng */
384772ac97cdSTom Musta } /* need exponent */
384872ac97cdSTom Musta
384972ac97cdSTom Musta /* lay out the digits of the coefficient, adding 0s and . as needed */
385072ac97cdSTom Musta u=*up;
385172ac97cdSTom Musta if (pre>0) { /* xxx.xxx or xx00 (engineering) form */
385272ac97cdSTom Musta Int n=pre;
385372ac97cdSTom Musta for (; pre>0; pre--, c++, cut--) {
385472ac97cdSTom Musta if (cut<0) { /* need new Unit */
385572ac97cdSTom Musta if (up==dn->lsu) break; /* out of input digits (pre>digits) */
385672ac97cdSTom Musta up--;
385772ac97cdSTom Musta cut=DECDPUN-1;
385872ac97cdSTom Musta u=*up;
385972ac97cdSTom Musta }
386072ac97cdSTom Musta TODIGIT(u, cut, c, pow);
386172ac97cdSTom Musta }
386272ac97cdSTom Musta if (n<dn->digits) { /* more to come, after '.' */
386372ac97cdSTom Musta *c='.'; c++;
386472ac97cdSTom Musta for (;; c++, cut--) {
386572ac97cdSTom Musta if (cut<0) { /* need new Unit */
386672ac97cdSTom Musta if (up==dn->lsu) break; /* out of input digits */
386772ac97cdSTom Musta up--;
386872ac97cdSTom Musta cut=DECDPUN-1;
386972ac97cdSTom Musta u=*up;
387072ac97cdSTom Musta }
387172ac97cdSTom Musta TODIGIT(u, cut, c, pow);
387272ac97cdSTom Musta }
387372ac97cdSTom Musta }
387472ac97cdSTom Musta else for (; pre>0; pre--, c++) *c='0'; /* 0 padding (for engineering) needed */
387572ac97cdSTom Musta }
387672ac97cdSTom Musta else { /* 0.xxx or 0.000xxx form */
387772ac97cdSTom Musta *c='0'; c++;
387872ac97cdSTom Musta *c='.'; c++;
387972ac97cdSTom Musta for (; pre<0; pre++, c++) *c='0'; /* add any 0's after '.' */
388072ac97cdSTom Musta for (; ; c++, cut--) {
388172ac97cdSTom Musta if (cut<0) { /* need new Unit */
388272ac97cdSTom Musta if (up==dn->lsu) break; /* out of input digits */
388372ac97cdSTom Musta up--;
388472ac97cdSTom Musta cut=DECDPUN-1;
388572ac97cdSTom Musta u=*up;
388672ac97cdSTom Musta }
388772ac97cdSTom Musta TODIGIT(u, cut, c, pow);
388872ac97cdSTom Musta }
388972ac97cdSTom Musta }
389072ac97cdSTom Musta
389172ac97cdSTom Musta /* Finally add the E-part, if needed. It will never be 0, has a
389272ac97cdSTom Musta base maximum and minimum of +999999999 through -999999999, but
389372ac97cdSTom Musta could range down to -1999999998 for anormal numbers */
389472ac97cdSTom Musta if (e!=0) {
389572ac97cdSTom Musta Flag had=0; /* 1=had non-zero */
389672ac97cdSTom Musta *c='E'; c++;
389772ac97cdSTom Musta *c='+'; c++; /* assume positive */
389872ac97cdSTom Musta u=e; /* .. */
389972ac97cdSTom Musta if (e<0) {
390072ac97cdSTom Musta *(c-1)='-'; /* oops, need - */
390172ac97cdSTom Musta u=-e; /* uInt, please */
390272ac97cdSTom Musta }
390372ac97cdSTom Musta /* lay out the exponent [_itoa or equivalent is not ANSI C] */
390472ac97cdSTom Musta for (cut=9; cut>=0; cut--) {
390572ac97cdSTom Musta TODIGIT(u, cut, c, pow);
390672ac97cdSTom Musta if (*c=='0' && !had) continue; /* skip leading zeros */
390772ac97cdSTom Musta had=1; /* had non-0 */
390872ac97cdSTom Musta c++; /* step for next */
390972ac97cdSTom Musta } /* cut */
391072ac97cdSTom Musta }
391172ac97cdSTom Musta *c='\0'; /* terminate the string (all paths) */
391272ac97cdSTom Musta return;
391372ac97cdSTom Musta } /* decToString */
391472ac97cdSTom Musta
391572ac97cdSTom Musta /* ------------------------------------------------------------------ */
391672ac97cdSTom Musta /* decAddOp -- add/subtract operation */
391772ac97cdSTom Musta /* */
391872ac97cdSTom Musta /* This computes C = A + B */
391972ac97cdSTom Musta /* */
392072ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X+X) */
392172ac97cdSTom Musta /* lhs is A */
392272ac97cdSTom Musta /* rhs is B */
392372ac97cdSTom Musta /* set is the context */
392472ac97cdSTom Musta /* negate is DECNEG if rhs should be negated, or 0 otherwise */
392572ac97cdSTom Musta /* status accumulates status for the caller */
392672ac97cdSTom Musta /* */
392772ac97cdSTom Musta /* C must have space for set->digits digits. */
392872ac97cdSTom Musta /* Inexact in status must be 0 for correct Exact zero sign in result */
392972ac97cdSTom Musta /* ------------------------------------------------------------------ */
393072ac97cdSTom Musta /* If possible, the coefficient is calculated directly into C. */
393172ac97cdSTom Musta /* However, if: */
393272ac97cdSTom Musta /* -- a digits+1 calculation is needed because the numbers are */
393372ac97cdSTom Musta /* unaligned and span more than set->digits digits */
393472ac97cdSTom Musta /* -- a carry to digits+1 digits looks possible */
393572ac97cdSTom Musta /* -- C is the same as A or B, and the result would destructively */
393672ac97cdSTom Musta /* overlap the A or B coefficient */
393772ac97cdSTom Musta /* then the result must be calculated into a temporary buffer. In */
393872ac97cdSTom Musta /* this case a local (stack) buffer is used if possible, and only if */
393972ac97cdSTom Musta /* too long for that does malloc become the final resort. */
394072ac97cdSTom Musta /* */
394172ac97cdSTom Musta /* Misalignment is handled as follows: */
394272ac97cdSTom Musta /* Apad: (AExp>BExp) Swap operands and proceed as for BExp>AExp. */
394372ac97cdSTom Musta /* BPad: Apply the padding by a combination of shifting (whole */
394472ac97cdSTom Musta /* units) and multiplication (part units). */
394572ac97cdSTom Musta /* */
394672ac97cdSTom Musta /* Addition, especially x=x+1, is speed-critical. */
394772ac97cdSTom Musta /* The static buffer is larger than might be expected to allow for */
394867cc32ebSVeres Lajos /* calls from higher-level functions (notably exp). */
394972ac97cdSTom Musta /* ------------------------------------------------------------------ */
decAddOp(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set,uByte negate,uInt * status)395072ac97cdSTom Musta static decNumber * decAddOp(decNumber *res, const decNumber *lhs,
395172ac97cdSTom Musta const decNumber *rhs, decContext *set,
395272ac97cdSTom Musta uByte negate, uInt *status) {
395372ac97cdSTom Musta #if DECSUBSET
395472ac97cdSTom Musta decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
395572ac97cdSTom Musta decNumber *allocrhs=NULL; /* .., rhs */
395672ac97cdSTom Musta #endif
395772ac97cdSTom Musta Int rhsshift; /* working shift (in Units) */
395872ac97cdSTom Musta Int maxdigits; /* longest logical length */
395972ac97cdSTom Musta Int mult; /* multiplier */
396072ac97cdSTom Musta Int residue; /* rounding accumulator */
396172ac97cdSTom Musta uByte bits; /* result bits */
396272ac97cdSTom Musta Flag diffsign; /* non-0 if arguments have different sign */
396372ac97cdSTom Musta Unit *acc; /* accumulator for result */
396472ac97cdSTom Musta Unit accbuff[SD2U(DECBUFFER*2+20)]; /* local buffer [*2+20 reduces many */
396572ac97cdSTom Musta /* allocations when called from */
396672ac97cdSTom Musta /* other operations, notable exp] */
396772ac97cdSTom Musta Unit *allocacc=NULL; /* -> allocated acc buffer, iff allocated */
396872ac97cdSTom Musta Int reqdigits=set->digits; /* local copy; requested DIGITS */
396972ac97cdSTom Musta Int padding; /* work */
397072ac97cdSTom Musta
397172ac97cdSTom Musta #if DECCHECK
397272ac97cdSTom Musta if (decCheckOperands(res, lhs, rhs, set)) return res;
397372ac97cdSTom Musta #endif
397472ac97cdSTom Musta
397572ac97cdSTom Musta do { /* protect allocated storage */
397672ac97cdSTom Musta #if DECSUBSET
397772ac97cdSTom Musta if (!set->extended) {
397872ac97cdSTom Musta /* reduce operands and set lostDigits status, as needed */
397972ac97cdSTom Musta if (lhs->digits>reqdigits) {
398072ac97cdSTom Musta alloclhs=decRoundOperand(lhs, set, status);
398172ac97cdSTom Musta if (alloclhs==NULL) break;
398272ac97cdSTom Musta lhs=alloclhs;
398372ac97cdSTom Musta }
398472ac97cdSTom Musta if (rhs->digits>reqdigits) {
398572ac97cdSTom Musta allocrhs=decRoundOperand(rhs, set, status);
398672ac97cdSTom Musta if (allocrhs==NULL) break;
398772ac97cdSTom Musta rhs=allocrhs;
398872ac97cdSTom Musta }
398972ac97cdSTom Musta }
399072ac97cdSTom Musta #endif
399172ac97cdSTom Musta /* [following code does not require input rounding] */
399272ac97cdSTom Musta
399372ac97cdSTom Musta /* note whether signs differ [used all paths] */
399472ac97cdSTom Musta diffsign=(Flag)((lhs->bits^rhs->bits^negate)&DECNEG);
399572ac97cdSTom Musta
399672ac97cdSTom Musta /* handle infinities and NaNs */
399772ac97cdSTom Musta if (SPECIALARGS) { /* a special bit set */
399872ac97cdSTom Musta if (SPECIALARGS & (DECSNAN | DECNAN)) /* a NaN */
399972ac97cdSTom Musta decNaNs(res, lhs, rhs, set, status);
400072ac97cdSTom Musta else { /* one or two infinities */
400172ac97cdSTom Musta if (decNumberIsInfinite(lhs)) { /* LHS is infinity */
400272ac97cdSTom Musta /* two infinities with different signs is invalid */
400372ac97cdSTom Musta if (decNumberIsInfinite(rhs) && diffsign) {
400472ac97cdSTom Musta *status|=DEC_Invalid_operation;
400572ac97cdSTom Musta break;
400672ac97cdSTom Musta }
400772ac97cdSTom Musta bits=lhs->bits & DECNEG; /* get sign from LHS */
400872ac97cdSTom Musta }
400972ac97cdSTom Musta else bits=(rhs->bits^negate) & DECNEG;/* RHS must be Infinity */
401072ac97cdSTom Musta bits|=DECINF;
401172ac97cdSTom Musta decNumberZero(res);
401272ac97cdSTom Musta res->bits=bits; /* set +/- infinity */
401372ac97cdSTom Musta } /* an infinity */
401472ac97cdSTom Musta break;
401572ac97cdSTom Musta }
401672ac97cdSTom Musta
401772ac97cdSTom Musta /* Quick exit for add 0s; return the non-0, modified as need be */
401872ac97cdSTom Musta if (ISZERO(lhs)) {
401972ac97cdSTom Musta Int adjust; /* work */
402072ac97cdSTom Musta Int lexp=lhs->exponent; /* save in case LHS==RES */
402172ac97cdSTom Musta bits=lhs->bits; /* .. */
402272ac97cdSTom Musta residue=0; /* clear accumulator */
402372ac97cdSTom Musta decCopyFit(res, rhs, set, &residue, status); /* copy (as needed) */
402472ac97cdSTom Musta res->bits^=negate; /* flip if rhs was negated */
402572ac97cdSTom Musta #if DECSUBSET
402672ac97cdSTom Musta if (set->extended) { /* exponents on zeros count */
402772ac97cdSTom Musta #endif
402872ac97cdSTom Musta /* exponent will be the lower of the two */
402972ac97cdSTom Musta adjust=lexp-res->exponent; /* adjustment needed [if -ve] */
403072ac97cdSTom Musta if (ISZERO(res)) { /* both 0: special IEEE 854 rules */
403172ac97cdSTom Musta if (adjust<0) res->exponent=lexp; /* set exponent */
403272ac97cdSTom Musta /* 0-0 gives +0 unless rounding to -infinity, and -0-0 gives -0 */
403372ac97cdSTom Musta if (diffsign) {
403472ac97cdSTom Musta if (set->round!=DEC_ROUND_FLOOR) res->bits=0;
403572ac97cdSTom Musta else res->bits=DECNEG; /* preserve 0 sign */
403672ac97cdSTom Musta }
403772ac97cdSTom Musta }
403872ac97cdSTom Musta else { /* non-0 res */
403972ac97cdSTom Musta if (adjust<0) { /* 0-padding needed */
404072ac97cdSTom Musta if ((res->digits-adjust)>set->digits) {
404172ac97cdSTom Musta adjust=res->digits-set->digits; /* to fit exactly */
404272ac97cdSTom Musta *status|=DEC_Rounded; /* [but exact] */
404372ac97cdSTom Musta }
404472ac97cdSTom Musta res->digits=decShiftToMost(res->lsu, res->digits, -adjust);
404572ac97cdSTom Musta res->exponent+=adjust; /* set the exponent. */
404672ac97cdSTom Musta }
404772ac97cdSTom Musta } /* non-0 res */
404872ac97cdSTom Musta #if DECSUBSET
404972ac97cdSTom Musta } /* extended */
405072ac97cdSTom Musta #endif
405172ac97cdSTom Musta decFinish(res, set, &residue, status); /* clean and finalize */
405272ac97cdSTom Musta break;}
405372ac97cdSTom Musta
405472ac97cdSTom Musta if (ISZERO(rhs)) { /* [lhs is non-zero] */
405572ac97cdSTom Musta Int adjust; /* work */
405672ac97cdSTom Musta Int rexp=rhs->exponent; /* save in case RHS==RES */
405772ac97cdSTom Musta bits=rhs->bits; /* be clean */
405872ac97cdSTom Musta residue=0; /* clear accumulator */
405972ac97cdSTom Musta decCopyFit(res, lhs, set, &residue, status); /* copy (as needed) */
406072ac97cdSTom Musta #if DECSUBSET
406172ac97cdSTom Musta if (set->extended) { /* exponents on zeros count */
406272ac97cdSTom Musta #endif
406372ac97cdSTom Musta /* exponent will be the lower of the two */
406472ac97cdSTom Musta /* [0-0 case handled above] */
406572ac97cdSTom Musta adjust=rexp-res->exponent; /* adjustment needed [if -ve] */
406672ac97cdSTom Musta if (adjust<0) { /* 0-padding needed */
406772ac97cdSTom Musta if ((res->digits-adjust)>set->digits) {
406872ac97cdSTom Musta adjust=res->digits-set->digits; /* to fit exactly */
406972ac97cdSTom Musta *status|=DEC_Rounded; /* [but exact] */
407072ac97cdSTom Musta }
407172ac97cdSTom Musta res->digits=decShiftToMost(res->lsu, res->digits, -adjust);
407272ac97cdSTom Musta res->exponent+=adjust; /* set the exponent. */
407372ac97cdSTom Musta }
407472ac97cdSTom Musta #if DECSUBSET
407572ac97cdSTom Musta } /* extended */
407672ac97cdSTom Musta #endif
407772ac97cdSTom Musta decFinish(res, set, &residue, status); /* clean and finalize */
407872ac97cdSTom Musta break;}
407972ac97cdSTom Musta
408072ac97cdSTom Musta /* [NB: both fastpath and mainpath code below assume these cases */
408172ac97cdSTom Musta /* (notably 0-0) have already been handled] */
408272ac97cdSTom Musta
408372ac97cdSTom Musta /* calculate the padding needed to align the operands */
408472ac97cdSTom Musta padding=rhs->exponent-lhs->exponent;
408572ac97cdSTom Musta
408672ac97cdSTom Musta /* Fastpath cases where the numbers are aligned and normal, the RHS */
408772ac97cdSTom Musta /* is all in one unit, no operand rounding is needed, and no carry, */
408872ac97cdSTom Musta /* lengthening, or borrow is needed */
408972ac97cdSTom Musta if (padding==0
409072ac97cdSTom Musta && rhs->digits<=DECDPUN
409172ac97cdSTom Musta && rhs->exponent>=set->emin /* [some normals drop through] */
409272ac97cdSTom Musta && rhs->exponent<=set->emax-set->digits+1 /* [could clamp] */
409372ac97cdSTom Musta && rhs->digits<=reqdigits
409472ac97cdSTom Musta && lhs->digits<=reqdigits) {
409572ac97cdSTom Musta Int partial=*lhs->lsu;
409672ac97cdSTom Musta if (!diffsign) { /* adding */
409772ac97cdSTom Musta partial+=*rhs->lsu;
409872ac97cdSTom Musta if ((partial<=DECDPUNMAX) /* result fits in unit */
409972ac97cdSTom Musta && (lhs->digits>=DECDPUN || /* .. and no digits-count change */
410072ac97cdSTom Musta partial<(Int)powers[lhs->digits])) { /* .. */
410172ac97cdSTom Musta if (res!=lhs) decNumberCopy(res, lhs); /* not in place */
410272ac97cdSTom Musta *res->lsu=(Unit)partial; /* [copy could have overwritten RHS] */
410372ac97cdSTom Musta break;
410472ac97cdSTom Musta }
410572ac97cdSTom Musta /* else drop out for careful add */
410672ac97cdSTom Musta }
410772ac97cdSTom Musta else { /* signs differ */
410872ac97cdSTom Musta partial-=*rhs->lsu;
410972ac97cdSTom Musta if (partial>0) { /* no borrow needed, and non-0 result */
411072ac97cdSTom Musta if (res!=lhs) decNumberCopy(res, lhs); /* not in place */
411172ac97cdSTom Musta *res->lsu=(Unit)partial;
411272ac97cdSTom Musta /* this could have reduced digits [but result>0] */
411372ac97cdSTom Musta res->digits=decGetDigits(res->lsu, D2U(res->digits));
411472ac97cdSTom Musta break;
411572ac97cdSTom Musta }
411672ac97cdSTom Musta /* else drop out for careful subtract */
411772ac97cdSTom Musta }
411872ac97cdSTom Musta }
411972ac97cdSTom Musta
412072ac97cdSTom Musta /* Now align (pad) the lhs or rhs so they can be added or */
412172ac97cdSTom Musta /* subtracted, as necessary. If one number is much larger than */
412272ac97cdSTom Musta /* the other (that is, if in plain form there is a least one */
412372ac97cdSTom Musta /* digit between the lowest digit of one and the highest of the */
412472ac97cdSTom Musta /* other) padding with up to DIGITS-1 trailing zeros may be */
412572ac97cdSTom Musta /* needed; then apply rounding (as exotic rounding modes may be */
412672ac97cdSTom Musta /* affected by the residue). */
412772ac97cdSTom Musta rhsshift=0; /* rhs shift to left (padding) in Units */
412872ac97cdSTom Musta bits=lhs->bits; /* assume sign is that of LHS */
412972ac97cdSTom Musta mult=1; /* likely multiplier */
413072ac97cdSTom Musta
413172ac97cdSTom Musta /* [if padding==0 the operands are aligned; no padding is needed] */
413272ac97cdSTom Musta if (padding!=0) {
413372ac97cdSTom Musta /* some padding needed; always pad the RHS, as any required */
413472ac97cdSTom Musta /* padding can then be effected by a simple combination of */
413572ac97cdSTom Musta /* shifts and a multiply */
413672ac97cdSTom Musta Flag swapped=0;
413772ac97cdSTom Musta if (padding<0) { /* LHS needs the padding */
413872ac97cdSTom Musta const decNumber *t;
413972ac97cdSTom Musta padding=-padding; /* will be +ve */
414072ac97cdSTom Musta bits=(uByte)(rhs->bits^negate); /* assumed sign is now that of RHS */
414172ac97cdSTom Musta t=lhs; lhs=rhs; rhs=t;
414272ac97cdSTom Musta swapped=1;
414372ac97cdSTom Musta }
414472ac97cdSTom Musta
414572ac97cdSTom Musta /* If, after pad, rhs would be longer than lhs by digits+1 or */
414672ac97cdSTom Musta /* more then lhs cannot affect the answer, except as a residue, */
414772ac97cdSTom Musta /* so only need to pad up to a length of DIGITS+1. */
414872ac97cdSTom Musta if (rhs->digits+padding > lhs->digits+reqdigits+1) {
414972ac97cdSTom Musta /* The RHS is sufficient */
415072ac97cdSTom Musta /* for residue use the relative sign indication... */
415172ac97cdSTom Musta Int shift=reqdigits-rhs->digits; /* left shift needed */
415272ac97cdSTom Musta residue=1; /* residue for rounding */
415372ac97cdSTom Musta if (diffsign) residue=-residue; /* signs differ */
415472ac97cdSTom Musta /* copy, shortening if necessary */
415572ac97cdSTom Musta decCopyFit(res, rhs, set, &residue, status);
415672ac97cdSTom Musta /* if it was already shorter, then need to pad with zeros */
415772ac97cdSTom Musta if (shift>0) {
415872ac97cdSTom Musta res->digits=decShiftToMost(res->lsu, res->digits, shift);
415972ac97cdSTom Musta res->exponent-=shift; /* adjust the exponent. */
416072ac97cdSTom Musta }
416172ac97cdSTom Musta /* flip the result sign if unswapped and rhs was negated */
416272ac97cdSTom Musta if (!swapped) res->bits^=negate;
416372ac97cdSTom Musta decFinish(res, set, &residue, status); /* done */
416472ac97cdSTom Musta break;}
416572ac97cdSTom Musta
416672ac97cdSTom Musta /* LHS digits may affect result */
416772ac97cdSTom Musta rhsshift=D2U(padding+1)-1; /* this much by Unit shift .. */
416872ac97cdSTom Musta mult=powers[padding-(rhsshift*DECDPUN)]; /* .. this by multiplication */
416972ac97cdSTom Musta } /* padding needed */
417072ac97cdSTom Musta
417172ac97cdSTom Musta if (diffsign) mult=-mult; /* signs differ */
417272ac97cdSTom Musta
417372ac97cdSTom Musta /* determine the longer operand */
417472ac97cdSTom Musta maxdigits=rhs->digits+padding; /* virtual length of RHS */
417572ac97cdSTom Musta if (lhs->digits>maxdigits) maxdigits=lhs->digits;
417672ac97cdSTom Musta
417772ac97cdSTom Musta /* Decide on the result buffer to use; if possible place directly */
417872ac97cdSTom Musta /* into result. */
417972ac97cdSTom Musta acc=res->lsu; /* assume add direct to result */
418072ac97cdSTom Musta /* If destructive overlap, or the number is too long, or a carry or */
418172ac97cdSTom Musta /* borrow to DIGITS+1 might be possible, a buffer must be used. */
418272ac97cdSTom Musta /* [Might be worth more sophisticated tests when maxdigits==reqdigits] */
418372ac97cdSTom Musta if ((maxdigits>=reqdigits) /* is, or could be, too large */
418472ac97cdSTom Musta || (res==rhs && rhsshift>0)) { /* destructive overlap */
418572ac97cdSTom Musta /* buffer needed, choose it; units for maxdigits digits will be */
418672ac97cdSTom Musta /* needed, +1 Unit for carry or borrow */
418772ac97cdSTom Musta Int need=D2U(maxdigits)+1;
418872ac97cdSTom Musta acc=accbuff; /* assume use local buffer */
418972ac97cdSTom Musta if (need*sizeof(Unit)>sizeof(accbuff)) {
419072ac97cdSTom Musta /* printf("malloc add %ld %ld\n", need, sizeof(accbuff)); */
419172ac97cdSTom Musta allocacc=(Unit *)malloc(need*sizeof(Unit));
419272ac97cdSTom Musta if (allocacc==NULL) { /* hopeless -- abandon */
419372ac97cdSTom Musta *status|=DEC_Insufficient_storage;
419472ac97cdSTom Musta break;}
419572ac97cdSTom Musta acc=allocacc;
419672ac97cdSTom Musta }
419772ac97cdSTom Musta }
419872ac97cdSTom Musta
419972ac97cdSTom Musta res->bits=(uByte)(bits&DECNEG); /* it's now safe to overwrite.. */
420072ac97cdSTom Musta res->exponent=lhs->exponent; /* .. operands (even if aliased) */
420172ac97cdSTom Musta
420272ac97cdSTom Musta #if DECTRACE
420372ac97cdSTom Musta decDumpAr('A', lhs->lsu, D2U(lhs->digits));
420472ac97cdSTom Musta decDumpAr('B', rhs->lsu, D2U(rhs->digits));
420572ac97cdSTom Musta printf(" :h: %ld %ld\n", rhsshift, mult);
420672ac97cdSTom Musta #endif
420772ac97cdSTom Musta
420872ac97cdSTom Musta /* add [A+B*m] or subtract [A+B*(-m)] */
420972ac97cdSTom Musta res->digits=decUnitAddSub(lhs->lsu, D2U(lhs->digits),
421072ac97cdSTom Musta rhs->lsu, D2U(rhs->digits),
421172ac97cdSTom Musta rhsshift, acc, mult)
421272ac97cdSTom Musta *DECDPUN; /* [units -> digits] */
421372ac97cdSTom Musta if (res->digits<0) { /* borrowed... */
421472ac97cdSTom Musta res->digits=-res->digits;
421572ac97cdSTom Musta res->bits^=DECNEG; /* flip the sign */
421672ac97cdSTom Musta }
421772ac97cdSTom Musta #if DECTRACE
421872ac97cdSTom Musta decDumpAr('+', acc, D2U(res->digits));
421972ac97cdSTom Musta #endif
422072ac97cdSTom Musta
422172ac97cdSTom Musta /* If a buffer was used the result must be copied back, possibly */
422272ac97cdSTom Musta /* shortening. (If no buffer was used then the result must have */
422372ac97cdSTom Musta /* fit, so can't need rounding and residue must be 0.) */
422472ac97cdSTom Musta residue=0; /* clear accumulator */
422572ac97cdSTom Musta if (acc!=res->lsu) {
422672ac97cdSTom Musta #if DECSUBSET
422772ac97cdSTom Musta if (set->extended) { /* round from first significant digit */
422872ac97cdSTom Musta #endif
422972ac97cdSTom Musta /* remove leading zeros that were added due to rounding up to */
423072ac97cdSTom Musta /* integral Units -- before the test for rounding. */
423172ac97cdSTom Musta if (res->digits>reqdigits)
423272ac97cdSTom Musta res->digits=decGetDigits(acc, D2U(res->digits));
423372ac97cdSTom Musta decSetCoeff(res, set, acc, res->digits, &residue, status);
423472ac97cdSTom Musta #if DECSUBSET
423572ac97cdSTom Musta }
423672ac97cdSTom Musta else { /* subset arithmetic rounds from original significant digit */
423772ac97cdSTom Musta /* May have an underestimate. This only occurs when both */
423872ac97cdSTom Musta /* numbers fit in DECDPUN digits and are padding with a */
423972ac97cdSTom Musta /* negative multiple (-10, -100...) and the top digit(s) become */
424072ac97cdSTom Musta /* 0. (This only matters when using X3.274 rules where the */
424172ac97cdSTom Musta /* leading zero could be included in the rounding.) */
424272ac97cdSTom Musta if (res->digits<maxdigits) {
424372ac97cdSTom Musta *(acc+D2U(res->digits))=0; /* ensure leading 0 is there */
424472ac97cdSTom Musta res->digits=maxdigits;
424572ac97cdSTom Musta }
424672ac97cdSTom Musta else {
424772ac97cdSTom Musta /* remove leading zeros that added due to rounding up to */
424872ac97cdSTom Musta /* integral Units (but only those in excess of the original */
424972ac97cdSTom Musta /* maxdigits length, unless extended) before test for rounding. */
425072ac97cdSTom Musta if (res->digits>reqdigits) {
425172ac97cdSTom Musta res->digits=decGetDigits(acc, D2U(res->digits));
425272ac97cdSTom Musta if (res->digits<maxdigits) res->digits=maxdigits;
425372ac97cdSTom Musta }
425472ac97cdSTom Musta }
425572ac97cdSTom Musta decSetCoeff(res, set, acc, res->digits, &residue, status);
425672ac97cdSTom Musta /* Now apply rounding if needed before removing leading zeros. */
425772ac97cdSTom Musta /* This is safe because subnormals are not a possibility */
425872ac97cdSTom Musta if (residue!=0) {
425972ac97cdSTom Musta decApplyRound(res, set, residue, status);
426072ac97cdSTom Musta residue=0; /* did what needed to be done */
426172ac97cdSTom Musta }
426272ac97cdSTom Musta } /* subset */
426372ac97cdSTom Musta #endif
426472ac97cdSTom Musta } /* used buffer */
426572ac97cdSTom Musta
426672ac97cdSTom Musta /* strip leading zeros [these were left on in case of subset subtract] */
426772ac97cdSTom Musta res->digits=decGetDigits(res->lsu, D2U(res->digits));
426872ac97cdSTom Musta
426972ac97cdSTom Musta /* apply checks and rounding */
427072ac97cdSTom Musta decFinish(res, set, &residue, status);
427172ac97cdSTom Musta
427272ac97cdSTom Musta /* "When the sum of two operands with opposite signs is exactly */
427372ac97cdSTom Musta /* zero, the sign of that sum shall be '+' in all rounding modes */
427472ac97cdSTom Musta /* except round toward -Infinity, in which mode that sign shall be */
427572ac97cdSTom Musta /* '-'." [Subset zeros also never have '-', set by decFinish.] */
427672ac97cdSTom Musta if (ISZERO(res) && diffsign
427772ac97cdSTom Musta #if DECSUBSET
427872ac97cdSTom Musta && set->extended
427972ac97cdSTom Musta #endif
428072ac97cdSTom Musta && (*status&DEC_Inexact)==0) {
428172ac97cdSTom Musta if (set->round==DEC_ROUND_FLOOR) res->bits|=DECNEG; /* sign - */
428272ac97cdSTom Musta else res->bits&=~DECNEG; /* sign + */
428372ac97cdSTom Musta }
428472ac97cdSTom Musta } while(0); /* end protected */
428572ac97cdSTom Musta
428672ac97cdSTom Musta if (allocacc!=NULL) free(allocacc); /* drop any storage used */
428772ac97cdSTom Musta #if DECSUBSET
428872ac97cdSTom Musta if (allocrhs!=NULL) free(allocrhs); /* .. */
428972ac97cdSTom Musta if (alloclhs!=NULL) free(alloclhs); /* .. */
429072ac97cdSTom Musta #endif
429172ac97cdSTom Musta return res;
429272ac97cdSTom Musta } /* decAddOp */
429372ac97cdSTom Musta
429472ac97cdSTom Musta /* ------------------------------------------------------------------ */
429572ac97cdSTom Musta /* decDivideOp -- division operation */
429672ac97cdSTom Musta /* */
429772ac97cdSTom Musta /* This routine performs the calculations for all four division */
429872ac97cdSTom Musta /* operators (divide, divideInteger, remainder, remainderNear). */
429972ac97cdSTom Musta /* */
430072ac97cdSTom Musta /* C=A op B */
430172ac97cdSTom Musta /* */
430272ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X/X) */
430372ac97cdSTom Musta /* lhs is A */
430472ac97cdSTom Musta /* rhs is B */
430572ac97cdSTom Musta /* set is the context */
430672ac97cdSTom Musta /* op is DIVIDE, DIVIDEINT, REMAINDER, or REMNEAR respectively. */
430772ac97cdSTom Musta /* status is the usual accumulator */
430872ac97cdSTom Musta /* */
430972ac97cdSTom Musta /* C must have space for set->digits digits. */
431072ac97cdSTom Musta /* */
431172ac97cdSTom Musta /* ------------------------------------------------------------------ */
431272ac97cdSTom Musta /* The underlying algorithm of this routine is the same as in the */
431372ac97cdSTom Musta /* 1981 S/370 implementation, that is, non-restoring long division */
431472ac97cdSTom Musta /* with bi-unit (rather than bi-digit) estimation for each unit */
431572ac97cdSTom Musta /* multiplier. In this pseudocode overview, complications for the */
431672ac97cdSTom Musta /* Remainder operators and division residues for exact rounding are */
431772ac97cdSTom Musta /* omitted for clarity. */
431872ac97cdSTom Musta /* */
431972ac97cdSTom Musta /* Prepare operands and handle special values */
432072ac97cdSTom Musta /* Test for x/0 and then 0/x */
432172ac97cdSTom Musta /* Exp =Exp1 - Exp2 */
432272ac97cdSTom Musta /* Exp =Exp +len(var1) -len(var2) */
432372ac97cdSTom Musta /* Sign=Sign1 * Sign2 */
432472ac97cdSTom Musta /* Pad accumulator (Var1) to double-length with 0's (pad1) */
432572ac97cdSTom Musta /* Pad Var2 to same length as Var1 */
432672ac97cdSTom Musta /* msu2pair/plus=1st 2 or 1 units of var2, +1 to allow for round */
432772ac97cdSTom Musta /* have=0 */
432872ac97cdSTom Musta /* Do until (have=digits+1 OR residue=0) */
432972ac97cdSTom Musta /* if exp<0 then if integer divide/residue then leave */
433072ac97cdSTom Musta /* this_unit=0 */
433172ac97cdSTom Musta /* Do forever */
433272ac97cdSTom Musta /* compare numbers */
433372ac97cdSTom Musta /* if <0 then leave inner_loop */
433472ac97cdSTom Musta /* if =0 then (* quick exit without subtract *) do */
433572ac97cdSTom Musta /* this_unit=this_unit+1; output this_unit */
433672ac97cdSTom Musta /* leave outer_loop; end */
433772ac97cdSTom Musta /* Compare lengths of numbers (mantissae): */
433872ac97cdSTom Musta /* If same then tops2=msu2pair -- {units 1&2 of var2} */
433972ac97cdSTom Musta /* else tops2=msu2plus -- {0, unit 1 of var2} */
434072ac97cdSTom Musta /* tops1=first_unit_of_Var1*10**DECDPUN +second_unit_of_var1 */
434172ac97cdSTom Musta /* mult=tops1/tops2 -- Good and safe guess at divisor */
434272ac97cdSTom Musta /* if mult=0 then mult=1 */
434372ac97cdSTom Musta /* this_unit=this_unit+mult */
434472ac97cdSTom Musta /* subtract */
434572ac97cdSTom Musta /* end inner_loop */
434672ac97cdSTom Musta /* if have\=0 | this_unit\=0 then do */
434772ac97cdSTom Musta /* output this_unit */
434872ac97cdSTom Musta /* have=have+1; end */
434972ac97cdSTom Musta /* var2=var2/10 */
435072ac97cdSTom Musta /* exp=exp-1 */
435172ac97cdSTom Musta /* end outer_loop */
435272ac97cdSTom Musta /* exp=exp+1 -- set the proper exponent */
435372ac97cdSTom Musta /* if have=0 then generate answer=0 */
435472ac97cdSTom Musta /* Return (Result is defined by Var1) */
435572ac97cdSTom Musta /* */
435672ac97cdSTom Musta /* ------------------------------------------------------------------ */
435772ac97cdSTom Musta /* Two working buffers are needed during the division; one (digits+ */
435872ac97cdSTom Musta /* 1) to accumulate the result, and the other (up to 2*digits+1) for */
435972ac97cdSTom Musta /* long subtractions. These are acc and var1 respectively. */
436072ac97cdSTom Musta /* var1 is a copy of the lhs coefficient, var2 is the rhs coefficient.*/
436172ac97cdSTom Musta /* The static buffers may be larger than might be expected to allow */
436267cc32ebSVeres Lajos /* for calls from higher-level functions (notably exp). */
436372ac97cdSTom Musta /* ------------------------------------------------------------------ */
decDivideOp(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set,Flag op,uInt * status)436472ac97cdSTom Musta static decNumber * decDivideOp(decNumber *res,
436572ac97cdSTom Musta const decNumber *lhs, const decNumber *rhs,
436672ac97cdSTom Musta decContext *set, Flag op, uInt *status) {
436772ac97cdSTom Musta #if DECSUBSET
436872ac97cdSTom Musta decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
436972ac97cdSTom Musta decNumber *allocrhs=NULL; /* .., rhs */
437072ac97cdSTom Musta #endif
437172ac97cdSTom Musta Unit accbuff[SD2U(DECBUFFER+DECDPUN+10)]; /* local buffer */
437272ac97cdSTom Musta Unit *acc=accbuff; /* -> accumulator array for result */
437372ac97cdSTom Musta Unit *allocacc=NULL; /* -> allocated buffer, iff allocated */
437472ac97cdSTom Musta Unit *accnext; /* -> where next digit will go */
437572ac97cdSTom Musta Int acclength; /* length of acc needed [Units] */
437672ac97cdSTom Musta Int accunits; /* count of units accumulated */
437772ac97cdSTom Musta Int accdigits; /* count of digits accumulated */
437872ac97cdSTom Musta
437972ac97cdSTom Musta Unit varbuff[SD2U(DECBUFFER*2+DECDPUN)*sizeof(Unit)]; /* buffer for var1 */
438072ac97cdSTom Musta Unit *var1=varbuff; /* -> var1 array for long subtraction */
438172ac97cdSTom Musta Unit *varalloc=NULL; /* -> allocated buffer, iff used */
438272ac97cdSTom Musta Unit *msu1; /* -> msu of var1 */
438372ac97cdSTom Musta
438472ac97cdSTom Musta const Unit *var2; /* -> var2 array */
438572ac97cdSTom Musta const Unit *msu2; /* -> msu of var2 */
438672ac97cdSTom Musta Int msu2plus; /* msu2 plus one [does not vary] */
438772ac97cdSTom Musta eInt msu2pair; /* msu2 pair plus one [does not vary] */
438872ac97cdSTom Musta
438972ac97cdSTom Musta Int var1units, var2units; /* actual lengths */
439072ac97cdSTom Musta Int var2ulen; /* logical length (units) */
439172ac97cdSTom Musta Int var1initpad=0; /* var1 initial padding (digits) */
439272ac97cdSTom Musta Int maxdigits; /* longest LHS or required acc length */
439372ac97cdSTom Musta Int mult; /* multiplier for subtraction */
439472ac97cdSTom Musta Unit thisunit; /* current unit being accumulated */
439572ac97cdSTom Musta Int residue; /* for rounding */
439672ac97cdSTom Musta Int reqdigits=set->digits; /* requested DIGITS */
439772ac97cdSTom Musta Int exponent; /* working exponent */
439872ac97cdSTom Musta Int maxexponent=0; /* DIVIDE maximum exponent if unrounded */
439972ac97cdSTom Musta uByte bits; /* working sign */
440072ac97cdSTom Musta Unit *target; /* work */
440172ac97cdSTom Musta const Unit *source; /* .. */
440279af3572STom Musta uLong const *pow; /* .. */
440372ac97cdSTom Musta Int shift, cut; /* .. */
440472ac97cdSTom Musta #if DECSUBSET
440572ac97cdSTom Musta Int dropped; /* work */
440672ac97cdSTom Musta #endif
440772ac97cdSTom Musta
440872ac97cdSTom Musta #if DECCHECK
440972ac97cdSTom Musta if (decCheckOperands(res, lhs, rhs, set)) return res;
441072ac97cdSTom Musta #endif
441172ac97cdSTom Musta
441272ac97cdSTom Musta do { /* protect allocated storage */
441372ac97cdSTom Musta #if DECSUBSET
441472ac97cdSTom Musta if (!set->extended) {
441572ac97cdSTom Musta /* reduce operands and set lostDigits status, as needed */
441672ac97cdSTom Musta if (lhs->digits>reqdigits) {
441772ac97cdSTom Musta alloclhs=decRoundOperand(lhs, set, status);
441872ac97cdSTom Musta if (alloclhs==NULL) break;
441972ac97cdSTom Musta lhs=alloclhs;
442072ac97cdSTom Musta }
442172ac97cdSTom Musta if (rhs->digits>reqdigits) {
442272ac97cdSTom Musta allocrhs=decRoundOperand(rhs, set, status);
442372ac97cdSTom Musta if (allocrhs==NULL) break;
442472ac97cdSTom Musta rhs=allocrhs;
442572ac97cdSTom Musta }
442672ac97cdSTom Musta }
442772ac97cdSTom Musta #endif
442872ac97cdSTom Musta /* [following code does not require input rounding] */
442972ac97cdSTom Musta
443072ac97cdSTom Musta bits=(lhs->bits^rhs->bits)&DECNEG; /* assumed sign for divisions */
443172ac97cdSTom Musta
443272ac97cdSTom Musta /* handle infinities and NaNs */
443372ac97cdSTom Musta if (SPECIALARGS) { /* a special bit set */
443472ac97cdSTom Musta if (SPECIALARGS & (DECSNAN | DECNAN)) { /* one or two NaNs */
443572ac97cdSTom Musta decNaNs(res, lhs, rhs, set, status);
443672ac97cdSTom Musta break;
443772ac97cdSTom Musta }
443872ac97cdSTom Musta /* one or two infinities */
443972ac97cdSTom Musta if (decNumberIsInfinite(lhs)) { /* LHS (dividend) is infinite */
444072ac97cdSTom Musta if (decNumberIsInfinite(rhs) || /* two infinities are invalid .. */
444172ac97cdSTom Musta op & (REMAINDER | REMNEAR)) { /* as is remainder of infinity */
444272ac97cdSTom Musta *status|=DEC_Invalid_operation;
444372ac97cdSTom Musta break;
444472ac97cdSTom Musta }
444572ac97cdSTom Musta /* [Note that infinity/0 raises no exceptions] */
444672ac97cdSTom Musta decNumberZero(res);
444772ac97cdSTom Musta res->bits=bits|DECINF; /* set +/- infinity */
444872ac97cdSTom Musta break;
444972ac97cdSTom Musta }
445072ac97cdSTom Musta else { /* RHS (divisor) is infinite */
445172ac97cdSTom Musta residue=0;
445272ac97cdSTom Musta if (op&(REMAINDER|REMNEAR)) {
445372ac97cdSTom Musta /* result is [finished clone of] lhs */
445472ac97cdSTom Musta decCopyFit(res, lhs, set, &residue, status);
445572ac97cdSTom Musta }
445672ac97cdSTom Musta else { /* a division */
445772ac97cdSTom Musta decNumberZero(res);
445872ac97cdSTom Musta res->bits=bits; /* set +/- zero */
445972ac97cdSTom Musta /* for DIVIDEINT the exponent is always 0. For DIVIDE, result */
446072ac97cdSTom Musta /* is a 0 with infinitely negative exponent, clamped to minimum */
446172ac97cdSTom Musta if (op&DIVIDE) {
446272ac97cdSTom Musta res->exponent=set->emin-set->digits+1;
446372ac97cdSTom Musta *status|=DEC_Clamped;
446472ac97cdSTom Musta }
446572ac97cdSTom Musta }
446672ac97cdSTom Musta decFinish(res, set, &residue, status);
446772ac97cdSTom Musta break;
446872ac97cdSTom Musta }
446972ac97cdSTom Musta }
447072ac97cdSTom Musta
447172ac97cdSTom Musta /* handle 0 rhs (x/0) */
447272ac97cdSTom Musta if (ISZERO(rhs)) { /* x/0 is always exceptional */
447372ac97cdSTom Musta if (ISZERO(lhs)) {
447472ac97cdSTom Musta decNumberZero(res); /* [after lhs test] */
447572ac97cdSTom Musta *status|=DEC_Division_undefined;/* 0/0 will become NaN */
447672ac97cdSTom Musta }
447772ac97cdSTom Musta else {
447872ac97cdSTom Musta decNumberZero(res);
447972ac97cdSTom Musta if (op&(REMAINDER|REMNEAR)) *status|=DEC_Invalid_operation;
448072ac97cdSTom Musta else {
448172ac97cdSTom Musta *status|=DEC_Division_by_zero; /* x/0 */
448272ac97cdSTom Musta res->bits=bits|DECINF; /* .. is +/- Infinity */
448372ac97cdSTom Musta }
448472ac97cdSTom Musta }
448572ac97cdSTom Musta break;}
448672ac97cdSTom Musta
448772ac97cdSTom Musta /* handle 0 lhs (0/x) */
448872ac97cdSTom Musta if (ISZERO(lhs)) { /* 0/x [x!=0] */
448972ac97cdSTom Musta #if DECSUBSET
449072ac97cdSTom Musta if (!set->extended) decNumberZero(res);
449172ac97cdSTom Musta else {
449272ac97cdSTom Musta #endif
449372ac97cdSTom Musta if (op&DIVIDE) {
449472ac97cdSTom Musta residue=0;
449572ac97cdSTom Musta exponent=lhs->exponent-rhs->exponent; /* ideal exponent */
449672ac97cdSTom Musta decNumberCopy(res, lhs); /* [zeros always fit] */
449772ac97cdSTom Musta res->bits=bits; /* sign as computed */
449872ac97cdSTom Musta res->exponent=exponent; /* exponent, too */
449972ac97cdSTom Musta decFinalize(res, set, &residue, status); /* check exponent */
450072ac97cdSTom Musta }
450172ac97cdSTom Musta else if (op&DIVIDEINT) {
450272ac97cdSTom Musta decNumberZero(res); /* integer 0 */
450372ac97cdSTom Musta res->bits=bits; /* sign as computed */
450472ac97cdSTom Musta }
450572ac97cdSTom Musta else { /* a remainder */
450672ac97cdSTom Musta exponent=rhs->exponent; /* [save in case overwrite] */
450772ac97cdSTom Musta decNumberCopy(res, lhs); /* [zeros always fit] */
450872ac97cdSTom Musta if (exponent<res->exponent) res->exponent=exponent; /* use lower */
450972ac97cdSTom Musta }
451072ac97cdSTom Musta #if DECSUBSET
451172ac97cdSTom Musta }
451272ac97cdSTom Musta #endif
451372ac97cdSTom Musta break;}
451472ac97cdSTom Musta
451572ac97cdSTom Musta /* Precalculate exponent. This starts off adjusted (and hence fits */
451672ac97cdSTom Musta /* in 31 bits) and becomes the usual unadjusted exponent as the */
451772ac97cdSTom Musta /* division proceeds. The order of evaluation is important, here, */
451872ac97cdSTom Musta /* to avoid wrap. */
451972ac97cdSTom Musta exponent=(lhs->exponent+lhs->digits)-(rhs->exponent+rhs->digits);
452072ac97cdSTom Musta
452172ac97cdSTom Musta /* If the working exponent is -ve, then some quick exits are */
452272ac97cdSTom Musta /* possible because the quotient is known to be <1 */
452372ac97cdSTom Musta /* [for REMNEAR, it needs to be < -1, as -0.5 could need work] */
452472ac97cdSTom Musta if (exponent<0 && !(op==DIVIDE)) {
452572ac97cdSTom Musta if (op&DIVIDEINT) {
452672ac97cdSTom Musta decNumberZero(res); /* integer part is 0 */
452772ac97cdSTom Musta #if DECSUBSET
452872ac97cdSTom Musta if (set->extended)
452972ac97cdSTom Musta #endif
453072ac97cdSTom Musta res->bits=bits; /* set +/- zero */
453172ac97cdSTom Musta break;}
453272ac97cdSTom Musta /* fastpath remainders so long as the lhs has the smaller */
453372ac97cdSTom Musta /* (or equal) exponent */
453472ac97cdSTom Musta if (lhs->exponent<=rhs->exponent) {
453572ac97cdSTom Musta if (op&REMAINDER || exponent<-1) {
453672ac97cdSTom Musta /* It is REMAINDER or safe REMNEAR; result is [finished */
453772ac97cdSTom Musta /* clone of] lhs (r = x - 0*y) */
453872ac97cdSTom Musta residue=0;
453972ac97cdSTom Musta decCopyFit(res, lhs, set, &residue, status);
454072ac97cdSTom Musta decFinish(res, set, &residue, status);
454172ac97cdSTom Musta break;
454272ac97cdSTom Musta }
454372ac97cdSTom Musta /* [unsafe REMNEAR drops through] */
454472ac97cdSTom Musta }
454572ac97cdSTom Musta } /* fastpaths */
454672ac97cdSTom Musta
454772ac97cdSTom Musta /* Long (slow) division is needed; roll up the sleeves... */
454872ac97cdSTom Musta
454972ac97cdSTom Musta /* The accumulator will hold the quotient of the division. */
455072ac97cdSTom Musta /* If it needs to be too long for stack storage, then allocate. */
455172ac97cdSTom Musta acclength=D2U(reqdigits+DECDPUN); /* in Units */
455272ac97cdSTom Musta if (acclength*sizeof(Unit)>sizeof(accbuff)) {
455372ac97cdSTom Musta /* printf("malloc dvacc %ld units\n", acclength); */
455472ac97cdSTom Musta allocacc=(Unit *)malloc(acclength*sizeof(Unit));
455572ac97cdSTom Musta if (allocacc==NULL) { /* hopeless -- abandon */
455672ac97cdSTom Musta *status|=DEC_Insufficient_storage;
455772ac97cdSTom Musta break;}
455872ac97cdSTom Musta acc=allocacc; /* use the allocated space */
455972ac97cdSTom Musta }
456072ac97cdSTom Musta
456172ac97cdSTom Musta /* var1 is the padded LHS ready for subtractions. */
456272ac97cdSTom Musta /* If it needs to be too long for stack storage, then allocate. */
456372ac97cdSTom Musta /* The maximum units needed for var1 (long subtraction) is: */
456472ac97cdSTom Musta /* Enough for */
456572ac97cdSTom Musta /* (rhs->digits+reqdigits-1) -- to allow full slide to right */
456672ac97cdSTom Musta /* or (lhs->digits) -- to allow for long lhs */
456772ac97cdSTom Musta /* whichever is larger */
456872ac97cdSTom Musta /* +1 -- for rounding of slide to right */
456972ac97cdSTom Musta /* +1 -- for leading 0s */
457072ac97cdSTom Musta /* +1 -- for pre-adjust if a remainder or DIVIDEINT */
457172ac97cdSTom Musta /* [Note: unused units do not participate in decUnitAddSub data] */
457272ac97cdSTom Musta maxdigits=rhs->digits+reqdigits-1;
457372ac97cdSTom Musta if (lhs->digits>maxdigits) maxdigits=lhs->digits;
457472ac97cdSTom Musta var1units=D2U(maxdigits)+2;
457572ac97cdSTom Musta /* allocate a guard unit above msu1 for REMAINDERNEAR */
457672ac97cdSTom Musta if (!(op&DIVIDE)) var1units++;
457772ac97cdSTom Musta if ((var1units+1)*sizeof(Unit)>sizeof(varbuff)) {
457872ac97cdSTom Musta /* printf("malloc dvvar %ld units\n", var1units+1); */
457972ac97cdSTom Musta varalloc=(Unit *)malloc((var1units+1)*sizeof(Unit));
458072ac97cdSTom Musta if (varalloc==NULL) { /* hopeless -- abandon */
458172ac97cdSTom Musta *status|=DEC_Insufficient_storage;
458272ac97cdSTom Musta break;}
458372ac97cdSTom Musta var1=varalloc; /* use the allocated space */
458472ac97cdSTom Musta }
458572ac97cdSTom Musta
458672ac97cdSTom Musta /* Extend the lhs and rhs to full long subtraction length. The lhs */
458772ac97cdSTom Musta /* is truly extended into the var1 buffer, with 0 padding, so a */
458872ac97cdSTom Musta /* subtract in place is always possible. The rhs (var2) has */
458972ac97cdSTom Musta /* virtual padding (implemented by decUnitAddSub). */
459072ac97cdSTom Musta /* One guard unit was allocated above msu1 for rem=rem+rem in */
459172ac97cdSTom Musta /* REMAINDERNEAR. */
459272ac97cdSTom Musta msu1=var1+var1units-1; /* msu of var1 */
459372ac97cdSTom Musta source=lhs->lsu+D2U(lhs->digits)-1; /* msu of input array */
459472ac97cdSTom Musta for (target=msu1; source>=lhs->lsu; source--, target--) *target=*source;
459572ac97cdSTom Musta for (; target>=var1; target--) *target=0;
459672ac97cdSTom Musta
459772ac97cdSTom Musta /* rhs (var2) is left-aligned with var1 at the start */
459872ac97cdSTom Musta var2ulen=var1units; /* rhs logical length (units) */
459972ac97cdSTom Musta var2units=D2U(rhs->digits); /* rhs actual length (units) */
460072ac97cdSTom Musta var2=rhs->lsu; /* -> rhs array */
460172ac97cdSTom Musta msu2=var2+var2units-1; /* -> msu of var2 [never changes] */
460272ac97cdSTom Musta /* now set up the variables which will be used for estimating the */
460372ac97cdSTom Musta /* multiplication factor. If these variables are not exact, add */
460472ac97cdSTom Musta /* 1 to make sure that the multiplier is never overestimated. */
460572ac97cdSTom Musta msu2plus=*msu2; /* it's value .. */
460672ac97cdSTom Musta if (var2units>1) msu2plus++; /* .. +1 if any more */
460772ac97cdSTom Musta msu2pair=(eInt)*msu2*(DECDPUNMAX+1);/* top two pair .. */
460872ac97cdSTom Musta if (var2units>1) { /* .. [else treat 2nd as 0] */
460972ac97cdSTom Musta msu2pair+=*(msu2-1); /* .. */
461072ac97cdSTom Musta if (var2units>2) msu2pair++; /* .. +1 if any more */
461172ac97cdSTom Musta }
461272ac97cdSTom Musta
461372ac97cdSTom Musta /* The calculation is working in units, which may have leading zeros, */
461472ac97cdSTom Musta /* but the exponent was calculated on the assumption that they are */
461572ac97cdSTom Musta /* both left-aligned. Adjust the exponent to compensate: add the */
461672ac97cdSTom Musta /* number of leading zeros in var1 msu and subtract those in var2 msu. */
461772ac97cdSTom Musta /* [This is actually done by counting the digits and negating, as */
461872ac97cdSTom Musta /* lead1=DECDPUN-digits1, and similarly for lead2.] */
461972ac97cdSTom Musta for (pow=&powers[1]; *msu1>=*pow; pow++) exponent--;
462072ac97cdSTom Musta for (pow=&powers[1]; *msu2>=*pow; pow++) exponent++;
462172ac97cdSTom Musta
462272ac97cdSTom Musta /* Now, if doing an integer divide or remainder, ensure that */
462372ac97cdSTom Musta /* the result will be Unit-aligned. To do this, shift the var1 */
462472ac97cdSTom Musta /* accumulator towards least if need be. (It's much easier to */
462572ac97cdSTom Musta /* do this now than to reassemble the residue afterwards, if */
462672ac97cdSTom Musta /* doing a remainder.) Also ensure the exponent is not negative. */
462772ac97cdSTom Musta if (!(op&DIVIDE)) {
462872ac97cdSTom Musta Unit *u; /* work */
462972ac97cdSTom Musta /* save the initial 'false' padding of var1, in digits */
463072ac97cdSTom Musta var1initpad=(var1units-D2U(lhs->digits))*DECDPUN;
463172ac97cdSTom Musta /* Determine the shift to do. */
463272ac97cdSTom Musta if (exponent<0) cut=-exponent;
463372ac97cdSTom Musta else cut=DECDPUN-exponent%DECDPUN;
463472ac97cdSTom Musta decShiftToLeast(var1, var1units, cut);
463572ac97cdSTom Musta exponent+=cut; /* maintain numerical value */
463672ac97cdSTom Musta var1initpad-=cut; /* .. and reduce padding */
463772ac97cdSTom Musta /* clean any most-significant units which were just emptied */
463872ac97cdSTom Musta for (u=msu1; cut>=DECDPUN; cut-=DECDPUN, u--) *u=0;
463972ac97cdSTom Musta } /* align */
464072ac97cdSTom Musta else { /* is DIVIDE */
464172ac97cdSTom Musta maxexponent=lhs->exponent-rhs->exponent; /* save */
464272ac97cdSTom Musta /* optimization: if the first iteration will just produce 0, */
464372ac97cdSTom Musta /* preadjust to skip it [valid for DIVIDE only] */
464472ac97cdSTom Musta if (*msu1<*msu2) {
464572ac97cdSTom Musta var2ulen--; /* shift down */
464672ac97cdSTom Musta exponent-=DECDPUN; /* update the exponent */
464772ac97cdSTom Musta }
464872ac97cdSTom Musta }
464972ac97cdSTom Musta
465072ac97cdSTom Musta /* ---- start the long-division loops ------------------------------ */
465172ac97cdSTom Musta accunits=0; /* no units accumulated yet */
465272ac97cdSTom Musta accdigits=0; /* .. or digits */
465372ac97cdSTom Musta accnext=acc+acclength-1; /* -> msu of acc [NB: allows digits+1] */
465472ac97cdSTom Musta for (;;) { /* outer forever loop */
465572ac97cdSTom Musta thisunit=0; /* current unit assumed 0 */
465672ac97cdSTom Musta /* find the next unit */
465772ac97cdSTom Musta for (;;) { /* inner forever loop */
465872ac97cdSTom Musta /* strip leading zero units [from either pre-adjust or from */
465972ac97cdSTom Musta /* subtract last time around]. Leave at least one unit. */
466072ac97cdSTom Musta for (; *msu1==0 && msu1>var1; msu1--) var1units--;
466172ac97cdSTom Musta
466272ac97cdSTom Musta if (var1units<var2ulen) break; /* var1 too low for subtract */
466372ac97cdSTom Musta if (var1units==var2ulen) { /* unit-by-unit compare needed */
466472ac97cdSTom Musta /* compare the two numbers, from msu */
466572ac97cdSTom Musta const Unit *pv1, *pv2;
466672ac97cdSTom Musta Unit v2; /* units to compare */
466772ac97cdSTom Musta pv2=msu2; /* -> msu */
466872ac97cdSTom Musta for (pv1=msu1; ; pv1--, pv2--) {
466972ac97cdSTom Musta /* v1=*pv1 -- always OK */
467072ac97cdSTom Musta v2=0; /* assume in padding */
467172ac97cdSTom Musta if (pv2>=var2) v2=*pv2; /* in range */
467272ac97cdSTom Musta if (*pv1!=v2) break; /* no longer the same */
467372ac97cdSTom Musta if (pv1==var1) break; /* done; leave pv1 as is */
467472ac97cdSTom Musta }
467572ac97cdSTom Musta /* here when all inspected or a difference seen */
467672ac97cdSTom Musta if (*pv1<v2) break; /* var1 too low to subtract */
467772ac97cdSTom Musta if (*pv1==v2) { /* var1 == var2 */
467872ac97cdSTom Musta /* reach here if var1 and var2 are identical; subtraction */
467972ac97cdSTom Musta /* would increase digit by one, and the residue will be 0 so */
468072ac97cdSTom Musta /* the calculation is done; leave the loop with residue=0. */
468172ac97cdSTom Musta thisunit++; /* as though subtracted */
468272ac97cdSTom Musta *var1=0; /* set var1 to 0 */
468372ac97cdSTom Musta var1units=1; /* .. */
468472ac97cdSTom Musta break; /* from inner */
468572ac97cdSTom Musta } /* var1 == var2 */
468672ac97cdSTom Musta /* *pv1>v2. Prepare for real subtraction; the lengths are equal */
468772ac97cdSTom Musta /* Estimate the multiplier (there's always a msu1-1)... */
468872ac97cdSTom Musta /* Bring in two units of var2 to provide a good estimate. */
468972ac97cdSTom Musta mult=(Int)(((eInt)*msu1*(DECDPUNMAX+1)+*(msu1-1))/msu2pair);
469072ac97cdSTom Musta } /* lengths the same */
469172ac97cdSTom Musta else { /* var1units > var2ulen, so subtraction is safe */
469272ac97cdSTom Musta /* The var2 msu is one unit towards the lsu of the var1 msu, */
469372ac97cdSTom Musta /* so only one unit for var2 can be used. */
469472ac97cdSTom Musta mult=(Int)(((eInt)*msu1*(DECDPUNMAX+1)+*(msu1-1))/msu2plus);
469572ac97cdSTom Musta }
469672ac97cdSTom Musta if (mult==0) mult=1; /* must always be at least 1 */
469772ac97cdSTom Musta /* subtraction needed; var1 is > var2 */
469872ac97cdSTom Musta thisunit=(Unit)(thisunit+mult); /* accumulate */
469972ac97cdSTom Musta /* subtract var1-var2, into var1; only the overlap needs */
470072ac97cdSTom Musta /* processing, as this is an in-place calculation */
470172ac97cdSTom Musta shift=var2ulen-var2units;
470272ac97cdSTom Musta #if DECTRACE
470372ac97cdSTom Musta decDumpAr('1', &var1[shift], var1units-shift);
470472ac97cdSTom Musta decDumpAr('2', var2, var2units);
470572ac97cdSTom Musta printf("m=%ld\n", -mult);
470672ac97cdSTom Musta #endif
470772ac97cdSTom Musta decUnitAddSub(&var1[shift], var1units-shift,
470872ac97cdSTom Musta var2, var2units, 0,
470972ac97cdSTom Musta &var1[shift], -mult);
471072ac97cdSTom Musta #if DECTRACE
471172ac97cdSTom Musta decDumpAr('#', &var1[shift], var1units-shift);
471272ac97cdSTom Musta #endif
471372ac97cdSTom Musta /* var1 now probably has leading zeros; these are removed at the */
471472ac97cdSTom Musta /* top of the inner loop. */
471572ac97cdSTom Musta } /* inner loop */
471672ac97cdSTom Musta
471772ac97cdSTom Musta /* The next unit has been calculated in full; unless it's a */
471872ac97cdSTom Musta /* leading zero, add to acc */
471972ac97cdSTom Musta if (accunits!=0 || thisunit!=0) { /* is first or non-zero */
472072ac97cdSTom Musta *accnext=thisunit; /* store in accumulator */
472172ac97cdSTom Musta /* account exactly for the new digits */
472272ac97cdSTom Musta if (accunits==0) {
472372ac97cdSTom Musta accdigits++; /* at least one */
472472ac97cdSTom Musta for (pow=&powers[1]; thisunit>=*pow; pow++) accdigits++;
472572ac97cdSTom Musta }
472672ac97cdSTom Musta else accdigits+=DECDPUN;
472772ac97cdSTom Musta accunits++; /* update count */
472872ac97cdSTom Musta accnext--; /* ready for next */
472972ac97cdSTom Musta if (accdigits>reqdigits) break; /* have enough digits */
473072ac97cdSTom Musta }
473172ac97cdSTom Musta
473272ac97cdSTom Musta /* if the residue is zero, the operation is done (unless divide */
473372ac97cdSTom Musta /* or divideInteger and still not enough digits yet) */
473472ac97cdSTom Musta if (*var1==0 && var1units==1) { /* residue is 0 */
473572ac97cdSTom Musta if (op&(REMAINDER|REMNEAR)) break;
473672ac97cdSTom Musta if ((op&DIVIDE) && (exponent<=maxexponent)) break;
473772ac97cdSTom Musta /* [drop through if divideInteger] */
473872ac97cdSTom Musta }
473972ac97cdSTom Musta /* also done enough if calculating remainder or integer */
474072ac97cdSTom Musta /* divide and just did the last ('units') unit */
474172ac97cdSTom Musta if (exponent==0 && !(op&DIVIDE)) break;
474272ac97cdSTom Musta
474372ac97cdSTom Musta /* to get here, var1 is less than var2, so divide var2 by the per- */
474472ac97cdSTom Musta /* Unit power of ten and go for the next digit */
474572ac97cdSTom Musta var2ulen--; /* shift down */
474672ac97cdSTom Musta exponent-=DECDPUN; /* update the exponent */
474772ac97cdSTom Musta } /* outer loop */
474872ac97cdSTom Musta
474972ac97cdSTom Musta /* ---- division is complete --------------------------------------- */
475072ac97cdSTom Musta /* here: acc has at least reqdigits+1 of good results (or fewer */
475172ac97cdSTom Musta /* if early stop), starting at accnext+1 (its lsu) */
475272ac97cdSTom Musta /* var1 has any residue at the stopping point */
475372ac97cdSTom Musta /* accunits is the number of digits collected in acc */
475472ac97cdSTom Musta if (accunits==0) { /* acc is 0 */
475572ac97cdSTom Musta accunits=1; /* show have a unit .. */
475672ac97cdSTom Musta accdigits=1; /* .. */
475772ac97cdSTom Musta *accnext=0; /* .. whose value is 0 */
475872ac97cdSTom Musta }
475972ac97cdSTom Musta else accnext++; /* back to last placed */
476072ac97cdSTom Musta /* accnext now -> lowest unit of result */
476172ac97cdSTom Musta
476272ac97cdSTom Musta residue=0; /* assume no residue */
476372ac97cdSTom Musta if (op&DIVIDE) {
476472ac97cdSTom Musta /* record the presence of any residue, for rounding */
476572ac97cdSTom Musta if (*var1!=0 || var1units>1) residue=1;
476672ac97cdSTom Musta else { /* no residue */
476772ac97cdSTom Musta /* Had an exact division; clean up spurious trailing 0s. */
476872ac97cdSTom Musta /* There will be at most DECDPUN-1, from the final multiply, */
476972ac97cdSTom Musta /* and then only if the result is non-0 (and even) and the */
477072ac97cdSTom Musta /* exponent is 'loose'. */
477172ac97cdSTom Musta #if DECDPUN>1
477272ac97cdSTom Musta Unit lsu=*accnext;
477372ac97cdSTom Musta if (!(lsu&0x01) && (lsu!=0)) {
477472ac97cdSTom Musta /* count the trailing zeros */
477572ac97cdSTom Musta Int drop=0;
477672ac97cdSTom Musta for (;; drop++) { /* [will terminate because lsu!=0] */
477772ac97cdSTom Musta if (exponent>=maxexponent) break; /* don't chop real 0s */
477872ac97cdSTom Musta #if DECDPUN<=4
477972ac97cdSTom Musta if ((lsu-QUOT10(lsu, drop+1)
478072ac97cdSTom Musta *powers[drop+1])!=0) break; /* found non-0 digit */
478172ac97cdSTom Musta #else
478272ac97cdSTom Musta if (lsu%powers[drop+1]!=0) break; /* found non-0 digit */
478372ac97cdSTom Musta #endif
478472ac97cdSTom Musta exponent++;
478572ac97cdSTom Musta }
478672ac97cdSTom Musta if (drop>0) {
478772ac97cdSTom Musta accunits=decShiftToLeast(accnext, accunits, drop);
478872ac97cdSTom Musta accdigits=decGetDigits(accnext, accunits);
478972ac97cdSTom Musta accunits=D2U(accdigits);
479072ac97cdSTom Musta /* [exponent was adjusted in the loop] */
479172ac97cdSTom Musta }
479272ac97cdSTom Musta } /* neither odd nor 0 */
479372ac97cdSTom Musta #endif
479472ac97cdSTom Musta } /* exact divide */
479572ac97cdSTom Musta } /* divide */
479672ac97cdSTom Musta else /* op!=DIVIDE */ {
479772ac97cdSTom Musta /* check for coefficient overflow */
479872ac97cdSTom Musta if (accdigits+exponent>reqdigits) {
479972ac97cdSTom Musta *status|=DEC_Division_impossible;
480072ac97cdSTom Musta break;
480172ac97cdSTom Musta }
480272ac97cdSTom Musta if (op & (REMAINDER|REMNEAR)) {
480372ac97cdSTom Musta /* [Here, the exponent will be 0, because var1 was adjusted */
480472ac97cdSTom Musta /* appropriately.] */
480572ac97cdSTom Musta Int postshift; /* work */
480672ac97cdSTom Musta Flag wasodd=0; /* integer was odd */
480772ac97cdSTom Musta Unit *quotlsu; /* for save */
480872ac97cdSTom Musta Int quotdigits; /* .. */
480972ac97cdSTom Musta
481072ac97cdSTom Musta bits=lhs->bits; /* remainder sign is always as lhs */
481172ac97cdSTom Musta
481272ac97cdSTom Musta /* Fastpath when residue is truly 0 is worthwhile [and */
481372ac97cdSTom Musta /* simplifies the code below] */
481472ac97cdSTom Musta if (*var1==0 && var1units==1) { /* residue is 0 */
481572ac97cdSTom Musta Int exp=lhs->exponent; /* save min(exponents) */
481672ac97cdSTom Musta if (rhs->exponent<exp) exp=rhs->exponent;
481772ac97cdSTom Musta decNumberZero(res); /* 0 coefficient */
481872ac97cdSTom Musta #if DECSUBSET
481972ac97cdSTom Musta if (set->extended)
482072ac97cdSTom Musta #endif
482172ac97cdSTom Musta res->exponent=exp; /* .. with proper exponent */
482272ac97cdSTom Musta res->bits=(uByte)(bits&DECNEG); /* [cleaned] */
482372ac97cdSTom Musta decFinish(res, set, &residue, status); /* might clamp */
482472ac97cdSTom Musta break;
482572ac97cdSTom Musta }
482672ac97cdSTom Musta /* note if the quotient was odd */
482772ac97cdSTom Musta if (*accnext & 0x01) wasodd=1; /* acc is odd */
482872ac97cdSTom Musta quotlsu=accnext; /* save in case need to reinspect */
482972ac97cdSTom Musta quotdigits=accdigits; /* .. */
483072ac97cdSTom Musta
483172ac97cdSTom Musta /* treat the residue, in var1, as the value to return, via acc */
483272ac97cdSTom Musta /* calculate the unused zero digits. This is the smaller of: */
483372ac97cdSTom Musta /* var1 initial padding (saved above) */
483472ac97cdSTom Musta /* var2 residual padding, which happens to be given by: */
483572ac97cdSTom Musta postshift=var1initpad+exponent-lhs->exponent+rhs->exponent;
483672ac97cdSTom Musta /* [the 'exponent' term accounts for the shifts during divide] */
483772ac97cdSTom Musta if (var1initpad<postshift) postshift=var1initpad;
483872ac97cdSTom Musta
483972ac97cdSTom Musta /* shift var1 the requested amount, and adjust its digits */
484072ac97cdSTom Musta var1units=decShiftToLeast(var1, var1units, postshift);
484172ac97cdSTom Musta accnext=var1;
484272ac97cdSTom Musta accdigits=decGetDigits(var1, var1units);
484372ac97cdSTom Musta accunits=D2U(accdigits);
484472ac97cdSTom Musta
484572ac97cdSTom Musta exponent=lhs->exponent; /* exponent is smaller of lhs & rhs */
484672ac97cdSTom Musta if (rhs->exponent<exponent) exponent=rhs->exponent;
484772ac97cdSTom Musta
484872ac97cdSTom Musta /* Now correct the result if doing remainderNear; if it */
484972ac97cdSTom Musta /* (looking just at coefficients) is > rhs/2, or == rhs/2 and */
485072ac97cdSTom Musta /* the integer was odd then the result should be rem-rhs. */
485172ac97cdSTom Musta if (op&REMNEAR) {
485272ac97cdSTom Musta Int compare, tarunits; /* work */
485372ac97cdSTom Musta Unit *up; /* .. */
485472ac97cdSTom Musta /* calculate remainder*2 into the var1 buffer (which has */
485572ac97cdSTom Musta /* 'headroom' of an extra unit and hence enough space) */
485672ac97cdSTom Musta /* [a dedicated 'double' loop would be faster, here] */
485772ac97cdSTom Musta tarunits=decUnitAddSub(accnext, accunits, accnext, accunits,
485872ac97cdSTom Musta 0, accnext, 1);
485972ac97cdSTom Musta /* decDumpAr('r', accnext, tarunits); */
486072ac97cdSTom Musta
486172ac97cdSTom Musta /* Here, accnext (var1) holds tarunits Units with twice the */
486272ac97cdSTom Musta /* remainder's coefficient, which must now be compared to the */
486372ac97cdSTom Musta /* RHS. The remainder's exponent may be smaller than the RHS's. */
486472ac97cdSTom Musta compare=decUnitCompare(accnext, tarunits, rhs->lsu, D2U(rhs->digits),
486572ac97cdSTom Musta rhs->exponent-exponent);
486672ac97cdSTom Musta if (compare==BADINT) { /* deep trouble */
486772ac97cdSTom Musta *status|=DEC_Insufficient_storage;
486872ac97cdSTom Musta break;}
486972ac97cdSTom Musta
487072ac97cdSTom Musta /* now restore the remainder by dividing by two; the lsu */
487172ac97cdSTom Musta /* is known to be even. */
487272ac97cdSTom Musta for (up=accnext; up<accnext+tarunits; up++) {
487372ac97cdSTom Musta Int half; /* half to add to lower unit */
487472ac97cdSTom Musta half=*up & 0x01;
487572ac97cdSTom Musta *up/=2; /* [shift] */
487672ac97cdSTom Musta if (!half) continue;
48776402cbbbSMarc-André Lureau *(up-1)+=DIV_ROUND_UP(DECDPUNMAX, 2);
487872ac97cdSTom Musta }
487972ac97cdSTom Musta /* [accunits still describes the original remainder length] */
488072ac97cdSTom Musta
488172ac97cdSTom Musta if (compare>0 || (compare==0 && wasodd)) { /* adjustment needed */
488272ac97cdSTom Musta Int exp, expunits, exprem; /* work */
488372ac97cdSTom Musta /* This is effectively causing round-up of the quotient, */
488472ac97cdSTom Musta /* so if it was the rare case where it was full and all */
488572ac97cdSTom Musta /* nines, it would overflow and hence division-impossible */
488672ac97cdSTom Musta /* should be raised */
488772ac97cdSTom Musta Flag allnines=0; /* 1 if quotient all nines */
488872ac97cdSTom Musta if (quotdigits==reqdigits) { /* could be borderline */
488972ac97cdSTom Musta for (up=quotlsu; ; up++) {
489072ac97cdSTom Musta if (quotdigits>DECDPUN) {
489172ac97cdSTom Musta if (*up!=DECDPUNMAX) break;/* non-nines */
489272ac97cdSTom Musta }
489372ac97cdSTom Musta else { /* this is the last Unit */
489472ac97cdSTom Musta if (*up==powers[quotdigits]-1) allnines=1;
489572ac97cdSTom Musta break;
489672ac97cdSTom Musta }
489772ac97cdSTom Musta quotdigits-=DECDPUN; /* checked those digits */
489872ac97cdSTom Musta } /* up */
489972ac97cdSTom Musta } /* borderline check */
490072ac97cdSTom Musta if (allnines) {
490172ac97cdSTom Musta *status|=DEC_Division_impossible;
490272ac97cdSTom Musta break;}
490372ac97cdSTom Musta
490472ac97cdSTom Musta /* rem-rhs is needed; the sign will invert. Again, var1 */
490572ac97cdSTom Musta /* can safely be used for the working Units array. */
490672ac97cdSTom Musta exp=rhs->exponent-exponent; /* RHS padding needed */
490772ac97cdSTom Musta /* Calculate units and remainder from exponent. */
490872ac97cdSTom Musta expunits=exp/DECDPUN;
490972ac97cdSTom Musta exprem=exp%DECDPUN;
491072ac97cdSTom Musta /* subtract [A+B*(-m)]; the result will always be negative */
491172ac97cdSTom Musta accunits=-decUnitAddSub(accnext, accunits,
491272ac97cdSTom Musta rhs->lsu, D2U(rhs->digits),
491372ac97cdSTom Musta expunits, accnext, -(Int)powers[exprem]);
491472ac97cdSTom Musta accdigits=decGetDigits(accnext, accunits); /* count digits exactly */
491572ac97cdSTom Musta accunits=D2U(accdigits); /* and recalculate the units for copy */
491672ac97cdSTom Musta /* [exponent is as for original remainder] */
491772ac97cdSTom Musta bits^=DECNEG; /* flip the sign */
491872ac97cdSTom Musta }
491972ac97cdSTom Musta } /* REMNEAR */
492072ac97cdSTom Musta } /* REMAINDER or REMNEAR */
492172ac97cdSTom Musta } /* not DIVIDE */
492272ac97cdSTom Musta
492372ac97cdSTom Musta /* Set exponent and bits */
492472ac97cdSTom Musta res->exponent=exponent;
492572ac97cdSTom Musta res->bits=(uByte)(bits&DECNEG); /* [cleaned] */
492672ac97cdSTom Musta
492772ac97cdSTom Musta /* Now the coefficient. */
492872ac97cdSTom Musta decSetCoeff(res, set, accnext, accdigits, &residue, status);
492972ac97cdSTom Musta
493072ac97cdSTom Musta decFinish(res, set, &residue, status); /* final cleanup */
493172ac97cdSTom Musta
493272ac97cdSTom Musta #if DECSUBSET
493372ac97cdSTom Musta /* If a divide then strip trailing zeros if subset [after round] */
493472ac97cdSTom Musta if (!set->extended && (op==DIVIDE)) decTrim(res, set, 0, &dropped);
493572ac97cdSTom Musta #endif
493672ac97cdSTom Musta } while(0); /* end protected */
493772ac97cdSTom Musta
493872ac97cdSTom Musta if (varalloc!=NULL) free(varalloc); /* drop any storage used */
493972ac97cdSTom Musta if (allocacc!=NULL) free(allocacc); /* .. */
494072ac97cdSTom Musta #if DECSUBSET
494172ac97cdSTom Musta if (allocrhs!=NULL) free(allocrhs); /* .. */
494272ac97cdSTom Musta if (alloclhs!=NULL) free(alloclhs); /* .. */
494372ac97cdSTom Musta #endif
494472ac97cdSTom Musta return res;
494572ac97cdSTom Musta } /* decDivideOp */
494672ac97cdSTom Musta
494772ac97cdSTom Musta /* ------------------------------------------------------------------ */
494872ac97cdSTom Musta /* decMultiplyOp -- multiplication operation */
494972ac97cdSTom Musta /* */
495072ac97cdSTom Musta /* This routine performs the multiplication C=A x B. */
495172ac97cdSTom Musta /* */
495272ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X*X) */
495372ac97cdSTom Musta /* lhs is A */
495472ac97cdSTom Musta /* rhs is B */
495572ac97cdSTom Musta /* set is the context */
495672ac97cdSTom Musta /* status is the usual accumulator */
495772ac97cdSTom Musta /* */
495872ac97cdSTom Musta /* C must have space for set->digits digits. */
495972ac97cdSTom Musta /* */
496072ac97cdSTom Musta /* ------------------------------------------------------------------ */
496172ac97cdSTom Musta /* 'Classic' multiplication is used rather than Karatsuba, as the */
496272ac97cdSTom Musta /* latter would give only a minor improvement for the short numbers */
496372ac97cdSTom Musta /* expected to be handled most (and uses much more memory). */
496472ac97cdSTom Musta /* */
496572ac97cdSTom Musta /* There are two major paths here: the general-purpose ('old code') */
496672ac97cdSTom Musta /* path which handles all DECDPUN values, and a fastpath version */
496772ac97cdSTom Musta /* which is used if 64-bit ints are available, DECDPUN<=4, and more */
496872ac97cdSTom Musta /* than two calls to decUnitAddSub would be made. */
496972ac97cdSTom Musta /* */
497072ac97cdSTom Musta /* The fastpath version lumps units together into 8-digit or 9-digit */
497172ac97cdSTom Musta /* chunks, and also uses a lazy carry strategy to minimise expensive */
497272ac97cdSTom Musta /* 64-bit divisions. The chunks are then broken apart again into */
497372ac97cdSTom Musta /* units for continuing processing. Despite this overhead, the */
497472ac97cdSTom Musta /* fastpath can speed up some 16-digit operations by 10x (and much */
497572ac97cdSTom Musta /* more for higher-precision calculations). */
497672ac97cdSTom Musta /* */
497772ac97cdSTom Musta /* A buffer always has to be used for the accumulator; in the */
497872ac97cdSTom Musta /* fastpath, buffers are also always needed for the chunked copies of */
497972ac97cdSTom Musta /* of the operand coefficients. */
498072ac97cdSTom Musta /* Static buffers are larger than needed just for multiply, to allow */
498172ac97cdSTom Musta /* for calls from other operations (notably exp). */
498272ac97cdSTom Musta /* ------------------------------------------------------------------ */
498372ac97cdSTom Musta #define FASTMUL (DECUSE64 && DECDPUN<5)
decMultiplyOp(decNumber * res,const decNumber * lhs,const decNumber * rhs,decContext * set,uInt * status)498472ac97cdSTom Musta static decNumber * decMultiplyOp(decNumber *res, const decNumber *lhs,
498572ac97cdSTom Musta const decNumber *rhs, decContext *set,
498672ac97cdSTom Musta uInt *status) {
498772ac97cdSTom Musta Int accunits; /* Units of accumulator in use */
498872ac97cdSTom Musta Int exponent; /* work */
498972ac97cdSTom Musta Int residue=0; /* rounding residue */
499072ac97cdSTom Musta uByte bits; /* result sign */
499172ac97cdSTom Musta Unit *acc; /* -> accumulator Unit array */
499272ac97cdSTom Musta Int needbytes; /* size calculator */
499372ac97cdSTom Musta void *allocacc=NULL; /* -> allocated accumulator, iff allocated */
499472ac97cdSTom Musta Unit accbuff[SD2U(DECBUFFER*4+1)]; /* buffer (+1 for DECBUFFER==0, */
499572ac97cdSTom Musta /* *4 for calls from other operations) */
499672ac97cdSTom Musta const Unit *mer, *mermsup; /* work */
499772ac97cdSTom Musta Int madlength; /* Units in multiplicand */
499872ac97cdSTom Musta Int shift; /* Units to shift multiplicand by */
499972ac97cdSTom Musta
500072ac97cdSTom Musta #if FASTMUL
500172ac97cdSTom Musta /* if DECDPUN is 1 or 3 work in base 10**9, otherwise */
500272ac97cdSTom Musta /* (DECDPUN is 2 or 4) then work in base 10**8 */
500372ac97cdSTom Musta #if DECDPUN & 1 /* odd */
500472ac97cdSTom Musta #define FASTBASE 1000000000 /* base */
500572ac97cdSTom Musta #define FASTDIGS 9 /* digits in base */
500672ac97cdSTom Musta #define FASTLAZY 18 /* carry resolution point [1->18] */
500772ac97cdSTom Musta #else
500872ac97cdSTom Musta #define FASTBASE 100000000
500972ac97cdSTom Musta #define FASTDIGS 8
501072ac97cdSTom Musta #define FASTLAZY 1844 /* carry resolution point [1->1844] */
501172ac97cdSTom Musta #endif
501272ac97cdSTom Musta /* three buffers are used, two for chunked copies of the operands */
501372ac97cdSTom Musta /* (base 10**8 or base 10**9) and one base 2**64 accumulator with */
501472ac97cdSTom Musta /* lazy carry evaluation */
501572ac97cdSTom Musta uInt zlhibuff[(DECBUFFER*2+1)/8+1]; /* buffer (+1 for DECBUFFER==0) */
501672ac97cdSTom Musta uInt *zlhi=zlhibuff; /* -> lhs array */
501772ac97cdSTom Musta uInt *alloclhi=NULL; /* -> allocated buffer, iff allocated */
501872ac97cdSTom Musta uInt zrhibuff[(DECBUFFER*2+1)/8+1]; /* buffer (+1 for DECBUFFER==0) */
501972ac97cdSTom Musta uInt *zrhi=zrhibuff; /* -> rhs array */
502072ac97cdSTom Musta uInt *allocrhi=NULL; /* -> allocated buffer, iff allocated */
502172ac97cdSTom Musta uLong zaccbuff[(DECBUFFER*2+1)/4+2]; /* buffer (+1 for DECBUFFER==0) */
502272ac97cdSTom Musta /* [allocacc is shared for both paths, as only one will run] */
502372ac97cdSTom Musta uLong *zacc=zaccbuff; /* -> accumulator array for exact result */
502472ac97cdSTom Musta #if DECDPUN==1
502572ac97cdSTom Musta Int zoff; /* accumulator offset */
502672ac97cdSTom Musta #endif
502772ac97cdSTom Musta uInt *lip, *rip; /* item pointers */
502872ac97cdSTom Musta uInt *lmsi, *rmsi; /* most significant items */
502972ac97cdSTom Musta Int ilhs, irhs, iacc; /* item counts in the arrays */
503072ac97cdSTom Musta Int lazy; /* lazy carry counter */
503172ac97cdSTom Musta uLong lcarry; /* uLong carry */
503272ac97cdSTom Musta uInt carry; /* carry (NB not uLong) */
503372ac97cdSTom Musta Int count; /* work */
503472ac97cdSTom Musta const Unit *cup; /* .. */
503572ac97cdSTom Musta Unit *up; /* .. */
503672ac97cdSTom Musta uLong *lp; /* .. */
503772ac97cdSTom Musta Int p; /* .. */
503872ac97cdSTom Musta #endif
503972ac97cdSTom Musta
504072ac97cdSTom Musta #if DECSUBSET
504172ac97cdSTom Musta decNumber *alloclhs=NULL; /* -> allocated buffer, iff allocated */
504272ac97cdSTom Musta decNumber *allocrhs=NULL; /* -> allocated buffer, iff allocated */
504372ac97cdSTom Musta #endif
504472ac97cdSTom Musta
504572ac97cdSTom Musta #if DECCHECK
504672ac97cdSTom Musta if (decCheckOperands(res, lhs, rhs, set)) return res;
504772ac97cdSTom Musta #endif
504872ac97cdSTom Musta
504972ac97cdSTom Musta /* precalculate result sign */
505072ac97cdSTom Musta bits=(uByte)((lhs->bits^rhs->bits)&DECNEG);
505172ac97cdSTom Musta
505272ac97cdSTom Musta /* handle infinities and NaNs */
505372ac97cdSTom Musta if (SPECIALARGS) { /* a special bit set */
505472ac97cdSTom Musta if (SPECIALARGS & (DECSNAN | DECNAN)) { /* one or two NaNs */
505572ac97cdSTom Musta decNaNs(res, lhs, rhs, set, status);
505672ac97cdSTom Musta return res;}
505772ac97cdSTom Musta /* one or two infinities; Infinity * 0 is invalid */
505872ac97cdSTom Musta if (((lhs->bits & DECINF)==0 && ISZERO(lhs))
505972ac97cdSTom Musta ||((rhs->bits & DECINF)==0 && ISZERO(rhs))) {
506072ac97cdSTom Musta *status|=DEC_Invalid_operation;
506172ac97cdSTom Musta return res;}
506272ac97cdSTom Musta decNumberZero(res);
506372ac97cdSTom Musta res->bits=bits|DECINF; /* infinity */
506472ac97cdSTom Musta return res;}
506572ac97cdSTom Musta
506672ac97cdSTom Musta /* For best speed, as in DMSRCN [the original Rexx numerics */
506772ac97cdSTom Musta /* module], use the shorter number as the multiplier (rhs) and */
506872ac97cdSTom Musta /* the longer as the multiplicand (lhs) to minimise the number of */
506972ac97cdSTom Musta /* adds (partial products) */
507072ac97cdSTom Musta if (lhs->digits<rhs->digits) { /* swap... */
507172ac97cdSTom Musta const decNumber *hold=lhs;
507272ac97cdSTom Musta lhs=rhs;
507372ac97cdSTom Musta rhs=hold;
507472ac97cdSTom Musta }
507572ac97cdSTom Musta
507672ac97cdSTom Musta do { /* protect allocated storage */
507772ac97cdSTom Musta #if DECSUBSET
507872ac97cdSTom Musta if (!set->extended) {
507972ac97cdSTom Musta /* reduce operands and set lostDigits status, as needed */
508072ac97cdSTom Musta if (lhs->digits>set->digits) {
508172ac97cdSTom Musta alloclhs=decRoundOperand(lhs, set, status);
508272ac97cdSTom Musta if (alloclhs==NULL) break;
508372ac97cdSTom Musta lhs=alloclhs;
508472ac97cdSTom Musta }
508572ac97cdSTom Musta if (rhs->digits>set->digits) {
508672ac97cdSTom Musta allocrhs=decRoundOperand(rhs, set, status);
508772ac97cdSTom Musta if (allocrhs==NULL) break;
508872ac97cdSTom Musta rhs=allocrhs;
508972ac97cdSTom Musta }
509072ac97cdSTom Musta }
509172ac97cdSTom Musta #endif
509272ac97cdSTom Musta /* [following code does not require input rounding] */
509372ac97cdSTom Musta
509472ac97cdSTom Musta #if FASTMUL /* fastpath can be used */
509572ac97cdSTom Musta /* use the fast path if there are enough digits in the shorter */
509672ac97cdSTom Musta /* operand to make the setup and takedown worthwhile */
509772ac97cdSTom Musta #define NEEDTWO (DECDPUN*2) /* within two decUnitAddSub calls */
509872ac97cdSTom Musta if (rhs->digits>NEEDTWO) { /* use fastpath... */
509972ac97cdSTom Musta /* calculate the number of elements in each array */
510072ac97cdSTom Musta ilhs=(lhs->digits+FASTDIGS-1)/FASTDIGS; /* [ceiling] */
510172ac97cdSTom Musta irhs=(rhs->digits+FASTDIGS-1)/FASTDIGS; /* .. */
510272ac97cdSTom Musta iacc=ilhs+irhs;
510372ac97cdSTom Musta
510472ac97cdSTom Musta /* allocate buffers if required, as usual */
510572ac97cdSTom Musta needbytes=ilhs*sizeof(uInt);
510672ac97cdSTom Musta if (needbytes>(Int)sizeof(zlhibuff)) {
510772ac97cdSTom Musta alloclhi=(uInt *)malloc(needbytes);
510872ac97cdSTom Musta zlhi=alloclhi;}
510972ac97cdSTom Musta needbytes=irhs*sizeof(uInt);
511072ac97cdSTom Musta if (needbytes>(Int)sizeof(zrhibuff)) {
511172ac97cdSTom Musta allocrhi=(uInt *)malloc(needbytes);
511272ac97cdSTom Musta zrhi=allocrhi;}
511372ac97cdSTom Musta
511472ac97cdSTom Musta /* Allocating the accumulator space needs a special case when */
511572ac97cdSTom Musta /* DECDPUN=1 because when converting the accumulator to Units */
511672ac97cdSTom Musta /* after the multiplication each 8-byte item becomes 9 1-byte */
511772ac97cdSTom Musta /* units. Therefore iacc extra bytes are needed at the front */
511872ac97cdSTom Musta /* (rounded up to a multiple of 8 bytes), and the uLong */
511972ac97cdSTom Musta /* accumulator starts offset the appropriate number of units */
512072ac97cdSTom Musta /* to the right to avoid overwrite during the unchunking. */
512172ac97cdSTom Musta needbytes=iacc*sizeof(uLong);
512272ac97cdSTom Musta #if DECDPUN==1
512372ac97cdSTom Musta zoff=(iacc+7)/8; /* items to offset by */
512472ac97cdSTom Musta needbytes+=zoff*8;
512572ac97cdSTom Musta #endif
512672ac97cdSTom Musta if (needbytes>(Int)sizeof(zaccbuff)) {
512772ac97cdSTom Musta allocacc=(uLong *)malloc(needbytes);
512872ac97cdSTom Musta zacc=(uLong *)allocacc;}
512972ac97cdSTom Musta if (zlhi==NULL||zrhi==NULL||zacc==NULL) {
513072ac97cdSTom Musta *status|=DEC_Insufficient_storage;
513172ac97cdSTom Musta break;}
513272ac97cdSTom Musta
513372ac97cdSTom Musta acc=(Unit *)zacc; /* -> target Unit array */
513472ac97cdSTom Musta #if DECDPUN==1
513572ac97cdSTom Musta zacc+=zoff; /* start uLong accumulator to right */
513672ac97cdSTom Musta #endif
513772ac97cdSTom Musta
513872ac97cdSTom Musta /* assemble the chunked copies of the left and right sides */
513972ac97cdSTom Musta for (count=lhs->digits, cup=lhs->lsu, lip=zlhi; count>0; lip++)
514072ac97cdSTom Musta for (p=0, *lip=0; p<FASTDIGS && count>0;
514172ac97cdSTom Musta p+=DECDPUN, cup++, count-=DECDPUN)
514272ac97cdSTom Musta *lip+=*cup*powers[p];
514372ac97cdSTom Musta lmsi=lip-1; /* save -> msi */
514472ac97cdSTom Musta for (count=rhs->digits, cup=rhs->lsu, rip=zrhi; count>0; rip++)
514572ac97cdSTom Musta for (p=0, *rip=0; p<FASTDIGS && count>0;
514672ac97cdSTom Musta p+=DECDPUN, cup++, count-=DECDPUN)
514772ac97cdSTom Musta *rip+=*cup*powers[p];
514872ac97cdSTom Musta rmsi=rip-1; /* save -> msi */
514972ac97cdSTom Musta
515072ac97cdSTom Musta /* zero the accumulator */
515172ac97cdSTom Musta for (lp=zacc; lp<zacc+iacc; lp++) *lp=0;
515272ac97cdSTom Musta
515372ac97cdSTom Musta /* Start the multiplication */
515472ac97cdSTom Musta /* Resolving carries can dominate the cost of accumulating the */
515572ac97cdSTom Musta /* partial products, so this is only done when necessary. */
515672ac97cdSTom Musta /* Each uLong item in the accumulator can hold values up to */
515772ac97cdSTom Musta /* 2**64-1, and each partial product can be as large as */
515872ac97cdSTom Musta /* (10**FASTDIGS-1)**2. When FASTDIGS=9, this can be added to */
515972ac97cdSTom Musta /* itself 18.4 times in a uLong without overflowing, so during */
516072ac97cdSTom Musta /* the main calculation resolution is carried out every 18th */
516172ac97cdSTom Musta /* add -- every 162 digits. Similarly, when FASTDIGS=8, the */
516272ac97cdSTom Musta /* partial products can be added to themselves 1844.6 times in */
516372ac97cdSTom Musta /* a uLong without overflowing, so intermediate carry */
516472ac97cdSTom Musta /* resolution occurs only every 14752 digits. Hence for common */
516572ac97cdSTom Musta /* short numbers usually only the one final carry resolution */
516672ac97cdSTom Musta /* occurs. */
516772ac97cdSTom Musta /* (The count is set via FASTLAZY to simplify experiments to */
516872ac97cdSTom Musta /* measure the value of this approach: a 35% improvement on a */
516972ac97cdSTom Musta /* [34x34] multiply.) */
517072ac97cdSTom Musta lazy=FASTLAZY; /* carry delay count */
517172ac97cdSTom Musta for (rip=zrhi; rip<=rmsi; rip++) { /* over each item in rhs */
517272ac97cdSTom Musta lp=zacc+(rip-zrhi); /* where to add the lhs */
517372ac97cdSTom Musta for (lip=zlhi; lip<=lmsi; lip++, lp++) { /* over each item in lhs */
517472ac97cdSTom Musta *lp+=(uLong)(*lip)*(*rip); /* [this should in-line] */
517572ac97cdSTom Musta } /* lip loop */
517672ac97cdSTom Musta lazy--;
517772ac97cdSTom Musta if (lazy>0 && rip!=rmsi) continue;
517872ac97cdSTom Musta lazy=FASTLAZY; /* reset delay count */
517972ac97cdSTom Musta /* spin up the accumulator resolving overflows */
518072ac97cdSTom Musta for (lp=zacc; lp<zacc+iacc; lp++) {
518172ac97cdSTom Musta if (*lp<FASTBASE) continue; /* it fits */
518272ac97cdSTom Musta lcarry=*lp/FASTBASE; /* top part [slow divide] */
518372ac97cdSTom Musta /* lcarry can exceed 2**32-1, so check again; this check */
518472ac97cdSTom Musta /* and occasional extra divide (slow) is well worth it, as */
518572ac97cdSTom Musta /* it allows FASTLAZY to be increased to 18 rather than 4 */
518672ac97cdSTom Musta /* in the FASTDIGS=9 case */
518772ac97cdSTom Musta if (lcarry<FASTBASE) carry=(uInt)lcarry; /* [usual] */
518872ac97cdSTom Musta else { /* two-place carry [fairly rare] */
518972ac97cdSTom Musta uInt carry2=(uInt)(lcarry/FASTBASE); /* top top part */
519072ac97cdSTom Musta *(lp+2)+=carry2; /* add to item+2 */
519172ac97cdSTom Musta *lp-=((uLong)FASTBASE*FASTBASE*carry2); /* [slow] */
519272ac97cdSTom Musta carry=(uInt)(lcarry-((uLong)FASTBASE*carry2)); /* [inline] */
519372ac97cdSTom Musta }
519472ac97cdSTom Musta *(lp+1)+=carry; /* add to item above [inline] */
519572ac97cdSTom Musta *lp-=((uLong)FASTBASE*carry); /* [inline] */
519672ac97cdSTom Musta } /* carry resolution */
519772ac97cdSTom Musta } /* rip loop */
519872ac97cdSTom Musta
519972ac97cdSTom Musta /* The multiplication is complete; time to convert back into */
520072ac97cdSTom Musta /* units. This can be done in-place in the accumulator and in */
520172ac97cdSTom Musta /* 32-bit operations, because carries were resolved after the */
520272ac97cdSTom Musta /* final add. This needs N-1 divides and multiplies for */
520372ac97cdSTom Musta /* each item in the accumulator (which will become up to N */
520472ac97cdSTom Musta /* units, where 2<=N<=9). */
520572ac97cdSTom Musta for (lp=zacc, up=acc; lp<zacc+iacc; lp++) {
520672ac97cdSTom Musta uInt item=(uInt)*lp; /* decapitate to uInt */
520772ac97cdSTom Musta for (p=0; p<FASTDIGS-DECDPUN; p+=DECDPUN, up++) {
520872ac97cdSTom Musta uInt part=item/(DECDPUNMAX+1);
520972ac97cdSTom Musta *up=(Unit)(item-(part*(DECDPUNMAX+1)));
521072ac97cdSTom Musta item=part;
521172ac97cdSTom Musta } /* p */
521272ac97cdSTom Musta *up=(Unit)item; up++; /* [final needs no division] */
521372ac97cdSTom Musta } /* lp */
521472ac97cdSTom Musta accunits=up-acc; /* count of units */
521572ac97cdSTom Musta }
521672ac97cdSTom Musta else { /* here to use units directly, without chunking ['old code'] */
521772ac97cdSTom Musta #endif
521872ac97cdSTom Musta
521972ac97cdSTom Musta /* if accumulator will be too long for local storage, then allocate */
522072ac97cdSTom Musta acc=accbuff; /* -> assume buffer for accumulator */
522172ac97cdSTom Musta needbytes=(D2U(lhs->digits)+D2U(rhs->digits))*sizeof(Unit);
522272ac97cdSTom Musta if (needbytes>(Int)sizeof(accbuff)) {
522372ac97cdSTom Musta allocacc=(Unit *)malloc(needbytes);
522472ac97cdSTom Musta if (allocacc==NULL) {*status|=DEC_Insufficient_storage; break;}
522572ac97cdSTom Musta acc=(Unit *)allocacc; /* use the allocated space */
522672ac97cdSTom Musta }
522772ac97cdSTom Musta
522872ac97cdSTom Musta /* Now the main long multiplication loop */
522972ac97cdSTom Musta /* Unlike the equivalent in the IBM Java implementation, there */
523072ac97cdSTom Musta /* is no advantage in calculating from msu to lsu. So, do it */
523172ac97cdSTom Musta /* by the book, as it were. */
523272ac97cdSTom Musta /* Each iteration calculates ACC=ACC+MULTAND*MULT */
523372ac97cdSTom Musta accunits=1; /* accumulator starts at '0' */
523472ac97cdSTom Musta *acc=0; /* .. (lsu=0) */
523572ac97cdSTom Musta shift=0; /* no multiplicand shift at first */
523672ac97cdSTom Musta madlength=D2U(lhs->digits); /* this won't change */
523772ac97cdSTom Musta mermsup=rhs->lsu+D2U(rhs->digits); /* -> msu+1 of multiplier */
523872ac97cdSTom Musta
523972ac97cdSTom Musta for (mer=rhs->lsu; mer<mermsup; mer++) {
524072ac97cdSTom Musta /* Here, *mer is the next Unit in the multiplier to use */
524172ac97cdSTom Musta /* If non-zero [optimization] add it... */
524272ac97cdSTom Musta if (*mer!=0) accunits=decUnitAddSub(&acc[shift], accunits-shift,
524372ac97cdSTom Musta lhs->lsu, madlength, 0,
524472ac97cdSTom Musta &acc[shift], *mer)
524572ac97cdSTom Musta + shift;
524672ac97cdSTom Musta else { /* extend acc with a 0; it will be used shortly */
524772ac97cdSTom Musta *(acc+accunits)=0; /* [this avoids length of <=0 later] */
524872ac97cdSTom Musta accunits++;
524972ac97cdSTom Musta }
525072ac97cdSTom Musta /* multiply multiplicand by 10**DECDPUN for next Unit to left */
525172ac97cdSTom Musta shift++; /* add this for 'logical length' */
525272ac97cdSTom Musta } /* n */
525372ac97cdSTom Musta #if FASTMUL
525472ac97cdSTom Musta } /* unchunked units */
525572ac97cdSTom Musta #endif
525672ac97cdSTom Musta /* common end-path */
525772ac97cdSTom Musta #if DECTRACE
525872ac97cdSTom Musta decDumpAr('*', acc, accunits); /* Show exact result */
525972ac97cdSTom Musta #endif
526072ac97cdSTom Musta
526172ac97cdSTom Musta /* acc now contains the exact result of the multiplication, */
526272ac97cdSTom Musta /* possibly with a leading zero unit; build the decNumber from */
526372ac97cdSTom Musta /* it, noting if any residue */
526472ac97cdSTom Musta res->bits=bits; /* set sign */
526572ac97cdSTom Musta res->digits=decGetDigits(acc, accunits); /* count digits exactly */
526672ac97cdSTom Musta
526772ac97cdSTom Musta /* There can be a 31-bit wrap in calculating the exponent. */
526872ac97cdSTom Musta /* This can only happen if both input exponents are negative and */
526972ac97cdSTom Musta /* both their magnitudes are large. If there was a wrap, set a */
527072ac97cdSTom Musta /* safe very negative exponent, from which decFinalize() will */
527172ac97cdSTom Musta /* raise a hard underflow shortly. */
527272ac97cdSTom Musta exponent=lhs->exponent+rhs->exponent; /* calculate exponent */
527372ac97cdSTom Musta if (lhs->exponent<0 && rhs->exponent<0 && exponent>0)
527472ac97cdSTom Musta exponent=-2*DECNUMMAXE; /* force underflow */
527572ac97cdSTom Musta res->exponent=exponent; /* OK to overwrite now */
527672ac97cdSTom Musta
527772ac97cdSTom Musta
527872ac97cdSTom Musta /* Set the coefficient. If any rounding, residue records */
527972ac97cdSTom Musta decSetCoeff(res, set, acc, res->digits, &residue, status);
528072ac97cdSTom Musta decFinish(res, set, &residue, status); /* final cleanup */
528172ac97cdSTom Musta } while(0); /* end protected */
528272ac97cdSTom Musta
528372ac97cdSTom Musta if (allocacc!=NULL) free(allocacc); /* drop any storage used */
528472ac97cdSTom Musta #if DECSUBSET
528572ac97cdSTom Musta if (allocrhs!=NULL) free(allocrhs); /* .. */
528672ac97cdSTom Musta if (alloclhs!=NULL) free(alloclhs); /* .. */
528772ac97cdSTom Musta #endif
528872ac97cdSTom Musta #if FASTMUL
528972ac97cdSTom Musta if (allocrhi!=NULL) free(allocrhi); /* .. */
529072ac97cdSTom Musta if (alloclhi!=NULL) free(alloclhi); /* .. */
529172ac97cdSTom Musta #endif
529272ac97cdSTom Musta return res;
529372ac97cdSTom Musta } /* decMultiplyOp */
529472ac97cdSTom Musta
529572ac97cdSTom Musta /* ------------------------------------------------------------------ */
529672ac97cdSTom Musta /* decExpOp -- effect exponentiation */
529772ac97cdSTom Musta /* */
529872ac97cdSTom Musta /* This computes C = exp(A) */
529972ac97cdSTom Musta /* */
530072ac97cdSTom Musta /* res is C, the result. C may be A */
530172ac97cdSTom Musta /* rhs is A */
530272ac97cdSTom Musta /* set is the context; note that rounding mode has no effect */
530372ac97cdSTom Musta /* */
530472ac97cdSTom Musta /* C must have space for set->digits digits. status is updated but */
530572ac97cdSTom Musta /* not set. */
530672ac97cdSTom Musta /* */
530772ac97cdSTom Musta /* Restrictions: */
530872ac97cdSTom Musta /* */
530972ac97cdSTom Musta /* digits, emax, and -emin in the context must be less than */
531072ac97cdSTom Musta /* 2*DEC_MAX_MATH (1999998), and the rhs must be within these */
531172ac97cdSTom Musta /* bounds or a zero. This is an internal routine, so these */
531272ac97cdSTom Musta /* restrictions are contractual and not enforced. */
531372ac97cdSTom Musta /* */
531472ac97cdSTom Musta /* A finite result is rounded using DEC_ROUND_HALF_EVEN; it will */
531572ac97cdSTom Musta /* almost always be correctly rounded, but may be up to 1 ulp in */
531672ac97cdSTom Musta /* error in rare cases. */
531772ac97cdSTom Musta /* */
531872ac97cdSTom Musta /* Finite results will always be full precision and Inexact, except */
531972ac97cdSTom Musta /* when A is a zero or -Infinity (giving 1 or 0 respectively). */
532072ac97cdSTom Musta /* ------------------------------------------------------------------ */
532172ac97cdSTom Musta /* This approach used here is similar to the algorithm described in */
532272ac97cdSTom Musta /* */
532372ac97cdSTom Musta /* Variable Precision Exponential Function, T. E. Hull and */
532472ac97cdSTom Musta /* A. Abrham, ACM Transactions on Mathematical Software, Vol 12 #2, */
532572ac97cdSTom Musta /* pp79-91, ACM, June 1986. */
532672ac97cdSTom Musta /* */
532772ac97cdSTom Musta /* with the main difference being that the iterations in the series */
532872ac97cdSTom Musta /* evaluation are terminated dynamically (which does not require the */
532972ac97cdSTom Musta /* extra variable-precision variables which are expensive in this */
533072ac97cdSTom Musta /* context). */
533172ac97cdSTom Musta /* */
533272ac97cdSTom Musta /* The error analysis in Hull & Abrham's paper applies except for the */
533372ac97cdSTom Musta /* round-off error accumulation during the series evaluation. This */
533472ac97cdSTom Musta /* code does not precalculate the number of iterations and so cannot */
533572ac97cdSTom Musta /* use Horner's scheme. Instead, the accumulation is done at double- */
533672ac97cdSTom Musta /* precision, which ensures that the additions of the terms are exact */
533772ac97cdSTom Musta /* and do not accumulate round-off (and any round-off errors in the */
533872ac97cdSTom Musta /* terms themselves move 'to the right' faster than they can */
533972ac97cdSTom Musta /* accumulate). This code also extends the calculation by allowing, */
534072ac97cdSTom Musta /* in the spirit of other decNumber operators, the input to be more */
534172ac97cdSTom Musta /* precise than the result (the precision used is based on the more */
534272ac97cdSTom Musta /* precise of the input or requested result). */
534372ac97cdSTom Musta /* */
534472ac97cdSTom Musta /* Implementation notes: */
534572ac97cdSTom Musta /* */
534672ac97cdSTom Musta /* 1. This is separated out as decExpOp so it can be called from */
534772ac97cdSTom Musta /* other Mathematical functions (notably Ln) with a wider range */
534872ac97cdSTom Musta /* than normal. In particular, it can handle the slightly wider */
534972ac97cdSTom Musta /* (double) range needed by Ln (which has to be able to calculate */
535072ac97cdSTom Musta /* exp(-x) where x can be the tiniest number (Ntiny). */
535172ac97cdSTom Musta /* */
535272ac97cdSTom Musta /* 2. Normalizing x to be <=0.1 (instead of <=1) reduces loop */
535367cc32ebSVeres Lajos /* iterations by approximately a third with additional (although */
535472ac97cdSTom Musta /* diminishing) returns as the range is reduced to even smaller */
535572ac97cdSTom Musta /* fractions. However, h (the power of 10 used to correct the */
535672ac97cdSTom Musta /* result at the end, see below) must be kept <=8 as otherwise */
535772ac97cdSTom Musta /* the final result cannot be computed. Hence the leverage is a */
535872ac97cdSTom Musta /* sliding value (8-h), where potentially the range is reduced */
535972ac97cdSTom Musta /* more for smaller values. */
536072ac97cdSTom Musta /* */
536172ac97cdSTom Musta /* The leverage that can be applied in this way is severely */
536272ac97cdSTom Musta /* limited by the cost of the raise-to-the power at the end, */
536372ac97cdSTom Musta /* which dominates when the number of iterations is small (less */
536472ac97cdSTom Musta /* than ten) or when rhs is short. As an example, the adjustment */
536572ac97cdSTom Musta /* x**10,000,000 needs 31 multiplications, all but one full-width. */
536672ac97cdSTom Musta /* */
536772ac97cdSTom Musta /* 3. The restrictions (especially precision) could be raised with */
536872ac97cdSTom Musta /* care, but the full decNumber range seems very hard within the */
536972ac97cdSTom Musta /* 32-bit limits. */
537072ac97cdSTom Musta /* */
537172ac97cdSTom Musta /* 4. The working precisions for the static buffers are twice the */
537272ac97cdSTom Musta /* obvious size to allow for calls from decNumberPower. */
537372ac97cdSTom Musta /* ------------------------------------------------------------------ */
decExpOp(decNumber * res,const decNumber * rhs,decContext * set,uInt * status)5374d072cdf3SStefan Weil static decNumber *decExpOp(decNumber *res, const decNumber *rhs,
537572ac97cdSTom Musta decContext *set, uInt *status) {
537672ac97cdSTom Musta uInt ignore=0; /* working status */
537772ac97cdSTom Musta Int h; /* adjusted exponent for 0.xxxx */
537872ac97cdSTom Musta Int p; /* working precision */
537972ac97cdSTom Musta Int residue; /* rounding residue */
538072ac97cdSTom Musta uInt needbytes; /* for space calculations */
538172ac97cdSTom Musta const decNumber *x=rhs; /* (may point to safe copy later) */
538272ac97cdSTom Musta decContext aset, tset, dset; /* working contexts */
538372ac97cdSTom Musta Int comp; /* work */
538472ac97cdSTom Musta
538572ac97cdSTom Musta /* the argument is often copied to normalize it, so (unusually) it */
538672ac97cdSTom Musta /* is treated like other buffers, using DECBUFFER, +1 in case */
538772ac97cdSTom Musta /* DECBUFFER is 0 */
538872ac97cdSTom Musta decNumber bufr[D2N(DECBUFFER*2+1)];
538972ac97cdSTom Musta decNumber *allocrhs=NULL; /* non-NULL if rhs buffer allocated */
539072ac97cdSTom Musta
539172ac97cdSTom Musta /* the working precision will be no more than set->digits+8+1 */
539272ac97cdSTom Musta /* so for on-stack buffers DECBUFFER+9 is used, +1 in case DECBUFFER */
539372ac97cdSTom Musta /* is 0 (and twice that for the accumulator) */
539472ac97cdSTom Musta
539572ac97cdSTom Musta /* buffer for t, term (working precision plus) */
539672ac97cdSTom Musta decNumber buft[D2N(DECBUFFER*2+9+1)];
539772ac97cdSTom Musta decNumber *allocbuft=NULL; /* -> allocated buft, iff allocated */
539872ac97cdSTom Musta decNumber *t=buft; /* term */
539972ac97cdSTom Musta /* buffer for a, accumulator (working precision * 2), at least 9 */
540072ac97cdSTom Musta decNumber bufa[D2N(DECBUFFER*4+18+1)];
540172ac97cdSTom Musta decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
540272ac97cdSTom Musta decNumber *a=bufa; /* accumulator */
540372ac97cdSTom Musta /* decNumber for the divisor term; this needs at most 9 digits */
540472ac97cdSTom Musta /* and so can be fixed size [16 so can use standard context] */
540572ac97cdSTom Musta decNumber bufd[D2N(16)];
540672ac97cdSTom Musta decNumber *d=bufd; /* divisor */
540772ac97cdSTom Musta decNumber numone; /* constant 1 */
540872ac97cdSTom Musta
540972ac97cdSTom Musta #if DECCHECK
541072ac97cdSTom Musta Int iterations=0; /* for later sanity check */
541172ac97cdSTom Musta if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
541272ac97cdSTom Musta #endif
541372ac97cdSTom Musta
541472ac97cdSTom Musta do { /* protect allocated storage */
541572ac97cdSTom Musta if (SPECIALARG) { /* handle infinities and NaNs */
541672ac97cdSTom Musta if (decNumberIsInfinite(rhs)) { /* an infinity */
541772ac97cdSTom Musta if (decNumberIsNegative(rhs)) /* -Infinity -> +0 */
541872ac97cdSTom Musta decNumberZero(res);
541972ac97cdSTom Musta else decNumberCopy(res, rhs); /* +Infinity -> self */
542072ac97cdSTom Musta }
542172ac97cdSTom Musta else decNaNs(res, rhs, NULL, set, status); /* a NaN */
542272ac97cdSTom Musta break;}
542372ac97cdSTom Musta
542472ac97cdSTom Musta if (ISZERO(rhs)) { /* zeros -> exact 1 */
542572ac97cdSTom Musta decNumberZero(res); /* make clean 1 */
542672ac97cdSTom Musta *res->lsu=1; /* .. */
542772ac97cdSTom Musta break;} /* [no status to set] */
542872ac97cdSTom Musta
542972ac97cdSTom Musta /* e**x when 0 < x < 0.66 is < 1+3x/2, hence can fast-path */
543072ac97cdSTom Musta /* positive and negative tiny cases which will result in inexact */
543172ac97cdSTom Musta /* 1. This also allows the later add-accumulate to always be */
543272ac97cdSTom Musta /* exact (because its length will never be more than twice the */
543372ac97cdSTom Musta /* working precision). */
543472ac97cdSTom Musta /* The comparator (tiny) needs just one digit, so use the */
543572ac97cdSTom Musta /* decNumber d for it (reused as the divisor, etc., below); its */
543672ac97cdSTom Musta /* exponent is such that if x is positive it will have */
543772ac97cdSTom Musta /* set->digits-1 zeros between the decimal point and the digit, */
543872ac97cdSTom Musta /* which is 4, and if x is negative one more zero there as the */
543972ac97cdSTom Musta /* more precise result will be of the form 0.9999999 rather than */
544072ac97cdSTom Musta /* 1.0000001. Hence, tiny will be 0.0000004 if digits=7 and x>0 */
544172ac97cdSTom Musta /* or 0.00000004 if digits=7 and x<0. If RHS not larger than */
544272ac97cdSTom Musta /* this then the result will be 1.000000 */
544372ac97cdSTom Musta decNumberZero(d); /* clean */
544472ac97cdSTom Musta *d->lsu=4; /* set 4 .. */
544572ac97cdSTom Musta d->exponent=-set->digits; /* * 10**(-d) */
544672ac97cdSTom Musta if (decNumberIsNegative(rhs)) d->exponent--; /* negative case */
544772ac97cdSTom Musta comp=decCompare(d, rhs, 1); /* signless compare */
544872ac97cdSTom Musta if (comp==BADINT) {
544972ac97cdSTom Musta *status|=DEC_Insufficient_storage;
545072ac97cdSTom Musta break;}
545172ac97cdSTom Musta if (comp>=0) { /* rhs < d */
545272ac97cdSTom Musta Int shift=set->digits-1;
545372ac97cdSTom Musta decNumberZero(res); /* set 1 */
545472ac97cdSTom Musta *res->lsu=1; /* .. */
545572ac97cdSTom Musta res->digits=decShiftToMost(res->lsu, 1, shift);
545672ac97cdSTom Musta res->exponent=-shift; /* make 1.0000... */
545772ac97cdSTom Musta *status|=DEC_Inexact | DEC_Rounded; /* .. inexactly */
545872ac97cdSTom Musta break;} /* tiny */
545972ac97cdSTom Musta
546072ac97cdSTom Musta /* set up the context to be used for calculating a, as this is */
546172ac97cdSTom Musta /* used on both paths below */
546272ac97cdSTom Musta decContextDefault(&aset, DEC_INIT_DECIMAL64);
546372ac97cdSTom Musta /* accumulator bounds are as requested (could underflow) */
546472ac97cdSTom Musta aset.emax=set->emax; /* usual bounds */
546572ac97cdSTom Musta aset.emin=set->emin; /* .. */
546672ac97cdSTom Musta aset.clamp=0; /* and no concrete format */
546772ac97cdSTom Musta
546872ac97cdSTom Musta /* calculate the adjusted (Hull & Abrham) exponent (where the */
546972ac97cdSTom Musta /* decimal point is just to the left of the coefficient msd) */
547072ac97cdSTom Musta h=rhs->exponent+rhs->digits;
547172ac97cdSTom Musta /* if h>8 then 10**h cannot be calculated safely; however, when */
547272ac97cdSTom Musta /* h=8 then exp(|rhs|) will be at least exp(1E+7) which is at */
547372ac97cdSTom Musta /* least 6.59E+4342944, so (due to the restriction on Emax/Emin) */
547472ac97cdSTom Musta /* overflow (or underflow to 0) is guaranteed -- so this case can */
547572ac97cdSTom Musta /* be handled by simply forcing the appropriate excess */
547672ac97cdSTom Musta if (h>8) { /* overflow/underflow */
547772ac97cdSTom Musta /* set up here so Power call below will over or underflow to */
547872ac97cdSTom Musta /* zero; set accumulator to either 2 or 0.02 */
547972ac97cdSTom Musta /* [stack buffer for a is always big enough for this] */
548072ac97cdSTom Musta decNumberZero(a);
548172ac97cdSTom Musta *a->lsu=2; /* not 1 but < exp(1) */
548272ac97cdSTom Musta if (decNumberIsNegative(rhs)) a->exponent=-2; /* make 0.02 */
548372ac97cdSTom Musta h=8; /* clamp so 10**h computable */
548472ac97cdSTom Musta p=9; /* set a working precision */
548572ac97cdSTom Musta }
548672ac97cdSTom Musta else { /* h<=8 */
548772ac97cdSTom Musta Int maxlever=(rhs->digits>8?1:0);
548872ac97cdSTom Musta /* [could/should increase this for precisions >40 or so, too] */
548972ac97cdSTom Musta
549072ac97cdSTom Musta /* if h is 8, cannot normalize to a lower upper limit because */
549172ac97cdSTom Musta /* the final result will not be computable (see notes above), */
549272ac97cdSTom Musta /* but leverage can be applied whenever h is less than 8. */
549372ac97cdSTom Musta /* Apply as much as possible, up to a MAXLEVER digits, which */
549472ac97cdSTom Musta /* sets the tradeoff against the cost of the later a**(10**h). */
549572ac97cdSTom Musta /* As h is increased, the working precision below also */
549672ac97cdSTom Musta /* increases to compensate for the "constant digits at the */
549772ac97cdSTom Musta /* front" effect. */
549872ac97cdSTom Musta Int lever=MINI(8-h, maxlever); /* leverage attainable */
549972ac97cdSTom Musta Int use=-rhs->digits-lever; /* exponent to use for RHS */
550072ac97cdSTom Musta h+=lever; /* apply leverage selected */
550172ac97cdSTom Musta if (h<0) { /* clamp */
550272ac97cdSTom Musta use+=h; /* [may end up subnormal] */
550372ac97cdSTom Musta h=0;
550472ac97cdSTom Musta }
550572ac97cdSTom Musta /* Take a copy of RHS if it needs normalization (true whenever x>=1) */
550672ac97cdSTom Musta if (rhs->exponent!=use) {
550772ac97cdSTom Musta decNumber *newrhs=bufr; /* assume will fit on stack */
550872ac97cdSTom Musta needbytes=sizeof(decNumber)+(D2U(rhs->digits)-1)*sizeof(Unit);
550972ac97cdSTom Musta if (needbytes>sizeof(bufr)) { /* need malloc space */
551072ac97cdSTom Musta allocrhs=(decNumber *)malloc(needbytes);
551172ac97cdSTom Musta if (allocrhs==NULL) { /* hopeless -- abandon */
551272ac97cdSTom Musta *status|=DEC_Insufficient_storage;
551372ac97cdSTom Musta break;}
551472ac97cdSTom Musta newrhs=allocrhs; /* use the allocated space */
551572ac97cdSTom Musta }
551672ac97cdSTom Musta decNumberCopy(newrhs, rhs); /* copy to safe space */
551772ac97cdSTom Musta newrhs->exponent=use; /* normalize; now <1 */
551872ac97cdSTom Musta x=newrhs; /* ready for use */
551972ac97cdSTom Musta /* decNumberShow(x); */
552072ac97cdSTom Musta }
552172ac97cdSTom Musta
552272ac97cdSTom Musta /* Now use the usual power series to evaluate exp(x). The */
552372ac97cdSTom Musta /* series starts as 1 + x + x^2/2 ... so prime ready for the */
552472ac97cdSTom Musta /* third term by setting the term variable t=x, the accumulator */
552572ac97cdSTom Musta /* a=1, and the divisor d=2. */
552672ac97cdSTom Musta
552772ac97cdSTom Musta /* First determine the working precision. From Hull & Abrham */
552872ac97cdSTom Musta /* this is set->digits+h+2. However, if x is 'over-precise' we */
552972ac97cdSTom Musta /* need to allow for all its digits to potentially participate */
553072ac97cdSTom Musta /* (consider an x where all the excess digits are 9s) so in */
553172ac97cdSTom Musta /* this case use x->digits+h+2 */
553272ac97cdSTom Musta p=MAXI(x->digits, set->digits)+h+2; /* [h<=8] */
553372ac97cdSTom Musta
553472ac97cdSTom Musta /* a and t are variable precision, and depend on p, so space */
553572ac97cdSTom Musta /* must be allocated for them if necessary */
553672ac97cdSTom Musta
553772ac97cdSTom Musta /* the accumulator needs to be able to hold 2p digits so that */
553872ac97cdSTom Musta /* the additions on the second and subsequent iterations are */
553972ac97cdSTom Musta /* sufficiently exact. */
554072ac97cdSTom Musta needbytes=sizeof(decNumber)+(D2U(p*2)-1)*sizeof(Unit);
554172ac97cdSTom Musta if (needbytes>sizeof(bufa)) { /* need malloc space */
554272ac97cdSTom Musta allocbufa=(decNumber *)malloc(needbytes);
554372ac97cdSTom Musta if (allocbufa==NULL) { /* hopeless -- abandon */
554472ac97cdSTom Musta *status|=DEC_Insufficient_storage;
554572ac97cdSTom Musta break;}
554672ac97cdSTom Musta a=allocbufa; /* use the allocated space */
554772ac97cdSTom Musta }
554872ac97cdSTom Musta /* the term needs to be able to hold p digits (which is */
554972ac97cdSTom Musta /* guaranteed to be larger than x->digits, so the initial copy */
555072ac97cdSTom Musta /* is safe); it may also be used for the raise-to-power */
555172ac97cdSTom Musta /* calculation below, which needs an extra two digits */
555272ac97cdSTom Musta needbytes=sizeof(decNumber)+(D2U(p+2)-1)*sizeof(Unit);
555372ac97cdSTom Musta if (needbytes>sizeof(buft)) { /* need malloc space */
555472ac97cdSTom Musta allocbuft=(decNumber *)malloc(needbytes);
555572ac97cdSTom Musta if (allocbuft==NULL) { /* hopeless -- abandon */
555672ac97cdSTom Musta *status|=DEC_Insufficient_storage;
555772ac97cdSTom Musta break;}
555872ac97cdSTom Musta t=allocbuft; /* use the allocated space */
555972ac97cdSTom Musta }
556072ac97cdSTom Musta
556172ac97cdSTom Musta decNumberCopy(t, x); /* term=x */
556272ac97cdSTom Musta decNumberZero(a); *a->lsu=1; /* accumulator=1 */
556372ac97cdSTom Musta decNumberZero(d); *d->lsu=2; /* divisor=2 */
556472ac97cdSTom Musta decNumberZero(&numone); *numone.lsu=1; /* constant 1 for increment */
556572ac97cdSTom Musta
556672ac97cdSTom Musta /* set up the contexts for calculating a, t, and d */
556772ac97cdSTom Musta decContextDefault(&tset, DEC_INIT_DECIMAL64);
556872ac97cdSTom Musta dset=tset;
556972ac97cdSTom Musta /* accumulator bounds are set above, set precision now */
557072ac97cdSTom Musta aset.digits=p*2; /* double */
557172ac97cdSTom Musta /* term bounds avoid any underflow or overflow */
557272ac97cdSTom Musta tset.digits=p;
557372ac97cdSTom Musta tset.emin=DEC_MIN_EMIN; /* [emax is plenty] */
557472ac97cdSTom Musta /* [dset.digits=16, etc., are sufficient] */
557572ac97cdSTom Musta
557672ac97cdSTom Musta /* finally ready to roll */
557772ac97cdSTom Musta for (;;) {
557872ac97cdSTom Musta #if DECCHECK
557972ac97cdSTom Musta iterations++;
558072ac97cdSTom Musta #endif
558172ac97cdSTom Musta /* only the status from the accumulation is interesting */
558272ac97cdSTom Musta /* [but it should remain unchanged after first add] */
558372ac97cdSTom Musta decAddOp(a, a, t, &aset, 0, status); /* a=a+t */
558472ac97cdSTom Musta decMultiplyOp(t, t, x, &tset, &ignore); /* t=t*x */
558572ac97cdSTom Musta decDivideOp(t, t, d, &tset, DIVIDE, &ignore); /* t=t/d */
558672ac97cdSTom Musta /* the iteration ends when the term cannot affect the result, */
558772ac97cdSTom Musta /* if rounded to p digits, which is when its value is smaller */
558872ac97cdSTom Musta /* than the accumulator by p+1 digits. There must also be */
558972ac97cdSTom Musta /* full precision in a. */
559072ac97cdSTom Musta if (((a->digits+a->exponent)>=(t->digits+t->exponent+p+1))
559172ac97cdSTom Musta && (a->digits>=p)) break;
559272ac97cdSTom Musta decAddOp(d, d, &numone, &dset, 0, &ignore); /* d=d+1 */
559372ac97cdSTom Musta } /* iterate */
559472ac97cdSTom Musta
559572ac97cdSTom Musta #if DECCHECK
559672ac97cdSTom Musta /* just a sanity check; comment out test to show always */
559772ac97cdSTom Musta if (iterations>p+3)
559872ac97cdSTom Musta printf("Exp iterations=%ld, status=%08lx, p=%ld, d=%ld\n",
559972ac97cdSTom Musta iterations, *status, p, x->digits);
560072ac97cdSTom Musta #endif
560172ac97cdSTom Musta } /* h<=8 */
560272ac97cdSTom Musta
560372ac97cdSTom Musta /* apply postconditioning: a=a**(10**h) -- this is calculated */
560472ac97cdSTom Musta /* at a slightly higher precision than Hull & Abrham suggest */
560572ac97cdSTom Musta if (h>0) {
560672ac97cdSTom Musta Int seenbit=0; /* set once a 1-bit is seen */
560772ac97cdSTom Musta Int i; /* counter */
560872ac97cdSTom Musta Int n=powers[h]; /* always positive */
560972ac97cdSTom Musta aset.digits=p+2; /* sufficient precision */
561072ac97cdSTom Musta /* avoid the overhead and many extra digits of decNumberPower */
561172ac97cdSTom Musta /* as all that is needed is the short 'multipliers' loop; here */
561272ac97cdSTom Musta /* accumulate the answer into t */
561372ac97cdSTom Musta decNumberZero(t); *t->lsu=1; /* acc=1 */
561472ac97cdSTom Musta for (i=1;;i++){ /* for each bit [top bit ignored] */
561572ac97cdSTom Musta /* abandon if have had overflow or terminal underflow */
561672ac97cdSTom Musta if (*status & (DEC_Overflow|DEC_Underflow)) { /* interesting? */
561772ac97cdSTom Musta if (*status&DEC_Overflow || ISZERO(t)) break;}
561872ac97cdSTom Musta n=n<<1; /* move next bit to testable position */
561972ac97cdSTom Musta if (n<0) { /* top bit is set */
562072ac97cdSTom Musta seenbit=1; /* OK, have a significant bit */
562172ac97cdSTom Musta decMultiplyOp(t, t, a, &aset, status); /* acc=acc*x */
562272ac97cdSTom Musta }
562372ac97cdSTom Musta if (i==31) break; /* that was the last bit */
562472ac97cdSTom Musta if (!seenbit) continue; /* no need to square 1 */
562572ac97cdSTom Musta decMultiplyOp(t, t, t, &aset, status); /* acc=acc*acc [square] */
562672ac97cdSTom Musta } /*i*/ /* 32 bits */
562772ac97cdSTom Musta /* decNumberShow(t); */
562872ac97cdSTom Musta a=t; /* and carry on using t instead of a */
562972ac97cdSTom Musta }
563072ac97cdSTom Musta
563172ac97cdSTom Musta /* Copy and round the result to res */
563272ac97cdSTom Musta residue=1; /* indicate dirt to right .. */
563372ac97cdSTom Musta if (ISZERO(a)) residue=0; /* .. unless underflowed to 0 */
563472ac97cdSTom Musta aset.digits=set->digits; /* [use default rounding] */
563572ac97cdSTom Musta decCopyFit(res, a, &aset, &residue, status); /* copy & shorten */
563672ac97cdSTom Musta decFinish(res, set, &residue, status); /* cleanup/set flags */
563772ac97cdSTom Musta } while(0); /* end protected */
563872ac97cdSTom Musta
563972ac97cdSTom Musta if (allocrhs !=NULL) free(allocrhs); /* drop any storage used */
564072ac97cdSTom Musta if (allocbufa!=NULL) free(allocbufa); /* .. */
564172ac97cdSTom Musta if (allocbuft!=NULL) free(allocbuft); /* .. */
564272ac97cdSTom Musta /* [status is handled by caller] */
564372ac97cdSTom Musta return res;
564472ac97cdSTom Musta } /* decExpOp */
564572ac97cdSTom Musta
564672ac97cdSTom Musta /* ------------------------------------------------------------------ */
564772ac97cdSTom Musta /* Initial-estimate natural logarithm table */
564872ac97cdSTom Musta /* */
564972ac97cdSTom Musta /* LNnn -- 90-entry 16-bit table for values from .10 through .99. */
565072ac97cdSTom Musta /* The result is a 4-digit encode of the coefficient (c=the */
565172ac97cdSTom Musta /* top 14 bits encoding 0-9999) and a 2-digit encode of the */
565272ac97cdSTom Musta /* exponent (e=the bottom 2 bits encoding 0-3) */
565372ac97cdSTom Musta /* */
565472ac97cdSTom Musta /* The resulting value is given by: */
565572ac97cdSTom Musta /* */
565672ac97cdSTom Musta /* v = -c * 10**(-e-3) */
565772ac97cdSTom Musta /* */
565872ac97cdSTom Musta /* where e and c are extracted from entry k = LNnn[x-10] */
565972ac97cdSTom Musta /* where x is truncated (NB) into the range 10 through 99, */
566072ac97cdSTom Musta /* and then c = k>>2 and e = k&3. */
566172ac97cdSTom Musta /* ------------------------------------------------------------------ */
5662d072cdf3SStefan Weil static const uShort LNnn[90] = {
5663d072cdf3SStefan Weil 9016, 8652, 8316, 8008, 7724, 7456, 7208,
566472ac97cdSTom Musta 6972, 6748, 6540, 6340, 6148, 5968, 5792, 5628, 5464, 5312,
566572ac97cdSTom Musta 5164, 5020, 4884, 4748, 4620, 4496, 4376, 4256, 4144, 4032,
566672ac97cdSTom Musta 39233, 38181, 37157, 36157, 35181, 34229, 33297, 32389, 31501, 30629,
566772ac97cdSTom Musta 29777, 28945, 28129, 27329, 26545, 25777, 25021, 24281, 23553, 22837,
566872ac97cdSTom Musta 22137, 21445, 20769, 20101, 19445, 18801, 18165, 17541, 16925, 16321,
566972ac97cdSTom Musta 15721, 15133, 14553, 13985, 13421, 12865, 12317, 11777, 11241, 10717,
567072ac97cdSTom Musta 10197, 9685, 9177, 8677, 8185, 7697, 7213, 6737, 6269, 5801,
567172ac97cdSTom Musta 5341, 4889, 4437, 39930, 35534, 31186, 26886, 22630, 18418, 14254,
567272ac97cdSTom Musta 10130, 6046, 20055};
567372ac97cdSTom Musta
567472ac97cdSTom Musta /* ------------------------------------------------------------------ */
567572ac97cdSTom Musta /* decLnOp -- effect natural logarithm */
567672ac97cdSTom Musta /* */
567772ac97cdSTom Musta /* This computes C = ln(A) */
567872ac97cdSTom Musta /* */
567972ac97cdSTom Musta /* res is C, the result. C may be A */
568072ac97cdSTom Musta /* rhs is A */
568172ac97cdSTom Musta /* set is the context; note that rounding mode has no effect */
568272ac97cdSTom Musta /* */
568372ac97cdSTom Musta /* C must have space for set->digits digits. */
568472ac97cdSTom Musta /* */
568572ac97cdSTom Musta /* Notable cases: */
568672ac97cdSTom Musta /* A<0 -> Invalid */
568772ac97cdSTom Musta /* A=0 -> -Infinity (Exact) */
568872ac97cdSTom Musta /* A=+Infinity -> +Infinity (Exact) */
568972ac97cdSTom Musta /* A=1 exactly -> 0 (Exact) */
569072ac97cdSTom Musta /* */
569172ac97cdSTom Musta /* Restrictions (as for Exp): */
569272ac97cdSTom Musta /* */
569372ac97cdSTom Musta /* digits, emax, and -emin in the context must be less than */
569472ac97cdSTom Musta /* DEC_MAX_MATH+11 (1000010), and the rhs must be within these */
569572ac97cdSTom Musta /* bounds or a zero. This is an internal routine, so these */
569672ac97cdSTom Musta /* restrictions are contractual and not enforced. */
569772ac97cdSTom Musta /* */
569872ac97cdSTom Musta /* A finite result is rounded using DEC_ROUND_HALF_EVEN; it will */
569972ac97cdSTom Musta /* almost always be correctly rounded, but may be up to 1 ulp in */
570072ac97cdSTom Musta /* error in rare cases. */
570172ac97cdSTom Musta /* ------------------------------------------------------------------ */
570272ac97cdSTom Musta /* The result is calculated using Newton's method, with each */
570372ac97cdSTom Musta /* iteration calculating a' = a + x * exp(-a) - 1. See, for example, */
570472ac97cdSTom Musta /* Epperson 1989. */
570572ac97cdSTom Musta /* */
570672ac97cdSTom Musta /* The iteration ends when the adjustment x*exp(-a)-1 is tiny enough. */
570772ac97cdSTom Musta /* This has to be calculated at the sum of the precision of x and the */
570872ac97cdSTom Musta /* working precision. */
570972ac97cdSTom Musta /* */
571072ac97cdSTom Musta /* Implementation notes: */
571172ac97cdSTom Musta /* */
571272ac97cdSTom Musta /* 1. This is separated out as decLnOp so it can be called from */
571372ac97cdSTom Musta /* other Mathematical functions (e.g., Log 10) with a wider range */
571472ac97cdSTom Musta /* than normal. In particular, it can handle the slightly wider */
571572ac97cdSTom Musta /* (+9+2) range needed by a power function. */
571672ac97cdSTom Musta /* */
571772ac97cdSTom Musta /* 2. The speed of this function is about 10x slower than exp, as */
571872ac97cdSTom Musta /* it typically needs 4-6 iterations for short numbers, and the */
571972ac97cdSTom Musta /* extra precision needed adds a squaring effect, twice. */
572072ac97cdSTom Musta /* */
572172ac97cdSTom Musta /* 3. Fastpaths are included for ln(10) and ln(2), up to length 40, */
572272ac97cdSTom Musta /* as these are common requests. ln(10) is used by log10(x). */
572372ac97cdSTom Musta /* */
572472ac97cdSTom Musta /* 4. An iteration might be saved by widening the LNnn table, and */
572572ac97cdSTom Musta /* would certainly save at least one if it were made ten times */
572672ac97cdSTom Musta /* bigger, too (for truncated fractions 0.100 through 0.999). */
572772ac97cdSTom Musta /* However, for most practical evaluations, at least four or five */
5728e3a6e0daSzhaolichang /* iterations will be needed -- so this would only speed up by */
572972ac97cdSTom Musta /* 20-25% and that probably does not justify increasing the table */
573072ac97cdSTom Musta /* size. */
573172ac97cdSTom Musta /* */
573272ac97cdSTom Musta /* 5. The static buffers are larger than might be expected to allow */
573372ac97cdSTom Musta /* for calls from decNumberPower. */
573472ac97cdSTom Musta /* ------------------------------------------------------------------ */
decLnOp(decNumber * res,const decNumber * rhs,decContext * set,uInt * status)5735d072cdf3SStefan Weil static decNumber *decLnOp(decNumber *res, const decNumber *rhs,
573672ac97cdSTom Musta decContext *set, uInt *status) {
573772ac97cdSTom Musta uInt ignore=0; /* working status accumulator */
573872ac97cdSTom Musta uInt needbytes; /* for space calculations */
573972ac97cdSTom Musta Int residue; /* rounding residue */
574072ac97cdSTom Musta Int r; /* rhs=f*10**r [see below] */
574172ac97cdSTom Musta Int p; /* working precision */
574272ac97cdSTom Musta Int pp; /* precision for iteration */
574372ac97cdSTom Musta Int t; /* work */
574472ac97cdSTom Musta
574572ac97cdSTom Musta /* buffers for a (accumulator, typically precision+2) and b */
574672ac97cdSTom Musta /* (adjustment calculator, same size) */
574772ac97cdSTom Musta decNumber bufa[D2N(DECBUFFER+12)];
574872ac97cdSTom Musta decNumber *allocbufa=NULL; /* -> allocated bufa, iff allocated */
574972ac97cdSTom Musta decNumber *a=bufa; /* accumulator/work */
575072ac97cdSTom Musta decNumber bufb[D2N(DECBUFFER*2+2)];
575172ac97cdSTom Musta decNumber *allocbufb=NULL; /* -> allocated bufa, iff allocated */
575272ac97cdSTom Musta decNumber *b=bufb; /* adjustment/work */
575372ac97cdSTom Musta
575472ac97cdSTom Musta decNumber numone; /* constant 1 */
575572ac97cdSTom Musta decNumber cmp; /* work */
575672ac97cdSTom Musta decContext aset, bset; /* working contexts */
575772ac97cdSTom Musta
575872ac97cdSTom Musta #if DECCHECK
575972ac97cdSTom Musta Int iterations=0; /* for later sanity check */
576072ac97cdSTom Musta if (decCheckOperands(res, DECUNUSED, rhs, set)) return res;
576172ac97cdSTom Musta #endif
576272ac97cdSTom Musta
576372ac97cdSTom Musta do { /* protect allocated storage */
576472ac97cdSTom Musta if (SPECIALARG) { /* handle infinities and NaNs */
576572ac97cdSTom Musta if (decNumberIsInfinite(rhs)) { /* an infinity */
576672ac97cdSTom Musta if (decNumberIsNegative(rhs)) /* -Infinity -> error */
576772ac97cdSTom Musta *status|=DEC_Invalid_operation;
576872ac97cdSTom Musta else decNumberCopy(res, rhs); /* +Infinity -> self */
576972ac97cdSTom Musta }
577072ac97cdSTom Musta else decNaNs(res, rhs, NULL, set, status); /* a NaN */
577172ac97cdSTom Musta break;}
577272ac97cdSTom Musta
577372ac97cdSTom Musta if (ISZERO(rhs)) { /* +/- zeros -> -Infinity */
577472ac97cdSTom Musta decNumberZero(res); /* make clean */
577572ac97cdSTom Musta res->bits=DECINF|DECNEG; /* set - infinity */
577672ac97cdSTom Musta break;} /* [no status to set] */
577772ac97cdSTom Musta
577872ac97cdSTom Musta /* Non-zero negatives are bad... */
577972ac97cdSTom Musta if (decNumberIsNegative(rhs)) { /* -x -> error */
578072ac97cdSTom Musta *status|=DEC_Invalid_operation;
578172ac97cdSTom Musta break;}
578272ac97cdSTom Musta
578372ac97cdSTom Musta /* Here, rhs is positive, finite, and in range */
578472ac97cdSTom Musta
578572ac97cdSTom Musta /* lookaside fastpath code for ln(2) and ln(10) at common lengths */
578672ac97cdSTom Musta if (rhs->exponent==0 && set->digits<=40) {
578772ac97cdSTom Musta #if DECDPUN==1
578872ac97cdSTom Musta if (rhs->lsu[0]==0 && rhs->lsu[1]==1 && rhs->digits==2) { /* ln(10) */
578972ac97cdSTom Musta #else
579072ac97cdSTom Musta if (rhs->lsu[0]==10 && rhs->digits==2) { /* ln(10) */
579172ac97cdSTom Musta #endif
579272ac97cdSTom Musta aset=*set; aset.round=DEC_ROUND_HALF_EVEN;
579372ac97cdSTom Musta #define LN10 "2.302585092994045684017991454684364207601"
579472ac97cdSTom Musta decNumberFromString(res, LN10, &aset);
579572ac97cdSTom Musta *status|=(DEC_Inexact | DEC_Rounded); /* is inexact */
579672ac97cdSTom Musta break;}
579772ac97cdSTom Musta if (rhs->lsu[0]==2 && rhs->digits==1) { /* ln(2) */
579872ac97cdSTom Musta aset=*set; aset.round=DEC_ROUND_HALF_EVEN;
579972ac97cdSTom Musta #define LN2 "0.6931471805599453094172321214581765680755"
580072ac97cdSTom Musta decNumberFromString(res, LN2, &aset);
580172ac97cdSTom Musta *status|=(DEC_Inexact | DEC_Rounded);
580272ac97cdSTom Musta break;}
580372ac97cdSTom Musta } /* integer and short */
580472ac97cdSTom Musta
580572ac97cdSTom Musta /* Determine the working precision. This is normally the */
580672ac97cdSTom Musta /* requested precision + 2, with a minimum of 9. However, if */
580772ac97cdSTom Musta /* the rhs is 'over-precise' then allow for all its digits to */
580872ac97cdSTom Musta /* potentially participate (consider an rhs where all the excess */
580972ac97cdSTom Musta /* digits are 9s) so in this case use rhs->digits+2. */
581072ac97cdSTom Musta p=MAXI(rhs->digits, MAXI(set->digits, 7))+2;
581172ac97cdSTom Musta
581272ac97cdSTom Musta /* Allocate space for the accumulator and the high-precision */
581372ac97cdSTom Musta /* adjustment calculator, if necessary. The accumulator must */
581472ac97cdSTom Musta /* be able to hold p digits, and the adjustment up to */
581572ac97cdSTom Musta /* rhs->digits+p digits. They are also made big enough for 16 */
581672ac97cdSTom Musta /* digits so that they can be used for calculating the initial */
581772ac97cdSTom Musta /* estimate. */
581872ac97cdSTom Musta needbytes=sizeof(decNumber)+(D2U(MAXI(p,16))-1)*sizeof(Unit);
581972ac97cdSTom Musta if (needbytes>sizeof(bufa)) { /* need malloc space */
582072ac97cdSTom Musta allocbufa=(decNumber *)malloc(needbytes);
582172ac97cdSTom Musta if (allocbufa==NULL) { /* hopeless -- abandon */
582272ac97cdSTom Musta *status|=DEC_Insufficient_storage;
582372ac97cdSTom Musta break;}
582472ac97cdSTom Musta a=allocbufa; /* use the allocated space */
582572ac97cdSTom Musta }
582672ac97cdSTom Musta pp=p+rhs->digits;
582772ac97cdSTom Musta needbytes=sizeof(decNumber)+(D2U(MAXI(pp,16))-1)*sizeof(Unit);
582872ac97cdSTom Musta if (needbytes>sizeof(bufb)) { /* need malloc space */
582972ac97cdSTom Musta allocbufb=(decNumber *)malloc(needbytes);
583072ac97cdSTom Musta if (allocbufb==NULL) { /* hopeless -- abandon */
583172ac97cdSTom Musta *status|=DEC_Insufficient_storage;
583272ac97cdSTom Musta break;}
583372ac97cdSTom Musta b=allocbufb; /* use the allocated space */
583472ac97cdSTom Musta }
583572ac97cdSTom Musta
583672ac97cdSTom Musta /* Prepare an initial estimate in acc. Calculate this by */
583772ac97cdSTom Musta /* considering the coefficient of x to be a normalized fraction, */
583872ac97cdSTom Musta /* f, with the decimal point at far left and multiplied by */
583972ac97cdSTom Musta /* 10**r. Then, rhs=f*10**r and 0.1<=f<1, and */
584072ac97cdSTom Musta /* ln(x) = ln(f) + ln(10)*r */
584172ac97cdSTom Musta /* Get the initial estimate for ln(f) from a small lookup */
584272ac97cdSTom Musta /* table (see above) indexed by the first two digits of f, */
584372ac97cdSTom Musta /* truncated. */
584472ac97cdSTom Musta
584572ac97cdSTom Musta decContextDefault(&aset, DEC_INIT_DECIMAL64); /* 16-digit extended */
584672ac97cdSTom Musta r=rhs->exponent+rhs->digits; /* 'normalised' exponent */
584772ac97cdSTom Musta decNumberFromInt32(a, r); /* a=r */
584872ac97cdSTom Musta decNumberFromInt32(b, 2302585); /* b=ln(10) (2.302585) */
584972ac97cdSTom Musta b->exponent=-6; /* .. */
585072ac97cdSTom Musta decMultiplyOp(a, a, b, &aset, &ignore); /* a=a*b */
585172ac97cdSTom Musta /* now get top two digits of rhs into b by simple truncate and */
585272ac97cdSTom Musta /* force to integer */
585372ac97cdSTom Musta residue=0; /* (no residue) */
585472ac97cdSTom Musta aset.digits=2; aset.round=DEC_ROUND_DOWN;
585572ac97cdSTom Musta decCopyFit(b, rhs, &aset, &residue, &ignore); /* copy & shorten */
585672ac97cdSTom Musta b->exponent=0; /* make integer */
585772ac97cdSTom Musta t=decGetInt(b); /* [cannot fail] */
585872ac97cdSTom Musta if (t<10) t=X10(t); /* adjust single-digit b */
585972ac97cdSTom Musta t=LNnn[t-10]; /* look up ln(b) */
586072ac97cdSTom Musta decNumberFromInt32(b, t>>2); /* b=ln(b) coefficient */
586172ac97cdSTom Musta b->exponent=-(t&3)-3; /* set exponent */
586272ac97cdSTom Musta b->bits=DECNEG; /* ln(0.10)->ln(0.99) always -ve */
586372ac97cdSTom Musta aset.digits=16; aset.round=DEC_ROUND_HALF_EVEN; /* restore */
586472ac97cdSTom Musta decAddOp(a, a, b, &aset, 0, &ignore); /* acc=a+b */
586572ac97cdSTom Musta /* the initial estimate is now in a, with up to 4 digits correct. */
586672ac97cdSTom Musta /* When rhs is at or near Nmax the estimate will be low, so we */
586772ac97cdSTom Musta /* will approach it from below, avoiding overflow when calling exp. */
586872ac97cdSTom Musta
586972ac97cdSTom Musta decNumberZero(&numone); *numone.lsu=1; /* constant 1 for adjustment */
587072ac97cdSTom Musta
587172ac97cdSTom Musta /* accumulator bounds are as requested (could underflow, but */
587272ac97cdSTom Musta /* cannot overflow) */
587372ac97cdSTom Musta aset.emax=set->emax;
587472ac97cdSTom Musta aset.emin=set->emin;
587572ac97cdSTom Musta aset.clamp=0; /* no concrete format */
587672ac97cdSTom Musta /* set up a context to be used for the multiply and subtract */
587772ac97cdSTom Musta bset=aset;
587872ac97cdSTom Musta bset.emax=DEC_MAX_MATH*2; /* use double bounds for the */
587972ac97cdSTom Musta bset.emin=-DEC_MAX_MATH*2; /* adjustment calculation */
588072ac97cdSTom Musta /* [see decExpOp call below] */
588172ac97cdSTom Musta /* for each iteration double the number of digits to calculate, */
588272ac97cdSTom Musta /* up to a maximum of p */
588372ac97cdSTom Musta pp=9; /* initial precision */
588472ac97cdSTom Musta /* [initially 9 as then the sequence starts 7+2, 16+2, and */
588572ac97cdSTom Musta /* 34+2, which is ideal for standard-sized numbers] */
588672ac97cdSTom Musta aset.digits=pp; /* working context */
588772ac97cdSTom Musta bset.digits=pp+rhs->digits; /* wider context */
588872ac97cdSTom Musta for (;;) { /* iterate */
588972ac97cdSTom Musta #if DECCHECK
589072ac97cdSTom Musta iterations++;
589172ac97cdSTom Musta if (iterations>24) break; /* consider 9 * 2**24 */
589272ac97cdSTom Musta #endif
589372ac97cdSTom Musta /* calculate the adjustment (exp(-a)*x-1) into b. This is a */
589472ac97cdSTom Musta /* catastrophic subtraction but it really is the difference */
589572ac97cdSTom Musta /* from 1 that is of interest. */
589672ac97cdSTom Musta /* Use the internal entry point to Exp as it allows the double */
589772ac97cdSTom Musta /* range for calculating exp(-a) when a is the tiniest subnormal. */
589872ac97cdSTom Musta a->bits^=DECNEG; /* make -a */
589972ac97cdSTom Musta decExpOp(b, a, &bset, &ignore); /* b=exp(-a) */
590072ac97cdSTom Musta a->bits^=DECNEG; /* restore sign of a */
590172ac97cdSTom Musta /* now multiply by rhs and subtract 1, at the wider precision */
590272ac97cdSTom Musta decMultiplyOp(b, b, rhs, &bset, &ignore); /* b=b*rhs */
590372ac97cdSTom Musta decAddOp(b, b, &numone, &bset, DECNEG, &ignore); /* b=b-1 */
590472ac97cdSTom Musta
590572ac97cdSTom Musta /* the iteration ends when the adjustment cannot affect the */
590672ac97cdSTom Musta /* result by >=0.5 ulp (at the requested digits), which */
590772ac97cdSTom Musta /* is when its value is smaller than the accumulator by */
590872ac97cdSTom Musta /* set->digits+1 digits (or it is zero) -- this is a looser */
590972ac97cdSTom Musta /* requirement than for Exp because all that happens to the */
591072ac97cdSTom Musta /* accumulator after this is the final rounding (but note that */
591172ac97cdSTom Musta /* there must also be full precision in a, or a=0). */
591272ac97cdSTom Musta
591372ac97cdSTom Musta if (decNumberIsZero(b) ||
591472ac97cdSTom Musta (a->digits+a->exponent)>=(b->digits+b->exponent+set->digits+1)) {
591572ac97cdSTom Musta if (a->digits==p) break;
591672ac97cdSTom Musta if (decNumberIsZero(a)) {
591772ac97cdSTom Musta decCompareOp(&cmp, rhs, &numone, &aset, COMPARE, &ignore); /* rhs=1 ? */
591872ac97cdSTom Musta if (cmp.lsu[0]==0) a->exponent=0; /* yes, exact 0 */
591972ac97cdSTom Musta else *status|=(DEC_Inexact | DEC_Rounded); /* no, inexact */
592072ac97cdSTom Musta break;
592172ac97cdSTom Musta }
592272ac97cdSTom Musta /* force padding if adjustment has gone to 0 before full length */
592372ac97cdSTom Musta if (decNumberIsZero(b)) b->exponent=a->exponent-p;
592472ac97cdSTom Musta }
592572ac97cdSTom Musta
592672ac97cdSTom Musta /* not done yet ... */
592772ac97cdSTom Musta decAddOp(a, a, b, &aset, 0, &ignore); /* a=a+b for next estimate */
592872ac97cdSTom Musta if (pp==p) continue; /* precision is at maximum */
592972ac97cdSTom Musta /* lengthen the next calculation */
593072ac97cdSTom Musta pp=pp*2; /* double precision */
593172ac97cdSTom Musta if (pp>p) pp=p; /* clamp to maximum */
593272ac97cdSTom Musta aset.digits=pp; /* working context */
593372ac97cdSTom Musta bset.digits=pp+rhs->digits; /* wider context */
593472ac97cdSTom Musta } /* Newton's iteration */
593572ac97cdSTom Musta
593672ac97cdSTom Musta #if DECCHECK
593772ac97cdSTom Musta /* just a sanity check; remove the test to show always */
593872ac97cdSTom Musta if (iterations>24)
593972ac97cdSTom Musta printf("Ln iterations=%ld, status=%08lx, p=%ld, d=%ld\n",
594072ac97cdSTom Musta iterations, *status, p, rhs->digits);
594172ac97cdSTom Musta #endif
594272ac97cdSTom Musta
594372ac97cdSTom Musta /* Copy and round the result to res */
594472ac97cdSTom Musta residue=1; /* indicate dirt to right */
594572ac97cdSTom Musta if (ISZERO(a)) residue=0; /* .. unless underflowed to 0 */
594672ac97cdSTom Musta aset.digits=set->digits; /* [use default rounding] */
594772ac97cdSTom Musta decCopyFit(res, a, &aset, &residue, status); /* copy & shorten */
594872ac97cdSTom Musta decFinish(res, set, &residue, status); /* cleanup/set flags */
594972ac97cdSTom Musta } while(0); /* end protected */
595072ac97cdSTom Musta
595172ac97cdSTom Musta if (allocbufa!=NULL) free(allocbufa); /* drop any storage used */
595272ac97cdSTom Musta if (allocbufb!=NULL) free(allocbufb); /* .. */
595372ac97cdSTom Musta /* [status is handled by caller] */
595472ac97cdSTom Musta return res;
595572ac97cdSTom Musta } /* decLnOp */
595672ac97cdSTom Musta
595772ac97cdSTom Musta /* ------------------------------------------------------------------ */
595872ac97cdSTom Musta /* decQuantizeOp -- force exponent to requested value */
595972ac97cdSTom Musta /* */
596072ac97cdSTom Musta /* This computes C = op(A, B), where op adjusts the coefficient */
596172ac97cdSTom Musta /* of C (by rounding or shifting) such that the exponent (-scale) */
596272ac97cdSTom Musta /* of C has the value B or matches the exponent of B. */
596372ac97cdSTom Musta /* The numerical value of C will equal A, except for the effects of */
596472ac97cdSTom Musta /* any rounding that occurred. */
596572ac97cdSTom Musta /* */
596672ac97cdSTom Musta /* res is C, the result. C may be A or B */
596772ac97cdSTom Musta /* lhs is A, the number to adjust */
596872ac97cdSTom Musta /* rhs is B, the requested exponent */
596972ac97cdSTom Musta /* set is the context */
597072ac97cdSTom Musta /* quant is 1 for quantize or 0 for rescale */
597172ac97cdSTom Musta /* status is the status accumulator (this can be called without */
597272ac97cdSTom Musta /* risk of control loss) */
597372ac97cdSTom Musta /* */
597472ac97cdSTom Musta /* C must have space for set->digits digits. */
597572ac97cdSTom Musta /* */
597672ac97cdSTom Musta /* Unless there is an error or the result is infinite, the exponent */
597772ac97cdSTom Musta /* after the operation is guaranteed to be that requested. */
597872ac97cdSTom Musta /* ------------------------------------------------------------------ */
597972ac97cdSTom Musta static decNumber * decQuantizeOp(decNumber *res, const decNumber *lhs,
598072ac97cdSTom Musta const decNumber *rhs, decContext *set,
598172ac97cdSTom Musta Flag quant, uInt *status) {
598272ac97cdSTom Musta #if DECSUBSET
598372ac97cdSTom Musta decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
598472ac97cdSTom Musta decNumber *allocrhs=NULL; /* .., rhs */
598572ac97cdSTom Musta #endif
598672ac97cdSTom Musta const decNumber *inrhs=rhs; /* save original rhs */
598772ac97cdSTom Musta Int reqdigits=set->digits; /* requested DIGITS */
598872ac97cdSTom Musta Int reqexp; /* requested exponent [-scale] */
598972ac97cdSTom Musta Int residue=0; /* rounding residue */
599072ac97cdSTom Musta Int etiny=set->emin-(reqdigits-1);
599172ac97cdSTom Musta
599272ac97cdSTom Musta #if DECCHECK
599372ac97cdSTom Musta if (decCheckOperands(res, lhs, rhs, set)) return res;
599472ac97cdSTom Musta #endif
599572ac97cdSTom Musta
599672ac97cdSTom Musta do { /* protect allocated storage */
599772ac97cdSTom Musta #if DECSUBSET
599872ac97cdSTom Musta if (!set->extended) {
599972ac97cdSTom Musta /* reduce operands and set lostDigits status, as needed */
600072ac97cdSTom Musta if (lhs->digits>reqdigits) {
600172ac97cdSTom Musta alloclhs=decRoundOperand(lhs, set, status);
600272ac97cdSTom Musta if (alloclhs==NULL) break;
600372ac97cdSTom Musta lhs=alloclhs;
600472ac97cdSTom Musta }
600572ac97cdSTom Musta if (rhs->digits>reqdigits) { /* [this only checks lostDigits] */
600672ac97cdSTom Musta allocrhs=decRoundOperand(rhs, set, status);
600772ac97cdSTom Musta if (allocrhs==NULL) break;
600872ac97cdSTom Musta rhs=allocrhs;
600972ac97cdSTom Musta }
601072ac97cdSTom Musta }
601172ac97cdSTom Musta #endif
601272ac97cdSTom Musta /* [following code does not require input rounding] */
601372ac97cdSTom Musta
601472ac97cdSTom Musta /* Handle special values */
601572ac97cdSTom Musta if (SPECIALARGS) {
601672ac97cdSTom Musta /* NaNs get usual processing */
601772ac97cdSTom Musta if (SPECIALARGS & (DECSNAN | DECNAN))
601872ac97cdSTom Musta decNaNs(res, lhs, rhs, set, status);
601972ac97cdSTom Musta /* one infinity but not both is bad */
602072ac97cdSTom Musta else if ((lhs->bits ^ rhs->bits) & DECINF)
602172ac97cdSTom Musta *status|=DEC_Invalid_operation;
602272ac97cdSTom Musta /* both infinity: return lhs */
602372ac97cdSTom Musta else decNumberCopy(res, lhs); /* [nop if in place] */
602472ac97cdSTom Musta break;
602572ac97cdSTom Musta }
602672ac97cdSTom Musta
602772ac97cdSTom Musta /* set requested exponent */
602872ac97cdSTom Musta if (quant) reqexp=inrhs->exponent; /* quantize -- match exponents */
602972ac97cdSTom Musta else { /* rescale -- use value of rhs */
603072ac97cdSTom Musta /* Original rhs must be an integer that fits and is in range, */
603172ac97cdSTom Musta /* which could be from -1999999997 to +999999999, thanks to */
603272ac97cdSTom Musta /* subnormals */
603372ac97cdSTom Musta reqexp=decGetInt(inrhs); /* [cannot fail] */
603472ac97cdSTom Musta }
603572ac97cdSTom Musta
603672ac97cdSTom Musta #if DECSUBSET
603772ac97cdSTom Musta if (!set->extended) etiny=set->emin; /* no subnormals */
603872ac97cdSTom Musta #endif
603972ac97cdSTom Musta
604072ac97cdSTom Musta if (reqexp==BADINT /* bad (rescale only) or .. */
604172ac97cdSTom Musta || reqexp==BIGODD || reqexp==BIGEVEN /* very big (ditto) or .. */
604272ac97cdSTom Musta || (reqexp<etiny) /* < lowest */
604372ac97cdSTom Musta || (reqexp>set->emax)) { /* > emax */
604472ac97cdSTom Musta *status|=DEC_Invalid_operation;
604572ac97cdSTom Musta break;}
604672ac97cdSTom Musta
604772ac97cdSTom Musta /* the RHS has been processed, so it can be overwritten now if necessary */
604872ac97cdSTom Musta if (ISZERO(lhs)) { /* zero coefficient unchanged */
604972ac97cdSTom Musta decNumberCopy(res, lhs); /* [nop if in place] */
605072ac97cdSTom Musta res->exponent=reqexp; /* .. just set exponent */
605172ac97cdSTom Musta #if DECSUBSET
605272ac97cdSTom Musta if (!set->extended) res->bits=0; /* subset specification; no -0 */
605372ac97cdSTom Musta #endif
605472ac97cdSTom Musta }
605572ac97cdSTom Musta else { /* non-zero lhs */
605672ac97cdSTom Musta Int adjust=reqexp-lhs->exponent; /* digit adjustment needed */
605772ac97cdSTom Musta /* if adjusted coefficient will definitely not fit, give up now */
605872ac97cdSTom Musta if ((lhs->digits-adjust)>reqdigits) {
605972ac97cdSTom Musta *status|=DEC_Invalid_operation;
606072ac97cdSTom Musta break;
606172ac97cdSTom Musta }
606272ac97cdSTom Musta
606372ac97cdSTom Musta if (adjust>0) { /* increasing exponent */
606472ac97cdSTom Musta /* this will decrease the length of the coefficient by adjust */
606572ac97cdSTom Musta /* digits, and must round as it does so */
606672ac97cdSTom Musta decContext workset; /* work */
606772ac97cdSTom Musta workset=*set; /* clone rounding, etc. */
606872ac97cdSTom Musta workset.digits=lhs->digits-adjust; /* set requested length */
606972ac97cdSTom Musta /* [note that the latter can be <1, here] */
607072ac97cdSTom Musta decCopyFit(res, lhs, &workset, &residue, status); /* fit to result */
607172ac97cdSTom Musta decApplyRound(res, &workset, residue, status); /* .. and round */
607272ac97cdSTom Musta residue=0; /* [used] */
607372ac97cdSTom Musta /* If just rounded a 999s case, exponent will be off by one; */
607472ac97cdSTom Musta /* adjust back (after checking space), if so. */
607572ac97cdSTom Musta if (res->exponent>reqexp) {
607672ac97cdSTom Musta /* re-check needed, e.g., for quantize(0.9999, 0.001) under */
607772ac97cdSTom Musta /* set->digits==3 */
607872ac97cdSTom Musta if (res->digits==reqdigits) { /* cannot shift by 1 */
607972ac97cdSTom Musta *status&=~(DEC_Inexact | DEC_Rounded); /* [clean these] */
608072ac97cdSTom Musta *status|=DEC_Invalid_operation;
608172ac97cdSTom Musta break;
608272ac97cdSTom Musta }
608372ac97cdSTom Musta res->digits=decShiftToMost(res->lsu, res->digits, 1); /* shift */
608472ac97cdSTom Musta res->exponent--; /* (re)adjust the exponent. */
608572ac97cdSTom Musta }
608672ac97cdSTom Musta #if DECSUBSET
608772ac97cdSTom Musta if (ISZERO(res) && !set->extended) res->bits=0; /* subset; no -0 */
608872ac97cdSTom Musta #endif
608972ac97cdSTom Musta } /* increase */
609072ac97cdSTom Musta else /* adjust<=0 */ { /* decreasing or = exponent */
609172ac97cdSTom Musta /* this will increase the length of the coefficient by -adjust */
609272ac97cdSTom Musta /* digits, by adding zero or more trailing zeros; this is */
609372ac97cdSTom Musta /* already checked for fit, above */
609472ac97cdSTom Musta decNumberCopy(res, lhs); /* [it will fit] */
609572ac97cdSTom Musta /* if padding needed (adjust<0), add it now... */
609672ac97cdSTom Musta if (adjust<0) {
609772ac97cdSTom Musta res->digits=decShiftToMost(res->lsu, res->digits, -adjust);
609872ac97cdSTom Musta res->exponent+=adjust; /* adjust the exponent */
609972ac97cdSTom Musta }
610072ac97cdSTom Musta } /* decrease */
610172ac97cdSTom Musta } /* non-zero */
610272ac97cdSTom Musta
610372ac97cdSTom Musta /* Check for overflow [do not use Finalize in this case, as an */
610472ac97cdSTom Musta /* overflow here is a "don't fit" situation] */
610572ac97cdSTom Musta if (res->exponent>set->emax-res->digits+1) { /* too big */
610672ac97cdSTom Musta *status|=DEC_Invalid_operation;
610772ac97cdSTom Musta break;
610872ac97cdSTom Musta }
610972ac97cdSTom Musta else {
611072ac97cdSTom Musta decFinalize(res, set, &residue, status); /* set subnormal flags */
611172ac97cdSTom Musta *status&=~DEC_Underflow; /* suppress Underflow [754r] */
611272ac97cdSTom Musta }
611372ac97cdSTom Musta } while(0); /* end protected */
611472ac97cdSTom Musta
611572ac97cdSTom Musta #if DECSUBSET
611672ac97cdSTom Musta if (allocrhs!=NULL) free(allocrhs); /* drop any storage used */
611772ac97cdSTom Musta if (alloclhs!=NULL) free(alloclhs); /* .. */
611872ac97cdSTom Musta #endif
611972ac97cdSTom Musta return res;
612072ac97cdSTom Musta } /* decQuantizeOp */
612172ac97cdSTom Musta
612272ac97cdSTom Musta /* ------------------------------------------------------------------ */
612372ac97cdSTom Musta /* decCompareOp -- compare, min, or max two Numbers */
612472ac97cdSTom Musta /* */
612572ac97cdSTom Musta /* This computes C = A ? B and carries out one of four operations: */
612672ac97cdSTom Musta /* COMPARE -- returns the signum (as a number) giving the */
612772ac97cdSTom Musta /* result of a comparison unless one or both */
612872ac97cdSTom Musta /* operands is a NaN (in which case a NaN results) */
612972ac97cdSTom Musta /* COMPSIG -- as COMPARE except that a quiet NaN raises */
613072ac97cdSTom Musta /* Invalid operation. */
613172ac97cdSTom Musta /* COMPMAX -- returns the larger of the operands, using the */
613272ac97cdSTom Musta /* 754r maxnum operation */
613372ac97cdSTom Musta /* COMPMAXMAG -- ditto, comparing absolute values */
613472ac97cdSTom Musta /* COMPMIN -- the 754r minnum operation */
613572ac97cdSTom Musta /* COMPMINMAG -- ditto, comparing absolute values */
613672ac97cdSTom Musta /* COMTOTAL -- returns the signum (as a number) giving the */
613772ac97cdSTom Musta /* result of a comparison using 754r total ordering */
613872ac97cdSTom Musta /* */
613972ac97cdSTom Musta /* res is C, the result. C may be A and/or B (e.g., X=X?X) */
614072ac97cdSTom Musta /* lhs is A */
614172ac97cdSTom Musta /* rhs is B */
614272ac97cdSTom Musta /* set is the context */
614372ac97cdSTom Musta /* op is the operation flag */
614472ac97cdSTom Musta /* status is the usual accumulator */
614572ac97cdSTom Musta /* */
614672ac97cdSTom Musta /* C must have space for one digit for COMPARE or set->digits for */
614772ac97cdSTom Musta /* COMPMAX, COMPMIN, COMPMAXMAG, or COMPMINMAG. */
614872ac97cdSTom Musta /* ------------------------------------------------------------------ */
614972ac97cdSTom Musta /* The emphasis here is on speed for common cases, and avoiding */
615072ac97cdSTom Musta /* coefficient comparison if possible. */
615172ac97cdSTom Musta /* ------------------------------------------------------------------ */
6152d072cdf3SStefan Weil static decNumber *decCompareOp(decNumber *res, const decNumber *lhs,
615372ac97cdSTom Musta const decNumber *rhs, decContext *set,
615472ac97cdSTom Musta Flag op, uInt *status) {
615572ac97cdSTom Musta #if DECSUBSET
615672ac97cdSTom Musta decNumber *alloclhs=NULL; /* non-NULL if rounded lhs allocated */
615772ac97cdSTom Musta decNumber *allocrhs=NULL; /* .., rhs */
615872ac97cdSTom Musta #endif
615972ac97cdSTom Musta Int result=0; /* default result value */
616072ac97cdSTom Musta uByte merged; /* work */
616172ac97cdSTom Musta
616272ac97cdSTom Musta #if DECCHECK
616372ac97cdSTom Musta if (decCheckOperands(res, lhs, rhs, set)) return res;
616472ac97cdSTom Musta #endif
616572ac97cdSTom Musta
616672ac97cdSTom Musta do { /* protect allocated storage */
616772ac97cdSTom Musta #if DECSUBSET
616872ac97cdSTom Musta if (!set->extended) {
616972ac97cdSTom Musta /* reduce operands and set lostDigits status, as needed */
617072ac97cdSTom Musta if (lhs->digits>set->digits) {
617172ac97cdSTom Musta alloclhs=decRoundOperand(lhs, set, status);
617272ac97cdSTom Musta if (alloclhs==NULL) {result=BADINT; break;}
617372ac97cdSTom Musta lhs=alloclhs;
617472ac97cdSTom Musta }
617572ac97cdSTom Musta if (rhs->digits>set->digits) {
617672ac97cdSTom Musta allocrhs=decRoundOperand(rhs, set, status);
617772ac97cdSTom Musta if (allocrhs==NULL) {result=BADINT; break;}
617872ac97cdSTom Musta rhs=allocrhs;
617972ac97cdSTom Musta }
618072ac97cdSTom Musta }
618172ac97cdSTom Musta #endif
618272ac97cdSTom Musta /* [following code does not require input rounding] */
618372ac97cdSTom Musta
618472ac97cdSTom Musta /* If total ordering then handle differing signs 'up front' */
618572ac97cdSTom Musta if (op==COMPTOTAL) { /* total ordering */
6186d072cdf3SStefan Weil if (decNumberIsNegative(lhs) && !decNumberIsNegative(rhs)) {
618772ac97cdSTom Musta result=-1;
618872ac97cdSTom Musta break;
618972ac97cdSTom Musta }
6190d072cdf3SStefan Weil if (!decNumberIsNegative(lhs) && decNumberIsNegative(rhs)) {
619172ac97cdSTom Musta result=+1;
619272ac97cdSTom Musta break;
619372ac97cdSTom Musta }
619472ac97cdSTom Musta }
619572ac97cdSTom Musta
619672ac97cdSTom Musta /* handle NaNs specially; let infinities drop through */
619772ac97cdSTom Musta /* This assumes sNaN (even just one) leads to NaN. */
619872ac97cdSTom Musta merged=(lhs->bits | rhs->bits) & (DECSNAN | DECNAN);
619972ac97cdSTom Musta if (merged) { /* a NaN bit set */
620072ac97cdSTom Musta if (op==COMPARE); /* result will be NaN */
620172ac97cdSTom Musta else if (op==COMPSIG) /* treat qNaN as sNaN */
620272ac97cdSTom Musta *status|=DEC_Invalid_operation | DEC_sNaN;
620372ac97cdSTom Musta else if (op==COMPTOTAL) { /* total ordering, always finite */
620472ac97cdSTom Musta /* signs are known to be the same; compute the ordering here */
620572ac97cdSTom Musta /* as if the signs are both positive, then invert for negatives */
620672ac97cdSTom Musta if (!decNumberIsNaN(lhs)) result=-1;
620772ac97cdSTom Musta else if (!decNumberIsNaN(rhs)) result=+1;
620872ac97cdSTom Musta /* here if both NaNs */
620972ac97cdSTom Musta else if (decNumberIsSNaN(lhs) && decNumberIsQNaN(rhs)) result=-1;
621072ac97cdSTom Musta else if (decNumberIsQNaN(lhs) && decNumberIsSNaN(rhs)) result=+1;
621172ac97cdSTom Musta else { /* both NaN or both sNaN */
621272ac97cdSTom Musta /* now it just depends on the payload */
621372ac97cdSTom Musta result=decUnitCompare(lhs->lsu, D2U(lhs->digits),
621472ac97cdSTom Musta rhs->lsu, D2U(rhs->digits), 0);
621572ac97cdSTom Musta /* [Error not possible, as these are 'aligned'] */
621672ac97cdSTom Musta } /* both same NaNs */
621772ac97cdSTom Musta if (decNumberIsNegative(lhs)) result=-result;
621872ac97cdSTom Musta break;
621972ac97cdSTom Musta } /* total order */
622072ac97cdSTom Musta
622172ac97cdSTom Musta else if (merged & DECSNAN); /* sNaN -> qNaN */
622272ac97cdSTom Musta else { /* here if MIN or MAX and one or two quiet NaNs */
622372ac97cdSTom Musta /* min or max -- 754r rules ignore single NaN */
622472ac97cdSTom Musta if (!decNumberIsNaN(lhs) || !decNumberIsNaN(rhs)) {
622572ac97cdSTom Musta /* just one NaN; force choice to be the non-NaN operand */
622672ac97cdSTom Musta op=COMPMAX;
622772ac97cdSTom Musta if (lhs->bits & DECNAN) result=-1; /* pick rhs */
622872ac97cdSTom Musta else result=+1; /* pick lhs */
622972ac97cdSTom Musta break;
623072ac97cdSTom Musta }
623172ac97cdSTom Musta } /* max or min */
623272ac97cdSTom Musta op=COMPNAN; /* use special path */
623372ac97cdSTom Musta decNaNs(res, lhs, rhs, set, status); /* propagate NaN */
623472ac97cdSTom Musta break;
623572ac97cdSTom Musta }
623672ac97cdSTom Musta /* have numbers */
623772ac97cdSTom Musta if (op==COMPMAXMAG || op==COMPMINMAG) result=decCompare(lhs, rhs, 1);
623872ac97cdSTom Musta else result=decCompare(lhs, rhs, 0); /* sign matters */
623972ac97cdSTom Musta } while(0); /* end protected */
624072ac97cdSTom Musta
624172ac97cdSTom Musta if (result==BADINT) *status|=DEC_Insufficient_storage; /* rare */
624272ac97cdSTom Musta else {
624372ac97cdSTom Musta if (op==COMPARE || op==COMPSIG ||op==COMPTOTAL) { /* returning signum */
624472ac97cdSTom Musta if (op==COMPTOTAL && result==0) {
624572ac97cdSTom Musta /* operands are numerically equal or same NaN (and same sign, */
624672ac97cdSTom Musta /* tested first); if identical, leave result 0 */
624772ac97cdSTom Musta if (lhs->exponent!=rhs->exponent) {
624872ac97cdSTom Musta if (lhs->exponent<rhs->exponent) result=-1;
624972ac97cdSTom Musta else result=+1;
625072ac97cdSTom Musta if (decNumberIsNegative(lhs)) result=-result;
625172ac97cdSTom Musta } /* lexp!=rexp */
625272ac97cdSTom Musta } /* total-order by exponent */
625372ac97cdSTom Musta decNumberZero(res); /* [always a valid result] */
625472ac97cdSTom Musta if (result!=0) { /* must be -1 or +1 */
625572ac97cdSTom Musta *res->lsu=1;
625672ac97cdSTom Musta if (result<0) res->bits=DECNEG;
625772ac97cdSTom Musta }
625872ac97cdSTom Musta }
625972ac97cdSTom Musta else if (op==COMPNAN); /* special, drop through */
626072ac97cdSTom Musta else { /* MAX or MIN, non-NaN result */
626172ac97cdSTom Musta Int residue=0; /* rounding accumulator */
626272ac97cdSTom Musta /* choose the operand for the result */
626372ac97cdSTom Musta const decNumber *choice;
626472ac97cdSTom Musta if (result==0) { /* operands are numerically equal */
626572ac97cdSTom Musta /* choose according to sign then exponent (see 754r) */
626672ac97cdSTom Musta uByte slhs=(lhs->bits & DECNEG);
626772ac97cdSTom Musta uByte srhs=(rhs->bits & DECNEG);
626872ac97cdSTom Musta #if DECSUBSET
626972ac97cdSTom Musta if (!set->extended) { /* subset: force left-hand */
627072ac97cdSTom Musta op=COMPMAX;
627172ac97cdSTom Musta result=+1;
627272ac97cdSTom Musta }
627372ac97cdSTom Musta else
627472ac97cdSTom Musta #endif
627572ac97cdSTom Musta if (slhs!=srhs) { /* signs differ */
627672ac97cdSTom Musta if (slhs) result=-1; /* rhs is max */
627772ac97cdSTom Musta else result=+1; /* lhs is max */
627872ac97cdSTom Musta }
627972ac97cdSTom Musta else if (slhs && srhs) { /* both negative */
628072ac97cdSTom Musta if (lhs->exponent<rhs->exponent) result=+1;
628172ac97cdSTom Musta else result=-1;
628272ac97cdSTom Musta /* [if equal, use lhs, technically identical] */
628372ac97cdSTom Musta }
628472ac97cdSTom Musta else { /* both positive */
628572ac97cdSTom Musta if (lhs->exponent>rhs->exponent) result=+1;
628672ac97cdSTom Musta else result=-1;
628772ac97cdSTom Musta /* [ditto] */
628872ac97cdSTom Musta }
628972ac97cdSTom Musta } /* numerically equal */
629072ac97cdSTom Musta /* here result will be non-0; reverse if looking for MIN */
629172ac97cdSTom Musta if (op==COMPMIN || op==COMPMINMAG) result=-result;
629272ac97cdSTom Musta choice=(result>0 ? lhs : rhs); /* choose */
629372ac97cdSTom Musta /* copy chosen to result, rounding if need be */
629472ac97cdSTom Musta decCopyFit(res, choice, set, &residue, status);
629572ac97cdSTom Musta decFinish(res, set, &residue, status);
629672ac97cdSTom Musta }
629772ac97cdSTom Musta }
629872ac97cdSTom Musta #if DECSUBSET
629972ac97cdSTom Musta if (allocrhs!=NULL) free(allocrhs); /* free any storage used */
630072ac97cdSTom Musta if (alloclhs!=NULL) free(alloclhs); /* .. */
630172ac97cdSTom Musta #endif
630272ac97cdSTom Musta return res;
630372ac97cdSTom Musta } /* decCompareOp */
630472ac97cdSTom Musta
630572ac97cdSTom Musta /* ------------------------------------------------------------------ */
630672ac97cdSTom Musta /* decCompare -- compare two decNumbers by numerical value */
630772ac97cdSTom Musta /* */
630872ac97cdSTom Musta /* This routine compares A ? B without altering them. */
630972ac97cdSTom Musta /* */
631072ac97cdSTom Musta /* Arg1 is A, a decNumber which is not a NaN */
631172ac97cdSTom Musta /* Arg2 is B, a decNumber which is not a NaN */
631272ac97cdSTom Musta /* Arg3 is 1 for a sign-independent compare, 0 otherwise */
631372ac97cdSTom Musta /* */
631472ac97cdSTom Musta /* returns -1, 0, or 1 for A<B, A==B, or A>B, or BADINT if failure */
631572ac97cdSTom Musta /* (the only possible failure is an allocation error) */
631672ac97cdSTom Musta /* ------------------------------------------------------------------ */
631772ac97cdSTom Musta static Int decCompare(const decNumber *lhs, const decNumber *rhs,
631872ac97cdSTom Musta Flag abs) {
631972ac97cdSTom Musta Int result; /* result value */
632072ac97cdSTom Musta Int sigr; /* rhs signum */
632172ac97cdSTom Musta Int compare; /* work */
632272ac97cdSTom Musta
632372ac97cdSTom Musta result=1; /* assume signum(lhs) */
632472ac97cdSTom Musta if (ISZERO(lhs)) result=0;
632572ac97cdSTom Musta if (abs) {
632672ac97cdSTom Musta if (ISZERO(rhs)) return result; /* LHS wins or both 0 */
632772ac97cdSTom Musta /* RHS is non-zero */
632872ac97cdSTom Musta if (result==0) return -1; /* LHS is 0; RHS wins */
632972ac97cdSTom Musta /* [here, both non-zero, result=1] */
633072ac97cdSTom Musta }
633172ac97cdSTom Musta else { /* signs matter */
633272ac97cdSTom Musta if (result && decNumberIsNegative(lhs)) result=-1;
633372ac97cdSTom Musta sigr=1; /* compute signum(rhs) */
633472ac97cdSTom Musta if (ISZERO(rhs)) sigr=0;
633572ac97cdSTom Musta else if (decNumberIsNegative(rhs)) sigr=-1;
633672ac97cdSTom Musta if (result > sigr) return +1; /* L > R, return 1 */
633772ac97cdSTom Musta if (result < sigr) return -1; /* L < R, return -1 */
633872ac97cdSTom Musta if (result==0) return 0; /* both 0 */
633972ac97cdSTom Musta }
634072ac97cdSTom Musta
634172ac97cdSTom Musta /* signums are the same; both are non-zero */
634272ac97cdSTom Musta if ((lhs->bits | rhs->bits) & DECINF) { /* one or more infinities */
634372ac97cdSTom Musta if (decNumberIsInfinite(rhs)) {
634472ac97cdSTom Musta if (decNumberIsInfinite(lhs)) result=0;/* both infinite */
634572ac97cdSTom Musta else result=-result; /* only rhs infinite */
634672ac97cdSTom Musta }
634772ac97cdSTom Musta return result;
634872ac97cdSTom Musta }
634972ac97cdSTom Musta /* must compare the coefficients, allowing for exponents */
635072ac97cdSTom Musta if (lhs->exponent>rhs->exponent) { /* LHS exponent larger */
635172ac97cdSTom Musta /* swap sides, and sign */
635272ac97cdSTom Musta const decNumber *temp=lhs;
635372ac97cdSTom Musta lhs=rhs;
635472ac97cdSTom Musta rhs=temp;
635572ac97cdSTom Musta result=-result;
635672ac97cdSTom Musta }
635772ac97cdSTom Musta compare=decUnitCompare(lhs->lsu, D2U(lhs->digits),
635872ac97cdSTom Musta rhs->lsu, D2U(rhs->digits),
635972ac97cdSTom Musta rhs->exponent-lhs->exponent);
636072ac97cdSTom Musta if (compare!=BADINT) compare*=result; /* comparison succeeded */
636172ac97cdSTom Musta return compare;
636272ac97cdSTom Musta } /* decCompare */
636372ac97cdSTom Musta
636472ac97cdSTom Musta /* ------------------------------------------------------------------ */
636572ac97cdSTom Musta /* decUnitCompare -- compare two >=0 integers in Unit arrays */
636672ac97cdSTom Musta /* */
636772ac97cdSTom Musta /* This routine compares A ? B*10**E where A and B are unit arrays */
636872ac97cdSTom Musta /* A is a plain integer */
636972ac97cdSTom Musta /* B has an exponent of E (which must be non-negative) */
637072ac97cdSTom Musta /* */
637172ac97cdSTom Musta /* Arg1 is A first Unit (lsu) */
637272ac97cdSTom Musta /* Arg2 is A length in Units */
637372ac97cdSTom Musta /* Arg3 is B first Unit (lsu) */
637472ac97cdSTom Musta /* Arg4 is B length in Units */
637572ac97cdSTom Musta /* Arg5 is E (0 if the units are aligned) */
637672ac97cdSTom Musta /* */
637772ac97cdSTom Musta /* returns -1, 0, or 1 for A<B, A==B, or A>B, or BADINT if failure */
637872ac97cdSTom Musta /* (the only possible failure is an allocation error, which can */
637972ac97cdSTom Musta /* only occur if E!=0) */
638072ac97cdSTom Musta /* ------------------------------------------------------------------ */
638172ac97cdSTom Musta static Int decUnitCompare(const Unit *a, Int alength,
638272ac97cdSTom Musta const Unit *b, Int blength, Int exp) {
638372ac97cdSTom Musta Unit *acc; /* accumulator for result */
638472ac97cdSTom Musta Unit accbuff[SD2U(DECBUFFER*2+1)]; /* local buffer */
638572ac97cdSTom Musta Unit *allocacc=NULL; /* -> allocated acc buffer, iff allocated */
638672ac97cdSTom Musta Int accunits, need; /* units in use or needed for acc */
638772ac97cdSTom Musta const Unit *l, *r, *u; /* work */
638872ac97cdSTom Musta Int expunits, exprem, result; /* .. */
638972ac97cdSTom Musta
639072ac97cdSTom Musta if (exp==0) { /* aligned; fastpath */
639172ac97cdSTom Musta if (alength>blength) return 1;
639272ac97cdSTom Musta if (alength<blength) return -1;
639372ac97cdSTom Musta /* same number of units in both -- need unit-by-unit compare */
639472ac97cdSTom Musta l=a+alength-1;
639572ac97cdSTom Musta r=b+alength-1;
639672ac97cdSTom Musta for (;l>=a; l--, r--) {
639772ac97cdSTom Musta if (*l>*r) return 1;
639872ac97cdSTom Musta if (*l<*r) return -1;
639972ac97cdSTom Musta }
640072ac97cdSTom Musta return 0; /* all units match */
640172ac97cdSTom Musta } /* aligned */
640272ac97cdSTom Musta
640372ac97cdSTom Musta /* Unaligned. If one is >1 unit longer than the other, padded */
640472ac97cdSTom Musta /* approximately, then can return easily */
640572ac97cdSTom Musta if (alength>blength+(Int)D2U(exp)) return 1;
640672ac97cdSTom Musta if (alength+1<blength+(Int)D2U(exp)) return -1;
640772ac97cdSTom Musta
640872ac97cdSTom Musta /* Need to do a real subtract. For this, a result buffer is needed */
640972ac97cdSTom Musta /* even though only the sign is of interest. Its length needs */
641072ac97cdSTom Musta /* to be the larger of alength and padded blength, +2 */
641172ac97cdSTom Musta need=blength+D2U(exp); /* maximum real length of B */
641272ac97cdSTom Musta if (need<alength) need=alength;
641372ac97cdSTom Musta need+=2;
641472ac97cdSTom Musta acc=accbuff; /* assume use local buffer */
641572ac97cdSTom Musta if (need*sizeof(Unit)>sizeof(accbuff)) {
641672ac97cdSTom Musta allocacc=(Unit *)malloc(need*sizeof(Unit));
641772ac97cdSTom Musta if (allocacc==NULL) return BADINT; /* hopeless -- abandon */
641872ac97cdSTom Musta acc=allocacc;
641972ac97cdSTom Musta }
642072ac97cdSTom Musta /* Calculate units and remainder from exponent. */
642172ac97cdSTom Musta expunits=exp/DECDPUN;
642272ac97cdSTom Musta exprem=exp%DECDPUN;
642372ac97cdSTom Musta /* subtract [A+B*(-m)] */
642472ac97cdSTom Musta accunits=decUnitAddSub(a, alength, b, blength, expunits, acc,
642572ac97cdSTom Musta -(Int)powers[exprem]);
642672ac97cdSTom Musta /* [UnitAddSub result may have leading zeros, even on zero] */
642772ac97cdSTom Musta if (accunits<0) result=-1; /* negative result */
642872ac97cdSTom Musta else { /* non-negative result */
642972ac97cdSTom Musta /* check units of the result before freeing any storage */
643072ac97cdSTom Musta for (u=acc; u<acc+accunits-1 && *u==0;) u++;
643172ac97cdSTom Musta result=(*u==0 ? 0 : +1);
643272ac97cdSTom Musta }
643372ac97cdSTom Musta /* clean up and return the result */
643472ac97cdSTom Musta if (allocacc!=NULL) free(allocacc); /* drop any storage used */
643572ac97cdSTom Musta return result;
643672ac97cdSTom Musta } /* decUnitCompare */
643772ac97cdSTom Musta
643872ac97cdSTom Musta /* ------------------------------------------------------------------ */
643972ac97cdSTom Musta /* decUnitAddSub -- add or subtract two >=0 integers in Unit arrays */
644072ac97cdSTom Musta /* */
644172ac97cdSTom Musta /* This routine performs the calculation: */
644272ac97cdSTom Musta /* */
644372ac97cdSTom Musta /* C=A+(B*M) */
644472ac97cdSTom Musta /* */
644572ac97cdSTom Musta /* Where M is in the range -DECDPUNMAX through +DECDPUNMAX. */
644672ac97cdSTom Musta /* */
644772ac97cdSTom Musta /* A may be shorter or longer than B. */
644872ac97cdSTom Musta /* */
644972ac97cdSTom Musta /* Leading zeros are not removed after a calculation. The result is */
645072ac97cdSTom Musta /* either the same length as the longer of A and B (adding any */
645172ac97cdSTom Musta /* shift), or one Unit longer than that (if a Unit carry occurred). */
645272ac97cdSTom Musta /* */
645372ac97cdSTom Musta /* A and B content are not altered unless C is also A or B. */
645472ac97cdSTom Musta /* C may be the same array as A or B, but only if no zero padding is */
645572ac97cdSTom Musta /* requested (that is, C may be B only if bshift==0). */
645672ac97cdSTom Musta /* C is filled from the lsu; only those units necessary to complete */
645772ac97cdSTom Musta /* the calculation are referenced. */
645872ac97cdSTom Musta /* */
645972ac97cdSTom Musta /* Arg1 is A first Unit (lsu) */
646072ac97cdSTom Musta /* Arg2 is A length in Units */
646172ac97cdSTom Musta /* Arg3 is B first Unit (lsu) */
646272ac97cdSTom Musta /* Arg4 is B length in Units */
646372ac97cdSTom Musta /* Arg5 is B shift in Units (>=0; pads with 0 units if positive) */
646472ac97cdSTom Musta /* Arg6 is C first Unit (lsu) */
646572ac97cdSTom Musta /* Arg7 is M, the multiplier */
646672ac97cdSTom Musta /* */
646772ac97cdSTom Musta /* returns the count of Units written to C, which will be non-zero */
646872ac97cdSTom Musta /* and negated if the result is negative. That is, the sign of the */
646972ac97cdSTom Musta /* returned Int is the sign of the result (positive for zero) and */
647072ac97cdSTom Musta /* the absolute value of the Int is the count of Units. */
647172ac97cdSTom Musta /* */
647272ac97cdSTom Musta /* It is the caller's responsibility to make sure that C size is */
647372ac97cdSTom Musta /* safe, allowing space if necessary for a one-Unit carry. */
647472ac97cdSTom Musta /* */
647572ac97cdSTom Musta /* This routine is severely performance-critical; *any* change here */
647672ac97cdSTom Musta /* must be measured (timed) to assure no performance degradation. */
647772ac97cdSTom Musta /* In particular, trickery here tends to be counter-productive, as */
647872ac97cdSTom Musta /* increased complexity of code hurts register optimizations on */
647972ac97cdSTom Musta /* register-poor architectures. Avoiding divisions is nearly */
648072ac97cdSTom Musta /* always a Good Idea, however. */
648172ac97cdSTom Musta /* */
648272ac97cdSTom Musta /* Special thanks to Rick McGuire (IBM Cambridge, MA) and Dave Clark */
648372ac97cdSTom Musta /* (IBM Warwick, UK) for some of the ideas used in this routine. */
648472ac97cdSTom Musta /* ------------------------------------------------------------------ */
648572ac97cdSTom Musta static Int decUnitAddSub(const Unit *a, Int alength,
648672ac97cdSTom Musta const Unit *b, Int blength, Int bshift,
648772ac97cdSTom Musta Unit *c, Int m) {
648872ac97cdSTom Musta const Unit *alsu=a; /* A lsu [need to remember it] */
648972ac97cdSTom Musta Unit *clsu=c; /* C ditto */
649072ac97cdSTom Musta Unit *minC; /* low water mark for C */
649172ac97cdSTom Musta Unit *maxC; /* high water mark for C */
649272ac97cdSTom Musta eInt carry=0; /* carry integer (could be Long) */
649372ac97cdSTom Musta Int add; /* work */
649472ac97cdSTom Musta #if DECDPUN<=4 /* myriadal, millenary, etc. */
649572ac97cdSTom Musta Int est; /* estimated quotient */
649672ac97cdSTom Musta #endif
649772ac97cdSTom Musta
649872ac97cdSTom Musta #if DECTRACE
649972ac97cdSTom Musta if (alength<1 || blength<1)
650072ac97cdSTom Musta printf("decUnitAddSub: alen blen m %ld %ld [%ld]\n", alength, blength, m);
650172ac97cdSTom Musta #endif
650272ac97cdSTom Musta
650372ac97cdSTom Musta maxC=c+alength; /* A is usually the longer */
650472ac97cdSTom Musta minC=c+blength; /* .. and B the shorter */
650572ac97cdSTom Musta if (bshift!=0) { /* B is shifted; low As copy across */
650672ac97cdSTom Musta minC+=bshift;
650772ac97cdSTom Musta /* if in place [common], skip copy unless there's a gap [rare] */
650872ac97cdSTom Musta if (a==c && bshift<=alength) {
650972ac97cdSTom Musta c+=bshift;
651072ac97cdSTom Musta a+=bshift;
651172ac97cdSTom Musta }
651272ac97cdSTom Musta else for (; c<clsu+bshift; a++, c++) { /* copy needed */
651372ac97cdSTom Musta if (a<alsu+alength) *c=*a;
651472ac97cdSTom Musta else *c=0;
651572ac97cdSTom Musta }
651672ac97cdSTom Musta }
651772ac97cdSTom Musta if (minC>maxC) { /* swap */
651872ac97cdSTom Musta Unit *hold=minC;
651972ac97cdSTom Musta minC=maxC;
652072ac97cdSTom Musta maxC=hold;
652172ac97cdSTom Musta }
652272ac97cdSTom Musta
652372ac97cdSTom Musta /* For speed, do the addition as two loops; the first where both A */
652472ac97cdSTom Musta /* and B contribute, and the second (if necessary) where only one or */
652572ac97cdSTom Musta /* other of the numbers contribute. */
652672ac97cdSTom Musta /* Carry handling is the same (i.e., duplicated) in each case. */
652772ac97cdSTom Musta for (; c<minC; c++) {
652872ac97cdSTom Musta carry+=*a;
652972ac97cdSTom Musta a++;
653072ac97cdSTom Musta carry+=((eInt)*b)*m; /* [special-casing m=1/-1 */
653172ac97cdSTom Musta b++; /* here is not a win] */
653272ac97cdSTom Musta /* here carry is new Unit of digits; it could be +ve or -ve */
653372ac97cdSTom Musta if ((ueInt)carry<=DECDPUNMAX) { /* fastpath 0-DECDPUNMAX */
653472ac97cdSTom Musta *c=(Unit)carry;
653572ac97cdSTom Musta carry=0;
653672ac97cdSTom Musta continue;
653772ac97cdSTom Musta }
653872ac97cdSTom Musta #if DECDPUN==4 /* use divide-by-multiply */
653972ac97cdSTom Musta if (carry>=0) {
654072ac97cdSTom Musta est=(((ueInt)carry>>11)*53687)>>18;
654172ac97cdSTom Musta *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
654272ac97cdSTom Musta carry=est; /* likely quotient [89%] */
654372ac97cdSTom Musta if (*c<DECDPUNMAX+1) continue; /* estimate was correct */
654472ac97cdSTom Musta carry++;
654572ac97cdSTom Musta *c-=DECDPUNMAX+1;
654672ac97cdSTom Musta continue;
654772ac97cdSTom Musta }
654872ac97cdSTom Musta /* negative case */
654972ac97cdSTom Musta carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
655072ac97cdSTom Musta est=(((ueInt)carry>>11)*53687)>>18;
655172ac97cdSTom Musta *c=(Unit)(carry-est*(DECDPUNMAX+1));
655272ac97cdSTom Musta carry=est-(DECDPUNMAX+1); /* correctly negative */
655372ac97cdSTom Musta if (*c<DECDPUNMAX+1) continue; /* was OK */
655472ac97cdSTom Musta carry++;
655572ac97cdSTom Musta *c-=DECDPUNMAX+1;
655672ac97cdSTom Musta #elif DECDPUN==3
655772ac97cdSTom Musta if (carry>=0) {
655872ac97cdSTom Musta est=(((ueInt)carry>>3)*16777)>>21;
655972ac97cdSTom Musta *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
656072ac97cdSTom Musta carry=est; /* likely quotient [99%] */
656172ac97cdSTom Musta if (*c<DECDPUNMAX+1) continue; /* estimate was correct */
656272ac97cdSTom Musta carry++;
656372ac97cdSTom Musta *c-=DECDPUNMAX+1;
656472ac97cdSTom Musta continue;
656572ac97cdSTom Musta }
656672ac97cdSTom Musta /* negative case */
656772ac97cdSTom Musta carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
656872ac97cdSTom Musta est=(((ueInt)carry>>3)*16777)>>21;
656972ac97cdSTom Musta *c=(Unit)(carry-est*(DECDPUNMAX+1));
657072ac97cdSTom Musta carry=est-(DECDPUNMAX+1); /* correctly negative */
657172ac97cdSTom Musta if (*c<DECDPUNMAX+1) continue; /* was OK */
657272ac97cdSTom Musta carry++;
657372ac97cdSTom Musta *c-=DECDPUNMAX+1;
657472ac97cdSTom Musta #elif DECDPUN<=2
657572ac97cdSTom Musta /* Can use QUOT10 as carry <= 4 digits */
657672ac97cdSTom Musta if (carry>=0) {
657772ac97cdSTom Musta est=QUOT10(carry, DECDPUN);
657872ac97cdSTom Musta *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
657972ac97cdSTom Musta carry=est; /* quotient */
658072ac97cdSTom Musta continue;
658172ac97cdSTom Musta }
658272ac97cdSTom Musta /* negative case */
658372ac97cdSTom Musta carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
658472ac97cdSTom Musta est=QUOT10(carry, DECDPUN);
658572ac97cdSTom Musta *c=(Unit)(carry-est*(DECDPUNMAX+1));
658672ac97cdSTom Musta carry=est-(DECDPUNMAX+1); /* correctly negative */
658772ac97cdSTom Musta #else
658872ac97cdSTom Musta /* remainder operator is undefined if negative, so must test */
658972ac97cdSTom Musta if ((ueInt)carry<(DECDPUNMAX+1)*2) { /* fastpath carry +1 */
659072ac97cdSTom Musta *c=(Unit)(carry-(DECDPUNMAX+1)); /* [helps additions] */
659172ac97cdSTom Musta carry=1;
659272ac97cdSTom Musta continue;
659372ac97cdSTom Musta }
659472ac97cdSTom Musta if (carry>=0) {
659572ac97cdSTom Musta *c=(Unit)(carry%(DECDPUNMAX+1));
659672ac97cdSTom Musta carry=carry/(DECDPUNMAX+1);
659772ac97cdSTom Musta continue;
659872ac97cdSTom Musta }
659972ac97cdSTom Musta /* negative case */
660072ac97cdSTom Musta carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
660172ac97cdSTom Musta *c=(Unit)(carry%(DECDPUNMAX+1));
660272ac97cdSTom Musta carry=carry/(DECDPUNMAX+1)-(DECDPUNMAX+1);
660372ac97cdSTom Musta #endif
660472ac97cdSTom Musta } /* c */
660572ac97cdSTom Musta
660672ac97cdSTom Musta /* now may have one or other to complete */
660772ac97cdSTom Musta /* [pretest to avoid loop setup/shutdown] */
660872ac97cdSTom Musta if (c<maxC) for (; c<maxC; c++) {
660972ac97cdSTom Musta if (a<alsu+alength) { /* still in A */
661072ac97cdSTom Musta carry+=*a;
661172ac97cdSTom Musta a++;
661272ac97cdSTom Musta }
661372ac97cdSTom Musta else { /* inside B */
661472ac97cdSTom Musta carry+=((eInt)*b)*m;
661572ac97cdSTom Musta b++;
661672ac97cdSTom Musta }
661772ac97cdSTom Musta /* here carry is new Unit of digits; it could be +ve or -ve and */
661872ac97cdSTom Musta /* magnitude up to DECDPUNMAX squared */
661972ac97cdSTom Musta if ((ueInt)carry<=DECDPUNMAX) { /* fastpath 0-DECDPUNMAX */
662072ac97cdSTom Musta *c=(Unit)carry;
662172ac97cdSTom Musta carry=0;
662272ac97cdSTom Musta continue;
662372ac97cdSTom Musta }
662472ac97cdSTom Musta /* result for this unit is negative or >DECDPUNMAX */
662572ac97cdSTom Musta #if DECDPUN==4 /* use divide-by-multiply */
662672ac97cdSTom Musta if (carry>=0) {
662772ac97cdSTom Musta est=(((ueInt)carry>>11)*53687)>>18;
662872ac97cdSTom Musta *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
662972ac97cdSTom Musta carry=est; /* likely quotient [79.7%] */
663072ac97cdSTom Musta if (*c<DECDPUNMAX+1) continue; /* estimate was correct */
663172ac97cdSTom Musta carry++;
663272ac97cdSTom Musta *c-=DECDPUNMAX+1;
663372ac97cdSTom Musta continue;
663472ac97cdSTom Musta }
663572ac97cdSTom Musta /* negative case */
663672ac97cdSTom Musta carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
663772ac97cdSTom Musta est=(((ueInt)carry>>11)*53687)>>18;
663872ac97cdSTom Musta *c=(Unit)(carry-est*(DECDPUNMAX+1));
663972ac97cdSTom Musta carry=est-(DECDPUNMAX+1); /* correctly negative */
664072ac97cdSTom Musta if (*c<DECDPUNMAX+1) continue; /* was OK */
664172ac97cdSTom Musta carry++;
664272ac97cdSTom Musta *c-=DECDPUNMAX+1;
664372ac97cdSTom Musta #elif DECDPUN==3
664472ac97cdSTom Musta if (carry>=0) {
664572ac97cdSTom Musta est=(((ueInt)carry>>3)*16777)>>21;
664672ac97cdSTom Musta *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
664772ac97cdSTom Musta carry=est; /* likely quotient [99%] */
664872ac97cdSTom Musta if (*c<DECDPUNMAX+1) continue; /* estimate was correct */
664972ac97cdSTom Musta carry++;
665072ac97cdSTom Musta *c-=DECDPUNMAX+1;
665172ac97cdSTom Musta continue;
665272ac97cdSTom Musta }
665372ac97cdSTom Musta /* negative case */
665472ac97cdSTom Musta carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
665572ac97cdSTom Musta est=(((ueInt)carry>>3)*16777)>>21;
665672ac97cdSTom Musta *c=(Unit)(carry-est*(DECDPUNMAX+1));
665772ac97cdSTom Musta carry=est-(DECDPUNMAX+1); /* correctly negative */
665872ac97cdSTom Musta if (*c<DECDPUNMAX+1) continue; /* was OK */
665972ac97cdSTom Musta carry++;
666072ac97cdSTom Musta *c-=DECDPUNMAX+1;
666172ac97cdSTom Musta #elif DECDPUN<=2
666272ac97cdSTom Musta if (carry>=0) {
666372ac97cdSTom Musta est=QUOT10(carry, DECDPUN);
666472ac97cdSTom Musta *c=(Unit)(carry-est*(DECDPUNMAX+1)); /* remainder */
666572ac97cdSTom Musta carry=est; /* quotient */
666672ac97cdSTom Musta continue;
666772ac97cdSTom Musta }
666872ac97cdSTom Musta /* negative case */
666972ac97cdSTom Musta carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
667072ac97cdSTom Musta est=QUOT10(carry, DECDPUN);
667172ac97cdSTom Musta *c=(Unit)(carry-est*(DECDPUNMAX+1));
667272ac97cdSTom Musta carry=est-(DECDPUNMAX+1); /* correctly negative */
667372ac97cdSTom Musta #else
667472ac97cdSTom Musta if ((ueInt)carry<(DECDPUNMAX+1)*2){ /* fastpath carry 1 */
667572ac97cdSTom Musta *c=(Unit)(carry-(DECDPUNMAX+1));
667672ac97cdSTom Musta carry=1;
667772ac97cdSTom Musta continue;
667872ac97cdSTom Musta }
667972ac97cdSTom Musta /* remainder operator is undefined if negative, so must test */
668072ac97cdSTom Musta if (carry>=0) {
668172ac97cdSTom Musta *c=(Unit)(carry%(DECDPUNMAX+1));
668272ac97cdSTom Musta carry=carry/(DECDPUNMAX+1);
668372ac97cdSTom Musta continue;
668472ac97cdSTom Musta }
668572ac97cdSTom Musta /* negative case */
668672ac97cdSTom Musta carry=carry+(eInt)(DECDPUNMAX+1)*(DECDPUNMAX+1); /* make positive */
668772ac97cdSTom Musta *c=(Unit)(carry%(DECDPUNMAX+1));
668872ac97cdSTom Musta carry=carry/(DECDPUNMAX+1)-(DECDPUNMAX+1);
668972ac97cdSTom Musta #endif
669072ac97cdSTom Musta } /* c */
669172ac97cdSTom Musta
669272ac97cdSTom Musta /* OK, all A and B processed; might still have carry or borrow */
669372ac97cdSTom Musta /* return number of Units in the result, negated if a borrow */
669472ac97cdSTom Musta if (carry==0) return c-clsu; /* no carry, so no more to do */
669572ac97cdSTom Musta if (carry>0) { /* positive carry */
669672ac97cdSTom Musta *c=(Unit)carry; /* place as new unit */
669772ac97cdSTom Musta c++; /* .. */
669872ac97cdSTom Musta return c-clsu;
669972ac97cdSTom Musta }
670072ac97cdSTom Musta /* -ve carry: it's a borrow; complement needed */
670172ac97cdSTom Musta add=1; /* temporary carry... */
670272ac97cdSTom Musta for (c=clsu; c<maxC; c++) {
670372ac97cdSTom Musta add=DECDPUNMAX+add-*c;
670472ac97cdSTom Musta if (add<=DECDPUNMAX) {
670572ac97cdSTom Musta *c=(Unit)add;
670672ac97cdSTom Musta add=0;
670772ac97cdSTom Musta }
670872ac97cdSTom Musta else {
670972ac97cdSTom Musta *c=0;
671072ac97cdSTom Musta add=1;
671172ac97cdSTom Musta }
671272ac97cdSTom Musta }
671372ac97cdSTom Musta /* add an extra unit iff it would be non-zero */
671472ac97cdSTom Musta #if DECTRACE
671572ac97cdSTom Musta printf("UAS borrow: add %ld, carry %ld\n", add, carry);
671672ac97cdSTom Musta #endif
671772ac97cdSTom Musta if ((add-carry-1)!=0) {
671872ac97cdSTom Musta *c=(Unit)(add-carry-1);
671972ac97cdSTom Musta c++; /* interesting, include it */
672072ac97cdSTom Musta }
672172ac97cdSTom Musta return clsu-c; /* -ve result indicates borrowed */
672272ac97cdSTom Musta } /* decUnitAddSub */
672372ac97cdSTom Musta
672472ac97cdSTom Musta /* ------------------------------------------------------------------ */
672572ac97cdSTom Musta /* decTrim -- trim trailing zeros or normalize */
672672ac97cdSTom Musta /* */
672772ac97cdSTom Musta /* dn is the number to trim or normalize */
672872ac97cdSTom Musta /* set is the context to use to check for clamp */
672972ac97cdSTom Musta /* all is 1 to remove all trailing zeros, 0 for just fraction ones */
673072ac97cdSTom Musta /* dropped returns the number of discarded trailing zeros */
673172ac97cdSTom Musta /* returns dn */
673272ac97cdSTom Musta /* */
673372ac97cdSTom Musta /* If clamp is set in the context then the number of zeros trimmed */
673472ac97cdSTom Musta /* may be limited if the exponent is high. */
673572ac97cdSTom Musta /* All fields are updated as required. This is a utility operation, */
673672ac97cdSTom Musta /* so special values are unchanged and no error is possible. */
673772ac97cdSTom Musta /* ------------------------------------------------------------------ */
673872ac97cdSTom Musta static decNumber * decTrim(decNumber *dn, decContext *set, Flag all,
673972ac97cdSTom Musta Int *dropped) {
674072ac97cdSTom Musta Int d, exp; /* work */
674172ac97cdSTom Musta uInt cut; /* .. */
674272ac97cdSTom Musta Unit *up; /* -> current Unit */
674372ac97cdSTom Musta
674472ac97cdSTom Musta #if DECCHECK
674572ac97cdSTom Musta if (decCheckOperands(dn, DECUNUSED, DECUNUSED, DECUNCONT)) return dn;
674672ac97cdSTom Musta #endif
674772ac97cdSTom Musta
674872ac97cdSTom Musta *dropped=0; /* assume no zeros dropped */
674972ac97cdSTom Musta if ((dn->bits & DECSPECIAL) /* fast exit if special .. */
675072ac97cdSTom Musta || (*dn->lsu & 0x01)) return dn; /* .. or odd */
675172ac97cdSTom Musta if (ISZERO(dn)) { /* .. or 0 */
675272ac97cdSTom Musta dn->exponent=0; /* (sign is preserved) */
675372ac97cdSTom Musta return dn;
675472ac97cdSTom Musta }
675572ac97cdSTom Musta
675672ac97cdSTom Musta /* have a finite number which is even */
675772ac97cdSTom Musta exp=dn->exponent;
675872ac97cdSTom Musta cut=1; /* digit (1-DECDPUN) in Unit */
675972ac97cdSTom Musta up=dn->lsu; /* -> current Unit */
676072ac97cdSTom Musta for (d=0; d<dn->digits-1; d++) { /* [don't strip the final digit] */
676172ac97cdSTom Musta /* slice by powers */
676272ac97cdSTom Musta #if DECDPUN<=4
676372ac97cdSTom Musta uInt quot=QUOT10(*up, cut);
676472ac97cdSTom Musta if ((*up-quot*powers[cut])!=0) break; /* found non-0 digit */
676572ac97cdSTom Musta #else
676672ac97cdSTom Musta if (*up%powers[cut]!=0) break; /* found non-0 digit */
676772ac97cdSTom Musta #endif
676872ac97cdSTom Musta /* have a trailing 0 */
676972ac97cdSTom Musta if (!all) { /* trimming */
677072ac97cdSTom Musta /* [if exp>0 then all trailing 0s are significant for trim] */
677172ac97cdSTom Musta if (exp<=0) { /* if digit might be significant */
677272ac97cdSTom Musta if (exp==0) break; /* then quit */
677372ac97cdSTom Musta exp++; /* next digit might be significant */
677472ac97cdSTom Musta }
677572ac97cdSTom Musta }
677672ac97cdSTom Musta cut++; /* next power */
677772ac97cdSTom Musta if (cut>DECDPUN) { /* need new Unit */
677872ac97cdSTom Musta up++;
677972ac97cdSTom Musta cut=1;
678072ac97cdSTom Musta }
678172ac97cdSTom Musta } /* d */
678272ac97cdSTom Musta if (d==0) return dn; /* none to drop */
678372ac97cdSTom Musta
678472ac97cdSTom Musta /* may need to limit drop if clamping */
678572ac97cdSTom Musta if (set->clamp) {
678672ac97cdSTom Musta Int maxd=set->emax-set->digits+1-dn->exponent;
678772ac97cdSTom Musta if (maxd<=0) return dn; /* nothing possible */
678872ac97cdSTom Musta if (d>maxd) d=maxd;
678972ac97cdSTom Musta }
679072ac97cdSTom Musta
679172ac97cdSTom Musta /* effect the drop */
679272ac97cdSTom Musta decShiftToLeast(dn->lsu, D2U(dn->digits), d);
679372ac97cdSTom Musta dn->exponent+=d; /* maintain numerical value */
679472ac97cdSTom Musta dn->digits-=d; /* new length */
679572ac97cdSTom Musta *dropped=d; /* report the count */
679672ac97cdSTom Musta return dn;
679772ac97cdSTom Musta } /* decTrim */
679872ac97cdSTom Musta
679972ac97cdSTom Musta /* ------------------------------------------------------------------ */
680072ac97cdSTom Musta /* decReverse -- reverse a Unit array in place */
680172ac97cdSTom Musta /* */
680272ac97cdSTom Musta /* ulo is the start of the array */
680372ac97cdSTom Musta /* uhi is the end of the array (highest Unit to include) */
680472ac97cdSTom Musta /* */
680572ac97cdSTom Musta /* The units ulo through uhi are reversed in place (if the number */
680672ac97cdSTom Musta /* of units is odd, the middle one is untouched). Note that the */
680772ac97cdSTom Musta /* digit(s) in each unit are unaffected. */
680872ac97cdSTom Musta /* ------------------------------------------------------------------ */
680972ac97cdSTom Musta static void decReverse(Unit *ulo, Unit *uhi) {
681072ac97cdSTom Musta Unit temp;
681172ac97cdSTom Musta for (; ulo<uhi; ulo++, uhi--) {
681272ac97cdSTom Musta temp=*ulo;
681372ac97cdSTom Musta *ulo=*uhi;
681472ac97cdSTom Musta *uhi=temp;
681572ac97cdSTom Musta }
681672ac97cdSTom Musta return;
681772ac97cdSTom Musta } /* decReverse */
681872ac97cdSTom Musta
681972ac97cdSTom Musta /* ------------------------------------------------------------------ */
682072ac97cdSTom Musta /* decShiftToMost -- shift digits in array towards most significant */
682172ac97cdSTom Musta /* */
682272ac97cdSTom Musta /* uar is the array */
682372ac97cdSTom Musta /* digits is the count of digits in use in the array */
682472ac97cdSTom Musta /* shift is the number of zeros to pad with (least significant); */
682572ac97cdSTom Musta /* it must be zero or positive */
682672ac97cdSTom Musta /* */
682772ac97cdSTom Musta /* returns the new length of the integer in the array, in digits */
682872ac97cdSTom Musta /* */
682972ac97cdSTom Musta /* No overflow is permitted (that is, the uar array must be known to */
683072ac97cdSTom Musta /* be large enough to hold the result, after shifting). */
683172ac97cdSTom Musta /* ------------------------------------------------------------------ */
683272ac97cdSTom Musta static Int decShiftToMost(Unit *uar, Int digits, Int shift) {
683372ac97cdSTom Musta Unit *target, *source, *first; /* work */
683472ac97cdSTom Musta Int cut; /* odd 0's to add */
683572ac97cdSTom Musta uInt next; /* work */
683672ac97cdSTom Musta
683772ac97cdSTom Musta if (shift==0) return digits; /* [fastpath] nothing to do */
683872ac97cdSTom Musta if ((digits+shift)<=DECDPUN) { /* [fastpath] single-unit case */
683972ac97cdSTom Musta *uar=(Unit)(*uar*powers[shift]);
684072ac97cdSTom Musta return digits+shift;
684172ac97cdSTom Musta }
684272ac97cdSTom Musta
684372ac97cdSTom Musta next=0; /* all paths */
684472ac97cdSTom Musta source=uar+D2U(digits)-1; /* where msu comes from */
684572ac97cdSTom Musta target=source+D2U(shift); /* where upper part of first cut goes */
684672ac97cdSTom Musta cut=DECDPUN-MSUDIGITS(shift); /* where to slice */
684772ac97cdSTom Musta if (cut==0) { /* unit-boundary case */
684872ac97cdSTom Musta for (; source>=uar; source--, target--) *target=*source;
684972ac97cdSTom Musta }
685072ac97cdSTom Musta else {
685172ac97cdSTom Musta first=uar+D2U(digits+shift)-1; /* where msu of source will end up */
685272ac97cdSTom Musta for (; source>=uar; source--, target--) {
685372ac97cdSTom Musta /* split the source Unit and accumulate remainder for next */
685472ac97cdSTom Musta #if DECDPUN<=4
685572ac97cdSTom Musta uInt quot=QUOT10(*source, cut);
685672ac97cdSTom Musta uInt rem=*source-quot*powers[cut];
685772ac97cdSTom Musta next+=quot;
685872ac97cdSTom Musta #else
685972ac97cdSTom Musta uInt rem=*source%powers[cut];
686072ac97cdSTom Musta next+=*source/powers[cut];
686172ac97cdSTom Musta #endif
686272ac97cdSTom Musta if (target<=first) *target=(Unit)next; /* write to target iff valid */
686372ac97cdSTom Musta next=rem*powers[DECDPUN-cut]; /* save remainder for next Unit */
686472ac97cdSTom Musta }
686572ac97cdSTom Musta } /* shift-move */
686672ac97cdSTom Musta
686772ac97cdSTom Musta /* propagate any partial unit to one below and clear the rest */
686872ac97cdSTom Musta for (; target>=uar; target--) {
686972ac97cdSTom Musta *target=(Unit)next;
687072ac97cdSTom Musta next=0;
687172ac97cdSTom Musta }
687272ac97cdSTom Musta return digits+shift;
687372ac97cdSTom Musta } /* decShiftToMost */
687472ac97cdSTom Musta
687572ac97cdSTom Musta /* ------------------------------------------------------------------ */
687672ac97cdSTom Musta /* decShiftToLeast -- shift digits in array towards least significant */
687772ac97cdSTom Musta /* */
687872ac97cdSTom Musta /* uar is the array */
687972ac97cdSTom Musta /* units is length of the array, in units */
688072ac97cdSTom Musta /* shift is the number of digits to remove from the lsu end; it */
688172ac97cdSTom Musta /* must be zero or positive and <= than units*DECDPUN. */
688272ac97cdSTom Musta /* */
688372ac97cdSTom Musta /* returns the new length of the integer in the array, in units */
688472ac97cdSTom Musta /* */
688572ac97cdSTom Musta /* Removed digits are discarded (lost). Units not required to hold */
688672ac97cdSTom Musta /* the final result are unchanged. */
688772ac97cdSTom Musta /* ------------------------------------------------------------------ */
688872ac97cdSTom Musta static Int decShiftToLeast(Unit *uar, Int units, Int shift) {
688972ac97cdSTom Musta Unit *target, *up; /* work */
689072ac97cdSTom Musta Int cut, count; /* work */
689172ac97cdSTom Musta Int quot, rem; /* for division */
689272ac97cdSTom Musta
689372ac97cdSTom Musta if (shift==0) return units; /* [fastpath] nothing to do */
689472ac97cdSTom Musta if (shift==units*DECDPUN) { /* [fastpath] little to do */
689572ac97cdSTom Musta *uar=0; /* all digits cleared gives zero */
689672ac97cdSTom Musta return 1; /* leaves just the one */
689772ac97cdSTom Musta }
689872ac97cdSTom Musta
689972ac97cdSTom Musta target=uar; /* both paths */
690072ac97cdSTom Musta cut=MSUDIGITS(shift);
690172ac97cdSTom Musta if (cut==DECDPUN) { /* unit-boundary case; easy */
690272ac97cdSTom Musta up=uar+D2U(shift);
690372ac97cdSTom Musta for (; up<uar+units; target++, up++) *target=*up;
690472ac97cdSTom Musta return target-uar;
690572ac97cdSTom Musta }
690672ac97cdSTom Musta
690772ac97cdSTom Musta /* messier */
690872ac97cdSTom Musta up=uar+D2U(shift-cut); /* source; correct to whole Units */
690972ac97cdSTom Musta count=units*DECDPUN-shift; /* the maximum new length */
691072ac97cdSTom Musta #if DECDPUN<=4
691172ac97cdSTom Musta quot=QUOT10(*up, cut);
691272ac97cdSTom Musta #else
691372ac97cdSTom Musta quot=*up/powers[cut];
691472ac97cdSTom Musta #endif
691572ac97cdSTom Musta for (; ; target++) {
691672ac97cdSTom Musta *target=(Unit)quot;
691772ac97cdSTom Musta count-=(DECDPUN-cut);
691872ac97cdSTom Musta if (count<=0) break;
691972ac97cdSTom Musta up++;
692072ac97cdSTom Musta quot=*up;
692172ac97cdSTom Musta #if DECDPUN<=4
692272ac97cdSTom Musta quot=QUOT10(quot, cut);
692372ac97cdSTom Musta rem=*up-quot*powers[cut];
692472ac97cdSTom Musta #else
692572ac97cdSTom Musta rem=quot%powers[cut];
692672ac97cdSTom Musta quot=quot/powers[cut];
692772ac97cdSTom Musta #endif
692872ac97cdSTom Musta *target=(Unit)(*target+rem*powers[DECDPUN-cut]);
692972ac97cdSTom Musta count-=cut;
693072ac97cdSTom Musta if (count<=0) break;
693172ac97cdSTom Musta }
693272ac97cdSTom Musta return target-uar+1;
693372ac97cdSTom Musta } /* decShiftToLeast */
693472ac97cdSTom Musta
693572ac97cdSTom Musta #if DECSUBSET
693672ac97cdSTom Musta /* ------------------------------------------------------------------ */
693772ac97cdSTom Musta /* decRoundOperand -- round an operand [used for subset only] */
693872ac97cdSTom Musta /* */
693972ac97cdSTom Musta /* dn is the number to round (dn->digits is > set->digits) */
694072ac97cdSTom Musta /* set is the relevant context */
694172ac97cdSTom Musta /* status is the status accumulator */
694272ac97cdSTom Musta /* */
694372ac97cdSTom Musta /* returns an allocated decNumber with the rounded result. */
694472ac97cdSTom Musta /* */
694572ac97cdSTom Musta /* lostDigits and other status may be set by this. */
694672ac97cdSTom Musta /* */
694772ac97cdSTom Musta /* Since the input is an operand, it must not be modified. */
694872ac97cdSTom Musta /* Instead, return an allocated decNumber, rounded as required. */
694972ac97cdSTom Musta /* It is the caller's responsibility to free the allocated storage. */
695072ac97cdSTom Musta /* */
695172ac97cdSTom Musta /* If no storage is available then the result cannot be used, so NULL */
695272ac97cdSTom Musta /* is returned. */
695372ac97cdSTom Musta /* ------------------------------------------------------------------ */
695472ac97cdSTom Musta static decNumber *decRoundOperand(const decNumber *dn, decContext *set,
695572ac97cdSTom Musta uInt *status) {
695672ac97cdSTom Musta decNumber *res; /* result structure */
695772ac97cdSTom Musta uInt newstatus=0; /* status from round */
695872ac97cdSTom Musta Int residue=0; /* rounding accumulator */
695972ac97cdSTom Musta
696072ac97cdSTom Musta /* Allocate storage for the returned decNumber, big enough for the */
696172ac97cdSTom Musta /* length specified by the context */
696272ac97cdSTom Musta res=(decNumber *)malloc(sizeof(decNumber)
696372ac97cdSTom Musta +(D2U(set->digits)-1)*sizeof(Unit));
696472ac97cdSTom Musta if (res==NULL) {
696572ac97cdSTom Musta *status|=DEC_Insufficient_storage;
696672ac97cdSTom Musta return NULL;
696772ac97cdSTom Musta }
696872ac97cdSTom Musta decCopyFit(res, dn, set, &residue, &newstatus);
696972ac97cdSTom Musta decApplyRound(res, set, residue, &newstatus);
697072ac97cdSTom Musta
697172ac97cdSTom Musta /* If that set Inexact then "lost digits" is raised... */
697272ac97cdSTom Musta if (newstatus & DEC_Inexact) newstatus|=DEC_Lost_digits;
697372ac97cdSTom Musta *status|=newstatus;
697472ac97cdSTom Musta return res;
697572ac97cdSTom Musta } /* decRoundOperand */
697672ac97cdSTom Musta #endif
697772ac97cdSTom Musta
697872ac97cdSTom Musta /* ------------------------------------------------------------------ */
697972ac97cdSTom Musta /* decCopyFit -- copy a number, truncating the coefficient if needed */
698072ac97cdSTom Musta /* */
698172ac97cdSTom Musta /* dest is the target decNumber */
698272ac97cdSTom Musta /* src is the source decNumber */
698372ac97cdSTom Musta /* set is the context [used for length (digits) and rounding mode] */
698472ac97cdSTom Musta /* residue is the residue accumulator */
698572ac97cdSTom Musta /* status contains the current status to be updated */
698672ac97cdSTom Musta /* */
698772ac97cdSTom Musta /* (dest==src is allowed and will be a no-op if fits) */
698872ac97cdSTom Musta /* All fields are updated as required. */
698972ac97cdSTom Musta /* ------------------------------------------------------------------ */
699072ac97cdSTom Musta static void decCopyFit(decNumber *dest, const decNumber *src,
699172ac97cdSTom Musta decContext *set, Int *residue, uInt *status) {
699272ac97cdSTom Musta dest->bits=src->bits;
699372ac97cdSTom Musta dest->exponent=src->exponent;
699472ac97cdSTom Musta decSetCoeff(dest, set, src->lsu, src->digits, residue, status);
699572ac97cdSTom Musta } /* decCopyFit */
699672ac97cdSTom Musta
699772ac97cdSTom Musta /* ------------------------------------------------------------------ */
699872ac97cdSTom Musta /* decSetCoeff -- set the coefficient of a number */
699972ac97cdSTom Musta /* */
700072ac97cdSTom Musta /* dn is the number whose coefficient array is to be set. */
700172ac97cdSTom Musta /* It must have space for set->digits digits */
700272ac97cdSTom Musta /* set is the context [for size] */
700372ac97cdSTom Musta /* lsu -> lsu of the source coefficient [may be dn->lsu] */
700472ac97cdSTom Musta /* len is digits in the source coefficient [may be dn->digits] */
700572ac97cdSTom Musta /* residue is the residue accumulator. This has values as in */
700672ac97cdSTom Musta /* decApplyRound, and will be unchanged unless the */
700772ac97cdSTom Musta /* target size is less than len. In this case, the */
700872ac97cdSTom Musta /* coefficient is truncated and the residue is updated to */
700972ac97cdSTom Musta /* reflect the previous residue and the dropped digits. */
701072ac97cdSTom Musta /* status is the status accumulator, as usual */
701172ac97cdSTom Musta /* */
701272ac97cdSTom Musta /* The coefficient may already be in the number, or it can be an */
701372ac97cdSTom Musta /* external intermediate array. If it is in the number, lsu must == */
701472ac97cdSTom Musta /* dn->lsu and len must == dn->digits. */
701572ac97cdSTom Musta /* */
701672ac97cdSTom Musta /* Note that the coefficient length (len) may be < set->digits, and */
701772ac97cdSTom Musta /* in this case this merely copies the coefficient (or is a no-op */
701872ac97cdSTom Musta /* if dn->lsu==lsu). */
701972ac97cdSTom Musta /* */
702072ac97cdSTom Musta /* Note also that (only internally, from decQuantizeOp and */
702172ac97cdSTom Musta /* decSetSubnormal) the value of set->digits may be less than one, */
702272ac97cdSTom Musta /* indicating a round to left. This routine handles that case */
702372ac97cdSTom Musta /* correctly; caller ensures space. */
702472ac97cdSTom Musta /* */
702572ac97cdSTom Musta /* dn->digits, dn->lsu (and as required), and dn->exponent are */
702672ac97cdSTom Musta /* updated as necessary. dn->bits (sign) is unchanged. */
702772ac97cdSTom Musta /* */
702872ac97cdSTom Musta /* DEC_Rounded status is set if any digits are discarded. */
702972ac97cdSTom Musta /* DEC_Inexact status is set if any non-zero digits are discarded, or */
703072ac97cdSTom Musta /* incoming residue was non-0 (implies rounded) */
703172ac97cdSTom Musta /* ------------------------------------------------------------------ */
703272ac97cdSTom Musta /* mapping array: maps 0-9 to canonical residues, so that a residue */
703372ac97cdSTom Musta /* can be adjusted in the range [-1, +1] and achieve correct rounding */
703472ac97cdSTom Musta /* 0 1 2 3 4 5 6 7 8 9 */
703572ac97cdSTom Musta static const uByte resmap[10]={0, 3, 3, 3, 3, 5, 7, 7, 7, 7};
703672ac97cdSTom Musta static void decSetCoeff(decNumber *dn, decContext *set, const Unit *lsu,
703772ac97cdSTom Musta Int len, Int *residue, uInt *status) {
703872ac97cdSTom Musta Int discard; /* number of digits to discard */
703972ac97cdSTom Musta uInt cut; /* cut point in Unit */
704072ac97cdSTom Musta const Unit *up; /* work */
704172ac97cdSTom Musta Unit *target; /* .. */
704272ac97cdSTom Musta Int count; /* .. */
704372ac97cdSTom Musta #if DECDPUN<=4
704472ac97cdSTom Musta uInt temp; /* .. */
704572ac97cdSTom Musta #endif
704672ac97cdSTom Musta
704772ac97cdSTom Musta discard=len-set->digits; /* digits to discard */
704872ac97cdSTom Musta if (discard<=0) { /* no digits are being discarded */
704972ac97cdSTom Musta if (dn->lsu!=lsu) { /* copy needed */
705072ac97cdSTom Musta /* copy the coefficient array to the result number; no shift needed */
705172ac97cdSTom Musta count=len; /* avoids D2U */
705272ac97cdSTom Musta up=lsu;
705372ac97cdSTom Musta for (target=dn->lsu; count>0; target++, up++, count-=DECDPUN)
705472ac97cdSTom Musta *target=*up;
705572ac97cdSTom Musta dn->digits=len; /* set the new length */
705672ac97cdSTom Musta }
705772ac97cdSTom Musta /* dn->exponent and residue are unchanged, record any inexactitude */
705872ac97cdSTom Musta if (*residue!=0) *status|=(DEC_Inexact | DEC_Rounded);
705972ac97cdSTom Musta return;
706072ac97cdSTom Musta }
706172ac97cdSTom Musta
706272ac97cdSTom Musta /* some digits must be discarded ... */
706372ac97cdSTom Musta dn->exponent+=discard; /* maintain numerical value */
706472ac97cdSTom Musta *status|=DEC_Rounded; /* accumulate Rounded status */
706572ac97cdSTom Musta if (*residue>1) *residue=1; /* previous residue now to right, so reduce */
706672ac97cdSTom Musta
706772ac97cdSTom Musta if (discard>len) { /* everything, +1, is being discarded */
706872ac97cdSTom Musta /* guard digit is 0 */
706972ac97cdSTom Musta /* residue is all the number [NB could be all 0s] */
707072ac97cdSTom Musta if (*residue<=0) { /* not already positive */
707172ac97cdSTom Musta count=len; /* avoids D2U */
707272ac97cdSTom Musta for (up=lsu; count>0; up++, count-=DECDPUN) if (*up!=0) { /* found non-0 */
707372ac97cdSTom Musta *residue=1;
707472ac97cdSTom Musta break; /* no need to check any others */
707572ac97cdSTom Musta }
707672ac97cdSTom Musta }
707772ac97cdSTom Musta if (*residue!=0) *status|=DEC_Inexact; /* record inexactitude */
707872ac97cdSTom Musta *dn->lsu=0; /* coefficient will now be 0 */
707972ac97cdSTom Musta dn->digits=1; /* .. */
708072ac97cdSTom Musta return;
708172ac97cdSTom Musta } /* total discard */
708272ac97cdSTom Musta
708372ac97cdSTom Musta /* partial discard [most common case] */
708472ac97cdSTom Musta /* here, at least the first (most significant) discarded digit exists */
708572ac97cdSTom Musta
708672ac97cdSTom Musta /* spin up the number, noting residue during the spin, until get to */
708772ac97cdSTom Musta /* the Unit with the first discarded digit. When reach it, extract */
708872ac97cdSTom Musta /* it and remember its position */
708972ac97cdSTom Musta count=0;
709072ac97cdSTom Musta for (up=lsu;; up++) {
709172ac97cdSTom Musta count+=DECDPUN;
709272ac97cdSTom Musta if (count>=discard) break; /* full ones all checked */
709372ac97cdSTom Musta if (*up!=0) *residue=1;
709472ac97cdSTom Musta } /* up */
709572ac97cdSTom Musta
709672ac97cdSTom Musta /* here up -> Unit with first discarded digit */
709772ac97cdSTom Musta cut=discard-(count-DECDPUN)-1;
709872ac97cdSTom Musta if (cut==DECDPUN-1) { /* unit-boundary case (fast) */
709972ac97cdSTom Musta Unit half=(Unit)powers[DECDPUN]>>1;
710072ac97cdSTom Musta /* set residue directly */
710172ac97cdSTom Musta if (*up>=half) {
710272ac97cdSTom Musta if (*up>half) *residue=7;
710372ac97cdSTom Musta else *residue+=5; /* add sticky bit */
710472ac97cdSTom Musta }
710572ac97cdSTom Musta else { /* <half */
710672ac97cdSTom Musta if (*up!=0) *residue=3; /* [else is 0, leave as sticky bit] */
710772ac97cdSTom Musta }
710872ac97cdSTom Musta if (set->digits<=0) { /* special for Quantize/Subnormal :-( */
710972ac97cdSTom Musta *dn->lsu=0; /* .. result is 0 */
711072ac97cdSTom Musta dn->digits=1; /* .. */
711172ac97cdSTom Musta }
711272ac97cdSTom Musta else { /* shift to least */
711372ac97cdSTom Musta count=set->digits; /* now digits to end up with */
711472ac97cdSTom Musta dn->digits=count; /* set the new length */
711572ac97cdSTom Musta up++; /* move to next */
711672ac97cdSTom Musta /* on unit boundary, so shift-down copy loop is simple */
711772ac97cdSTom Musta for (target=dn->lsu; count>0; target++, up++, count-=DECDPUN)
711872ac97cdSTom Musta *target=*up;
711972ac97cdSTom Musta }
712072ac97cdSTom Musta } /* unit-boundary case */
712172ac97cdSTom Musta
712272ac97cdSTom Musta else { /* discard digit is in low digit(s), and not top digit */
712372ac97cdSTom Musta uInt discard1; /* first discarded digit */
712472ac97cdSTom Musta uInt quot, rem; /* for divisions */
712572ac97cdSTom Musta if (cut==0) quot=*up; /* is at bottom of unit */
712672ac97cdSTom Musta else /* cut>0 */ { /* it's not at bottom of unit */
712772ac97cdSTom Musta #if DECDPUN<=4
712872ac97cdSTom Musta quot=QUOT10(*up, cut);
712972ac97cdSTom Musta rem=*up-quot*powers[cut];
713072ac97cdSTom Musta #else
713172ac97cdSTom Musta rem=*up%powers[cut];
713272ac97cdSTom Musta quot=*up/powers[cut];
713372ac97cdSTom Musta #endif
713472ac97cdSTom Musta if (rem!=0) *residue=1;
713572ac97cdSTom Musta }
713672ac97cdSTom Musta /* discard digit is now at bottom of quot */
713772ac97cdSTom Musta #if DECDPUN<=4
713872ac97cdSTom Musta temp=(quot*6554)>>16; /* fast /10 */
713972ac97cdSTom Musta /* Vowels algorithm here not a win (9 instructions) */
714072ac97cdSTom Musta discard1=quot-X10(temp);
714172ac97cdSTom Musta quot=temp;
714272ac97cdSTom Musta #else
714372ac97cdSTom Musta discard1=quot%10;
714472ac97cdSTom Musta quot=quot/10;
714572ac97cdSTom Musta #endif
714672ac97cdSTom Musta /* here, discard1 is the guard digit, and residue is everything */
714772ac97cdSTom Musta /* else [use mapping array to accumulate residue safely] */
714872ac97cdSTom Musta *residue+=resmap[discard1];
714972ac97cdSTom Musta cut++; /* update cut */
715072ac97cdSTom Musta /* here: up -> Unit of the array with bottom digit */
715172ac97cdSTom Musta /* cut is the division point for each Unit */
715272ac97cdSTom Musta /* quot holds the uncut high-order digits for the current unit */
715372ac97cdSTom Musta if (set->digits<=0) { /* special for Quantize/Subnormal :-( */
715472ac97cdSTom Musta *dn->lsu=0; /* .. result is 0 */
715572ac97cdSTom Musta dn->digits=1; /* .. */
715672ac97cdSTom Musta }
715772ac97cdSTom Musta else { /* shift to least needed */
715872ac97cdSTom Musta count=set->digits; /* now digits to end up with */
715972ac97cdSTom Musta dn->digits=count; /* set the new length */
716072ac97cdSTom Musta /* shift-copy the coefficient array to the result number */
716172ac97cdSTom Musta for (target=dn->lsu; ; target++) {
716272ac97cdSTom Musta *target=(Unit)quot;
716372ac97cdSTom Musta count-=(DECDPUN-cut);
716472ac97cdSTom Musta if (count<=0) break;
716572ac97cdSTom Musta up++;
716672ac97cdSTom Musta quot=*up;
716772ac97cdSTom Musta #if DECDPUN<=4
716872ac97cdSTom Musta quot=QUOT10(quot, cut);
716972ac97cdSTom Musta rem=*up-quot*powers[cut];
717072ac97cdSTom Musta #else
717172ac97cdSTom Musta rem=quot%powers[cut];
717272ac97cdSTom Musta quot=quot/powers[cut];
717372ac97cdSTom Musta #endif
717472ac97cdSTom Musta *target=(Unit)(*target+rem*powers[DECDPUN-cut]);
717572ac97cdSTom Musta count-=cut;
717672ac97cdSTom Musta if (count<=0) break;
717772ac97cdSTom Musta } /* shift-copy loop */
717872ac97cdSTom Musta } /* shift to least */
717972ac97cdSTom Musta } /* not unit boundary */
718072ac97cdSTom Musta
718172ac97cdSTom Musta if (*residue!=0) *status|=DEC_Inexact; /* record inexactitude */
718272ac97cdSTom Musta return;
718372ac97cdSTom Musta } /* decSetCoeff */
718472ac97cdSTom Musta
718572ac97cdSTom Musta /* ------------------------------------------------------------------ */
718672ac97cdSTom Musta /* decApplyRound -- apply pending rounding to a number */
718772ac97cdSTom Musta /* */
718872ac97cdSTom Musta /* dn is the number, with space for set->digits digits */
718972ac97cdSTom Musta /* set is the context [for size and rounding mode] */
719072ac97cdSTom Musta /* residue indicates pending rounding, being any accumulated */
719172ac97cdSTom Musta /* guard and sticky information. It may be: */
719272ac97cdSTom Musta /* 6-9: rounding digit is >5 */
719372ac97cdSTom Musta /* 5: rounding digit is exactly half-way */
719472ac97cdSTom Musta /* 1-4: rounding digit is <5 and >0 */
719572ac97cdSTom Musta /* 0: the coefficient is exact */
719672ac97cdSTom Musta /* -1: as 1, but the hidden digits are subtractive, that */
719772ac97cdSTom Musta /* is, of the opposite sign to dn. In this case the */
719872ac97cdSTom Musta /* coefficient must be non-0. This case occurs when */
719972ac97cdSTom Musta /* subtracting a small number (which can be reduced to */
720072ac97cdSTom Musta /* a sticky bit); see decAddOp. */
720172ac97cdSTom Musta /* status is the status accumulator, as usual */
720272ac97cdSTom Musta /* */
720372ac97cdSTom Musta /* This routine applies rounding while keeping the length of the */
720472ac97cdSTom Musta /* coefficient constant. The exponent and status are unchanged */
720572ac97cdSTom Musta /* except if: */
720672ac97cdSTom Musta /* */
720772ac97cdSTom Musta /* -- the coefficient was increased and is all nines (in which */
720872ac97cdSTom Musta /* case Overflow could occur, and is handled directly here so */
720972ac97cdSTom Musta /* the caller does not need to re-test for overflow) */
721072ac97cdSTom Musta /* */
721172ac97cdSTom Musta /* -- the coefficient was decreased and becomes all nines (in which */
721272ac97cdSTom Musta /* case Underflow could occur, and is also handled directly). */
721372ac97cdSTom Musta /* */
721472ac97cdSTom Musta /* All fields in dn are updated as required. */
721572ac97cdSTom Musta /* */
721672ac97cdSTom Musta /* ------------------------------------------------------------------ */
721772ac97cdSTom Musta static void decApplyRound(decNumber *dn, decContext *set, Int residue,
721872ac97cdSTom Musta uInt *status) {
721972ac97cdSTom Musta Int bump; /* 1 if coefficient needs to be incremented */
722072ac97cdSTom Musta /* -1 if coefficient needs to be decremented */
722172ac97cdSTom Musta
722272ac97cdSTom Musta if (residue==0) return; /* nothing to apply */
722372ac97cdSTom Musta
722472ac97cdSTom Musta bump=0; /* assume a smooth ride */
722572ac97cdSTom Musta
722672ac97cdSTom Musta /* now decide whether, and how, to round, depending on mode */
722772ac97cdSTom Musta switch (set->round) {
722872ac97cdSTom Musta case DEC_ROUND_05UP: { /* round zero or five up (for reround) */
722972ac97cdSTom Musta /* This is the same as DEC_ROUND_DOWN unless there is a */
723072ac97cdSTom Musta /* positive residue and the lsd of dn is 0 or 5, in which case */
723172ac97cdSTom Musta /* it is bumped; when residue is <0, the number is therefore */
723272ac97cdSTom Musta /* bumped down unless the final digit was 1 or 6 (in which */
723372ac97cdSTom Musta /* case it is bumped down and then up -- a no-op) */
723472ac97cdSTom Musta Int lsd5=*dn->lsu%5; /* get lsd and quintate */
723572ac97cdSTom Musta if (residue<0 && lsd5!=1) bump=-1;
723672ac97cdSTom Musta else if (residue>0 && lsd5==0) bump=1;
723772ac97cdSTom Musta /* [bump==1 could be applied directly; use common path for clarity] */
723872ac97cdSTom Musta break;} /* r-05 */
723972ac97cdSTom Musta
724072ac97cdSTom Musta case DEC_ROUND_DOWN: {
724172ac97cdSTom Musta /* no change, except if negative residue */
724272ac97cdSTom Musta if (residue<0) bump=-1;
724372ac97cdSTom Musta break;} /* r-d */
724472ac97cdSTom Musta
724572ac97cdSTom Musta case DEC_ROUND_HALF_DOWN: {
724672ac97cdSTom Musta if (residue>5) bump=1;
724772ac97cdSTom Musta break;} /* r-h-d */
724872ac97cdSTom Musta
724972ac97cdSTom Musta case DEC_ROUND_HALF_EVEN: {
725072ac97cdSTom Musta if (residue>5) bump=1; /* >0.5 goes up */
725172ac97cdSTom Musta else if (residue==5) { /* exactly 0.5000... */
725272ac97cdSTom Musta /* 0.5 goes up iff [new] lsd is odd */
725372ac97cdSTom Musta if (*dn->lsu & 0x01) bump=1;
725472ac97cdSTom Musta }
725572ac97cdSTom Musta break;} /* r-h-e */
725672ac97cdSTom Musta
725772ac97cdSTom Musta case DEC_ROUND_HALF_UP: {
725872ac97cdSTom Musta if (residue>=5) bump=1;
725972ac97cdSTom Musta break;} /* r-h-u */
726072ac97cdSTom Musta
726172ac97cdSTom Musta case DEC_ROUND_UP: {
726272ac97cdSTom Musta if (residue>0) bump=1;
726372ac97cdSTom Musta break;} /* r-u */
726472ac97cdSTom Musta
726572ac97cdSTom Musta case DEC_ROUND_CEILING: {
726672ac97cdSTom Musta /* same as _UP for positive numbers, and as _DOWN for negatives */
726772ac97cdSTom Musta /* [negative residue cannot occur on 0] */
726872ac97cdSTom Musta if (decNumberIsNegative(dn)) {
726972ac97cdSTom Musta if (residue<0) bump=-1;
727072ac97cdSTom Musta }
727172ac97cdSTom Musta else {
727272ac97cdSTom Musta if (residue>0) bump=1;
727372ac97cdSTom Musta }
727472ac97cdSTom Musta break;} /* r-c */
727572ac97cdSTom Musta
727672ac97cdSTom Musta case DEC_ROUND_FLOOR: {
727772ac97cdSTom Musta /* same as _UP for negative numbers, and as _DOWN for positive */
727872ac97cdSTom Musta /* [negative residue cannot occur on 0] */
727972ac97cdSTom Musta if (!decNumberIsNegative(dn)) {
728072ac97cdSTom Musta if (residue<0) bump=-1;
728172ac97cdSTom Musta }
728272ac97cdSTom Musta else {
728372ac97cdSTom Musta if (residue>0) bump=1;
728472ac97cdSTom Musta }
728572ac97cdSTom Musta break;} /* r-f */
728672ac97cdSTom Musta
728772ac97cdSTom Musta default: { /* e.g., DEC_ROUND_MAX */
728872ac97cdSTom Musta *status|=DEC_Invalid_context;
728972ac97cdSTom Musta #if DECTRACE || (DECCHECK && DECVERB)
729072ac97cdSTom Musta printf("Unknown rounding mode: %d\n", set->round);
729172ac97cdSTom Musta #endif
729272ac97cdSTom Musta break;}
729372ac97cdSTom Musta } /* switch */
729472ac97cdSTom Musta
729572ac97cdSTom Musta /* now bump the number, up or down, if need be */
729672ac97cdSTom Musta if (bump==0) return; /* no action required */
729772ac97cdSTom Musta
729872ac97cdSTom Musta /* Simply use decUnitAddSub unless bumping up and the number is */
729972ac97cdSTom Musta /* all nines. In this special case set to 100... explicitly */
730072ac97cdSTom Musta /* and adjust the exponent by one (as otherwise could overflow */
730172ac97cdSTom Musta /* the array) */
730272ac97cdSTom Musta /* Similarly handle all-nines result if bumping down. */
730372ac97cdSTom Musta if (bump>0) {
730472ac97cdSTom Musta Unit *up; /* work */
730572ac97cdSTom Musta uInt count=dn->digits; /* digits to be checked */
730672ac97cdSTom Musta for (up=dn->lsu; ; up++) {
730772ac97cdSTom Musta if (count<=DECDPUN) {
730872ac97cdSTom Musta /* this is the last Unit (the msu) */
730972ac97cdSTom Musta if (*up!=powers[count]-1) break; /* not still 9s */
731072ac97cdSTom Musta /* here if it, too, is all nines */
731172ac97cdSTom Musta *up=(Unit)powers[count-1]; /* here 999 -> 100 etc. */
731272ac97cdSTom Musta for (up=up-1; up>=dn->lsu; up--) *up=0; /* others all to 0 */
731372ac97cdSTom Musta dn->exponent++; /* and bump exponent */
731472ac97cdSTom Musta /* [which, very rarely, could cause Overflow...] */
731572ac97cdSTom Musta if ((dn->exponent+dn->digits)>set->emax+1) {
731672ac97cdSTom Musta decSetOverflow(dn, set, status);
731772ac97cdSTom Musta }
731872ac97cdSTom Musta return; /* done */
731972ac97cdSTom Musta }
732072ac97cdSTom Musta /* a full unit to check, with more to come */
732172ac97cdSTom Musta if (*up!=DECDPUNMAX) break; /* not still 9s */
732272ac97cdSTom Musta count-=DECDPUN;
732372ac97cdSTom Musta } /* up */
732472ac97cdSTom Musta } /* bump>0 */
732572ac97cdSTom Musta else { /* -1 */
732672ac97cdSTom Musta /* here checking for a pre-bump of 1000... (leading 1, all */
732772ac97cdSTom Musta /* other digits zero) */
732872ac97cdSTom Musta Unit *up, *sup; /* work */
732972ac97cdSTom Musta uInt count=dn->digits; /* digits to be checked */
733072ac97cdSTom Musta for (up=dn->lsu; ; up++) {
733172ac97cdSTom Musta if (count<=DECDPUN) {
733272ac97cdSTom Musta /* this is the last Unit (the msu) */
733372ac97cdSTom Musta if (*up!=powers[count-1]) break; /* not 100.. */
733472ac97cdSTom Musta /* here if have the 1000... case */
733572ac97cdSTom Musta sup=up; /* save msu pointer */
733672ac97cdSTom Musta *up=(Unit)powers[count]-1; /* here 100 in msu -> 999 */
733772ac97cdSTom Musta /* others all to all-nines, too */
733872ac97cdSTom Musta for (up=up-1; up>=dn->lsu; up--) *up=(Unit)powers[DECDPUN]-1;
733972ac97cdSTom Musta dn->exponent--; /* and bump exponent */
734072ac97cdSTom Musta
734172ac97cdSTom Musta /* iff the number was at the subnormal boundary (exponent=etiny) */
734272ac97cdSTom Musta /* then the exponent is now out of range, so it will in fact get */
734372ac97cdSTom Musta /* clamped to etiny and the final 9 dropped. */
734472ac97cdSTom Musta /* printf(">> emin=%d exp=%d sdig=%d\n", set->emin, */
734572ac97cdSTom Musta /* dn->exponent, set->digits); */
734672ac97cdSTom Musta if (dn->exponent+1==set->emin-set->digits+1) {
734772ac97cdSTom Musta if (count==1 && dn->digits==1) *sup=0; /* here 9 -> 0[.9] */
734872ac97cdSTom Musta else {
734972ac97cdSTom Musta *sup=(Unit)powers[count-1]-1; /* here 999.. in msu -> 99.. */
735072ac97cdSTom Musta dn->digits--;
735172ac97cdSTom Musta }
735272ac97cdSTom Musta dn->exponent++;
735372ac97cdSTom Musta *status|=DEC_Underflow | DEC_Subnormal | DEC_Inexact | DEC_Rounded;
735472ac97cdSTom Musta }
735572ac97cdSTom Musta return; /* done */
735672ac97cdSTom Musta }
735772ac97cdSTom Musta
735872ac97cdSTom Musta /* a full unit to check, with more to come */
735972ac97cdSTom Musta if (*up!=0) break; /* not still 0s */
736072ac97cdSTom Musta count-=DECDPUN;
736172ac97cdSTom Musta } /* up */
736272ac97cdSTom Musta
736372ac97cdSTom Musta } /* bump<0 */
736472ac97cdSTom Musta
736572ac97cdSTom Musta /* Actual bump needed. Do it. */
736672ac97cdSTom Musta decUnitAddSub(dn->lsu, D2U(dn->digits), uarrone, 1, 0, dn->lsu, bump);
736772ac97cdSTom Musta } /* decApplyRound */
736872ac97cdSTom Musta
736972ac97cdSTom Musta #if DECSUBSET
737072ac97cdSTom Musta /* ------------------------------------------------------------------ */
737172ac97cdSTom Musta /* decFinish -- finish processing a number */
737272ac97cdSTom Musta /* */
737372ac97cdSTom Musta /* dn is the number */
737472ac97cdSTom Musta /* set is the context */
737572ac97cdSTom Musta /* residue is the rounding accumulator (as in decApplyRound) */
737672ac97cdSTom Musta /* status is the accumulator */
737772ac97cdSTom Musta /* */
737872ac97cdSTom Musta /* This finishes off the current number by: */
737972ac97cdSTom Musta /* 1. If not extended: */
738072ac97cdSTom Musta /* a. Converting a zero result to clean '0' */
738172ac97cdSTom Musta /* b. Reducing positive exponents to 0, if would fit in digits */
738272ac97cdSTom Musta /* 2. Checking for overflow and subnormals (always) */
738372ac97cdSTom Musta /* Note this is just Finalize when no subset arithmetic. */
738472ac97cdSTom Musta /* All fields are updated as required. */
738572ac97cdSTom Musta /* ------------------------------------------------------------------ */
738672ac97cdSTom Musta static void decFinish(decNumber *dn, decContext *set, Int *residue,
738772ac97cdSTom Musta uInt *status) {
738872ac97cdSTom Musta if (!set->extended) {
738972ac97cdSTom Musta if ISZERO(dn) { /* value is zero */
739072ac97cdSTom Musta dn->exponent=0; /* clean exponent .. */
739172ac97cdSTom Musta dn->bits=0; /* .. and sign */
739272ac97cdSTom Musta return; /* no error possible */
739372ac97cdSTom Musta }
739472ac97cdSTom Musta if (dn->exponent>=0) { /* non-negative exponent */
739572ac97cdSTom Musta /* >0; reduce to integer if possible */
739672ac97cdSTom Musta if (set->digits >= (dn->exponent+dn->digits)) {
739772ac97cdSTom Musta dn->digits=decShiftToMost(dn->lsu, dn->digits, dn->exponent);
739872ac97cdSTom Musta dn->exponent=0;
739972ac97cdSTom Musta }
740072ac97cdSTom Musta }
740172ac97cdSTom Musta } /* !extended */
740272ac97cdSTom Musta
740372ac97cdSTom Musta decFinalize(dn, set, residue, status);
740472ac97cdSTom Musta } /* decFinish */
740572ac97cdSTom Musta #endif
740672ac97cdSTom Musta
740772ac97cdSTom Musta /* ------------------------------------------------------------------ */
740872ac97cdSTom Musta /* decFinalize -- final check, clamp, and round of a number */
740972ac97cdSTom Musta /* */
741072ac97cdSTom Musta /* dn is the number */
741172ac97cdSTom Musta /* set is the context */
741272ac97cdSTom Musta /* residue is the rounding accumulator (as in decApplyRound) */
741372ac97cdSTom Musta /* status is the status accumulator */
741472ac97cdSTom Musta /* */
741572ac97cdSTom Musta /* This finishes off the current number by checking for subnormal */
741672ac97cdSTom Musta /* results, applying any pending rounding, checking for overflow, */
741772ac97cdSTom Musta /* and applying any clamping. */
741872ac97cdSTom Musta /* Underflow and overflow conditions are raised as appropriate. */
741972ac97cdSTom Musta /* All fields are updated as required. */
742072ac97cdSTom Musta /* ------------------------------------------------------------------ */
742172ac97cdSTom Musta static void decFinalize(decNumber *dn, decContext *set, Int *residue,
742272ac97cdSTom Musta uInt *status) {
742372ac97cdSTom Musta Int shift; /* shift needed if clamping */
742472ac97cdSTom Musta Int tinyexp=set->emin-dn->digits+1; /* precalculate subnormal boundary */
742572ac97cdSTom Musta
742672ac97cdSTom Musta /* Must be careful, here, when checking the exponent as the */
742772ac97cdSTom Musta /* adjusted exponent could overflow 31 bits [because it may already */
742872ac97cdSTom Musta /* be up to twice the expected]. */
742972ac97cdSTom Musta
743072ac97cdSTom Musta /* First test for subnormal. This must be done before any final */
743172ac97cdSTom Musta /* round as the result could be rounded to Nmin or 0. */
743272ac97cdSTom Musta if (dn->exponent<=tinyexp) { /* prefilter */
743372ac97cdSTom Musta Int comp;
743472ac97cdSTom Musta decNumber nmin;
743572ac97cdSTom Musta /* A very nasty case here is dn == Nmin and residue<0 */
743672ac97cdSTom Musta if (dn->exponent<tinyexp) {
743772ac97cdSTom Musta /* Go handle subnormals; this will apply round if needed. */
743872ac97cdSTom Musta decSetSubnormal(dn, set, residue, status);
743972ac97cdSTom Musta return;
744072ac97cdSTom Musta }
744172ac97cdSTom Musta /* Equals case: only subnormal if dn=Nmin and negative residue */
744272ac97cdSTom Musta decNumberZero(&nmin);
744372ac97cdSTom Musta nmin.lsu[0]=1;
744472ac97cdSTom Musta nmin.exponent=set->emin;
744572ac97cdSTom Musta comp=decCompare(dn, &nmin, 1); /* (signless compare) */
744672ac97cdSTom Musta if (comp==BADINT) { /* oops */
744772ac97cdSTom Musta *status|=DEC_Insufficient_storage; /* abandon... */
744872ac97cdSTom Musta return;
744972ac97cdSTom Musta }
745072ac97cdSTom Musta if (*residue<0 && comp==0) { /* neg residue and dn==Nmin */
745172ac97cdSTom Musta decApplyRound(dn, set, *residue, status); /* might force down */
745272ac97cdSTom Musta decSetSubnormal(dn, set, residue, status);
745372ac97cdSTom Musta return;
745472ac97cdSTom Musta }
745572ac97cdSTom Musta }
745672ac97cdSTom Musta
745772ac97cdSTom Musta /* now apply any pending round (this could raise overflow). */
745872ac97cdSTom Musta if (*residue!=0) decApplyRound(dn, set, *residue, status);
745972ac97cdSTom Musta
746072ac97cdSTom Musta /* Check for overflow [redundant in the 'rare' case] or clamp */
746172ac97cdSTom Musta if (dn->exponent<=set->emax-set->digits+1) return; /* neither needed */
746272ac97cdSTom Musta
746372ac97cdSTom Musta
746472ac97cdSTom Musta /* here when might have an overflow or clamp to do */
746572ac97cdSTom Musta if (dn->exponent>set->emax-dn->digits+1) { /* too big */
746672ac97cdSTom Musta decSetOverflow(dn, set, status);
746772ac97cdSTom Musta return;
746872ac97cdSTom Musta }
746972ac97cdSTom Musta /* here when the result is normal but in clamp range */
747072ac97cdSTom Musta if (!set->clamp) return;
747172ac97cdSTom Musta
747272ac97cdSTom Musta /* here when need to apply the IEEE exponent clamp (fold-down) */
747372ac97cdSTom Musta shift=dn->exponent-(set->emax-set->digits+1);
747472ac97cdSTom Musta
747572ac97cdSTom Musta /* shift coefficient (if non-zero) */
747672ac97cdSTom Musta if (!ISZERO(dn)) {
747772ac97cdSTom Musta dn->digits=decShiftToMost(dn->lsu, dn->digits, shift);
747872ac97cdSTom Musta }
747972ac97cdSTom Musta dn->exponent-=shift; /* adjust the exponent to match */
748072ac97cdSTom Musta *status|=DEC_Clamped; /* and record the dirty deed */
748172ac97cdSTom Musta return;
748272ac97cdSTom Musta } /* decFinalize */
748372ac97cdSTom Musta
748472ac97cdSTom Musta /* ------------------------------------------------------------------ */
748572ac97cdSTom Musta /* decSetOverflow -- set number to proper overflow value */
748672ac97cdSTom Musta /* */
748772ac97cdSTom Musta /* dn is the number (used for sign [only] and result) */
748872ac97cdSTom Musta /* set is the context [used for the rounding mode, etc.] */
748972ac97cdSTom Musta /* status contains the current status to be updated */
749072ac97cdSTom Musta /* */
749172ac97cdSTom Musta /* This sets the sign of a number and sets its value to either */
749272ac97cdSTom Musta /* Infinity or the maximum finite value, depending on the sign of */
749372ac97cdSTom Musta /* dn and the rounding mode, following IEEE 854 rules. */
749472ac97cdSTom Musta /* ------------------------------------------------------------------ */
749572ac97cdSTom Musta static void decSetOverflow(decNumber *dn, decContext *set, uInt *status) {
749672ac97cdSTom Musta Flag needmax=0; /* result is maximum finite value */
749772ac97cdSTom Musta uByte sign=dn->bits&DECNEG; /* clean and save sign bit */
749872ac97cdSTom Musta
749972ac97cdSTom Musta if (ISZERO(dn)) { /* zero does not overflow magnitude */
750072ac97cdSTom Musta Int emax=set->emax; /* limit value */
750172ac97cdSTom Musta if (set->clamp) emax-=set->digits-1; /* lower if clamping */
750272ac97cdSTom Musta if (dn->exponent>emax) { /* clamp required */
750372ac97cdSTom Musta dn->exponent=emax;
750472ac97cdSTom Musta *status|=DEC_Clamped;
750572ac97cdSTom Musta }
750672ac97cdSTom Musta return;
750772ac97cdSTom Musta }
750872ac97cdSTom Musta
750972ac97cdSTom Musta decNumberZero(dn);
751072ac97cdSTom Musta switch (set->round) {
751172ac97cdSTom Musta case DEC_ROUND_DOWN: {
751272ac97cdSTom Musta needmax=1; /* never Infinity */
751372ac97cdSTom Musta break;} /* r-d */
751472ac97cdSTom Musta case DEC_ROUND_05UP: {
751572ac97cdSTom Musta needmax=1; /* never Infinity */
751672ac97cdSTom Musta break;} /* r-05 */
751772ac97cdSTom Musta case DEC_ROUND_CEILING: {
751872ac97cdSTom Musta if (sign) needmax=1; /* Infinity if non-negative */
751972ac97cdSTom Musta break;} /* r-c */
752072ac97cdSTom Musta case DEC_ROUND_FLOOR: {
752172ac97cdSTom Musta if (!sign) needmax=1; /* Infinity if negative */
752272ac97cdSTom Musta break;} /* r-f */
752372ac97cdSTom Musta default: break; /* Infinity in all other cases */
752472ac97cdSTom Musta }
752572ac97cdSTom Musta if (needmax) {
752672ac97cdSTom Musta decSetMaxValue(dn, set);
752772ac97cdSTom Musta dn->bits=sign; /* set sign */
752872ac97cdSTom Musta }
752972ac97cdSTom Musta else dn->bits=sign|DECINF; /* Value is +/-Infinity */
753072ac97cdSTom Musta *status|=DEC_Overflow | DEC_Inexact | DEC_Rounded;
753172ac97cdSTom Musta } /* decSetOverflow */
753272ac97cdSTom Musta
753372ac97cdSTom Musta /* ------------------------------------------------------------------ */
753472ac97cdSTom Musta /* decSetMaxValue -- set number to +Nmax (maximum normal value) */
753572ac97cdSTom Musta /* */
753672ac97cdSTom Musta /* dn is the number to set */
753772ac97cdSTom Musta /* set is the context [used for digits and emax] */
753872ac97cdSTom Musta /* */
753972ac97cdSTom Musta /* This sets the number to the maximum positive value. */
754072ac97cdSTom Musta /* ------------------------------------------------------------------ */
754172ac97cdSTom Musta static void decSetMaxValue(decNumber *dn, decContext *set) {
754272ac97cdSTom Musta Unit *up; /* work */
754372ac97cdSTom Musta Int count=set->digits; /* nines to add */
754472ac97cdSTom Musta dn->digits=count;
754572ac97cdSTom Musta /* fill in all nines to set maximum value */
754672ac97cdSTom Musta for (up=dn->lsu; ; up++) {
754772ac97cdSTom Musta if (count>DECDPUN) *up=DECDPUNMAX; /* unit full o'nines */
754872ac97cdSTom Musta else { /* this is the msu */
754972ac97cdSTom Musta *up=(Unit)(powers[count]-1);
755072ac97cdSTom Musta break;
755172ac97cdSTom Musta }
755272ac97cdSTom Musta count-=DECDPUN; /* filled those digits */
755372ac97cdSTom Musta } /* up */
755472ac97cdSTom Musta dn->bits=0; /* + sign */
755572ac97cdSTom Musta dn->exponent=set->emax-set->digits+1;
755672ac97cdSTom Musta } /* decSetMaxValue */
755772ac97cdSTom Musta
755872ac97cdSTom Musta /* ------------------------------------------------------------------ */
755972ac97cdSTom Musta /* decSetSubnormal -- process value whose exponent is <Emin */
756072ac97cdSTom Musta /* */
756172ac97cdSTom Musta /* dn is the number (used as input as well as output; it may have */
756272ac97cdSTom Musta /* an allowed subnormal value, which may need to be rounded) */
756372ac97cdSTom Musta /* set is the context [used for the rounding mode] */
756472ac97cdSTom Musta /* residue is any pending residue */
756572ac97cdSTom Musta /* status contains the current status to be updated */
756672ac97cdSTom Musta /* */
756772ac97cdSTom Musta /* If subset mode, set result to zero and set Underflow flags. */
756872ac97cdSTom Musta /* */
756972ac97cdSTom Musta /* Value may be zero with a low exponent; this does not set Subnormal */
757072ac97cdSTom Musta /* but the exponent will be clamped to Etiny. */
757172ac97cdSTom Musta /* */
757272ac97cdSTom Musta /* Otherwise ensure exponent is not out of range, and round as */
757372ac97cdSTom Musta /* necessary. Underflow is set if the result is Inexact. */
757472ac97cdSTom Musta /* ------------------------------------------------------------------ */
757572ac97cdSTom Musta static void decSetSubnormal(decNumber *dn, decContext *set, Int *residue,
757672ac97cdSTom Musta uInt *status) {
757772ac97cdSTom Musta decContext workset; /* work */
757872ac97cdSTom Musta Int etiny, adjust; /* .. */
757972ac97cdSTom Musta
758072ac97cdSTom Musta #if DECSUBSET
758172ac97cdSTom Musta /* simple set to zero and 'hard underflow' for subset */
758272ac97cdSTom Musta if (!set->extended) {
758372ac97cdSTom Musta decNumberZero(dn);
758472ac97cdSTom Musta /* always full overflow */
758572ac97cdSTom Musta *status|=DEC_Underflow | DEC_Subnormal | DEC_Inexact | DEC_Rounded;
758672ac97cdSTom Musta return;
758772ac97cdSTom Musta }
758872ac97cdSTom Musta #endif
758972ac97cdSTom Musta
759072ac97cdSTom Musta /* Full arithmetic -- allow subnormals, rounded to minimum exponent */
759172ac97cdSTom Musta /* (Etiny) if needed */
759272ac97cdSTom Musta etiny=set->emin-(set->digits-1); /* smallest allowed exponent */
759372ac97cdSTom Musta
759472ac97cdSTom Musta if ISZERO(dn) { /* value is zero */
759572ac97cdSTom Musta /* residue can never be non-zero here */
759672ac97cdSTom Musta #if DECCHECK
759772ac97cdSTom Musta if (*residue!=0) {
759872ac97cdSTom Musta printf("++ Subnormal 0 residue %ld\n", (LI)*residue);
759972ac97cdSTom Musta *status|=DEC_Invalid_operation;
760072ac97cdSTom Musta }
760172ac97cdSTom Musta #endif
760272ac97cdSTom Musta if (dn->exponent<etiny) { /* clamp required */
760372ac97cdSTom Musta dn->exponent=etiny;
760472ac97cdSTom Musta *status|=DEC_Clamped;
760572ac97cdSTom Musta }
760672ac97cdSTom Musta return;
760772ac97cdSTom Musta }
760872ac97cdSTom Musta
760972ac97cdSTom Musta *status|=DEC_Subnormal; /* have a non-zero subnormal */
761072ac97cdSTom Musta adjust=etiny-dn->exponent; /* calculate digits to remove */
761172ac97cdSTom Musta if (adjust<=0) { /* not out of range; unrounded */
761272ac97cdSTom Musta /* residue can never be non-zero here, except in the Nmin-residue */
761372ac97cdSTom Musta /* case (which is a subnormal result), so can take fast-path here */
761472ac97cdSTom Musta /* it may already be inexact (from setting the coefficient) */
761572ac97cdSTom Musta if (*status&DEC_Inexact) *status|=DEC_Underflow;
761672ac97cdSTom Musta return;
761772ac97cdSTom Musta }
761872ac97cdSTom Musta
761972ac97cdSTom Musta /* adjust>0, so need to rescale the result so exponent becomes Etiny */
762072ac97cdSTom Musta /* [this code is similar to that in rescale] */
762172ac97cdSTom Musta workset=*set; /* clone rounding, etc. */
762272ac97cdSTom Musta workset.digits=dn->digits-adjust; /* set requested length */
762372ac97cdSTom Musta workset.emin-=adjust; /* and adjust emin to match */
762472ac97cdSTom Musta /* [note that the latter can be <1, here, similar to Rescale case] */
762572ac97cdSTom Musta decSetCoeff(dn, &workset, dn->lsu, dn->digits, residue, status);
762672ac97cdSTom Musta decApplyRound(dn, &workset, *residue, status);
762772ac97cdSTom Musta
762872ac97cdSTom Musta /* Use 754R/854 default rule: Underflow is set iff Inexact */
762972ac97cdSTom Musta /* [independent of whether trapped] */
763072ac97cdSTom Musta if (*status&DEC_Inexact) *status|=DEC_Underflow;
763172ac97cdSTom Musta
763272ac97cdSTom Musta /* if rounded up a 999s case, exponent will be off by one; adjust */
763372ac97cdSTom Musta /* back if so [it will fit, because it was shortened earlier] */
763472ac97cdSTom Musta if (dn->exponent>etiny) {
763572ac97cdSTom Musta dn->digits=decShiftToMost(dn->lsu, dn->digits, 1);
763672ac97cdSTom Musta dn->exponent--; /* (re)adjust the exponent. */
763772ac97cdSTom Musta }
763872ac97cdSTom Musta
763972ac97cdSTom Musta /* if rounded to zero, it is by definition clamped... */
764072ac97cdSTom Musta if (ISZERO(dn)) *status|=DEC_Clamped;
764172ac97cdSTom Musta } /* decSetSubnormal */
764272ac97cdSTom Musta
764372ac97cdSTom Musta /* ------------------------------------------------------------------ */
764472ac97cdSTom Musta /* decCheckMath - check entry conditions for a math function */
764572ac97cdSTom Musta /* */
764672ac97cdSTom Musta /* This checks the context and the operand */
764772ac97cdSTom Musta /* */
764872ac97cdSTom Musta /* rhs is the operand to check */
764972ac97cdSTom Musta /* set is the context to check */
765072ac97cdSTom Musta /* status is unchanged if both are good */
765172ac97cdSTom Musta /* */
765272ac97cdSTom Musta /* returns non-zero if status is changed, 0 otherwise */
765372ac97cdSTom Musta /* */
765472ac97cdSTom Musta /* Restrictions enforced: */
765572ac97cdSTom Musta /* */
765672ac97cdSTom Musta /* digits, emax, and -emin in the context must be less than */
765772ac97cdSTom Musta /* DEC_MAX_MATH (999999), and A must be within these bounds if */
765872ac97cdSTom Musta /* non-zero. Invalid_operation is set in the status if a */
765972ac97cdSTom Musta /* restriction is violated. */
766072ac97cdSTom Musta /* ------------------------------------------------------------------ */
766172ac97cdSTom Musta static uInt decCheckMath(const decNumber *rhs, decContext *set,
766272ac97cdSTom Musta uInt *status) {
766372ac97cdSTom Musta uInt save=*status; /* record */
766472ac97cdSTom Musta if (set->digits>DEC_MAX_MATH
766572ac97cdSTom Musta || set->emax>DEC_MAX_MATH
766672ac97cdSTom Musta || -set->emin>DEC_MAX_MATH) *status|=DEC_Invalid_context;
766772ac97cdSTom Musta else if ((rhs->digits>DEC_MAX_MATH
766872ac97cdSTom Musta || rhs->exponent+rhs->digits>DEC_MAX_MATH+1
766972ac97cdSTom Musta || rhs->exponent+rhs->digits<2*(1-DEC_MAX_MATH))
767072ac97cdSTom Musta && !ISZERO(rhs)) *status|=DEC_Invalid_operation;
767172ac97cdSTom Musta return (*status!=save);
767272ac97cdSTom Musta } /* decCheckMath */
767372ac97cdSTom Musta
767472ac97cdSTom Musta /* ------------------------------------------------------------------ */
767572ac97cdSTom Musta /* decGetInt -- get integer from a number */
767672ac97cdSTom Musta /* */
767772ac97cdSTom Musta /* dn is the number [which will not be altered] */
767872ac97cdSTom Musta /* */
767972ac97cdSTom Musta /* returns one of: */
768072ac97cdSTom Musta /* BADINT if there is a non-zero fraction */
768172ac97cdSTom Musta /* the converted integer */
768272ac97cdSTom Musta /* BIGEVEN if the integer is even and magnitude > 2*10**9 */
768372ac97cdSTom Musta /* BIGODD if the integer is odd and magnitude > 2*10**9 */
768472ac97cdSTom Musta /* */
768572ac97cdSTom Musta /* This checks and gets a whole number from the input decNumber. */
768672ac97cdSTom Musta /* The sign can be determined from dn by the caller when BIGEVEN or */
768772ac97cdSTom Musta /* BIGODD is returned. */
768872ac97cdSTom Musta /* ------------------------------------------------------------------ */
768972ac97cdSTom Musta static Int decGetInt(const decNumber *dn) {
769072ac97cdSTom Musta Int theInt; /* result accumulator */
769172ac97cdSTom Musta const Unit *up; /* work */
769272ac97cdSTom Musta Int got; /* digits (real or not) processed */
769372ac97cdSTom Musta Int ilength=dn->digits+dn->exponent; /* integral length */
769472ac97cdSTom Musta Flag neg=decNumberIsNegative(dn); /* 1 if -ve */
769572ac97cdSTom Musta
769672ac97cdSTom Musta /* The number must be an integer that fits in 10 digits */
769772ac97cdSTom Musta /* Assert, here, that 10 is enough for any rescale Etiny */
769872ac97cdSTom Musta #if DEC_MAX_EMAX > 999999999
769972ac97cdSTom Musta #error GetInt may need updating [for Emax]
770072ac97cdSTom Musta #endif
770172ac97cdSTom Musta #if DEC_MIN_EMIN < -999999999
770272ac97cdSTom Musta #error GetInt may need updating [for Emin]
770372ac97cdSTom Musta #endif
770472ac97cdSTom Musta if (ISZERO(dn)) return 0; /* zeros are OK, with any exponent */
770572ac97cdSTom Musta
770672ac97cdSTom Musta up=dn->lsu; /* ready for lsu */
770772ac97cdSTom Musta theInt=0; /* ready to accumulate */
770872ac97cdSTom Musta if (dn->exponent>=0) { /* relatively easy */
770972ac97cdSTom Musta /* no fractional part [usual]; allow for positive exponent */
771072ac97cdSTom Musta got=dn->exponent;
771172ac97cdSTom Musta }
771272ac97cdSTom Musta else { /* -ve exponent; some fractional part to check and discard */
771372ac97cdSTom Musta Int count=-dn->exponent; /* digits to discard */
771472ac97cdSTom Musta /* spin up whole units until reach the Unit with the unit digit */
771572ac97cdSTom Musta for (; count>=DECDPUN; up++) {
771672ac97cdSTom Musta if (*up!=0) return BADINT; /* non-zero Unit to discard */
771772ac97cdSTom Musta count-=DECDPUN;
771872ac97cdSTom Musta }
771972ac97cdSTom Musta if (count==0) got=0; /* [a multiple of DECDPUN] */
772072ac97cdSTom Musta else { /* [not multiple of DECDPUN] */
772172ac97cdSTom Musta Int rem; /* work */
772272ac97cdSTom Musta /* slice off fraction digits and check for non-zero */
772372ac97cdSTom Musta #if DECDPUN<=4
772472ac97cdSTom Musta theInt=QUOT10(*up, count);
772572ac97cdSTom Musta rem=*up-theInt*powers[count];
772672ac97cdSTom Musta #else
772772ac97cdSTom Musta rem=*up%powers[count]; /* slice off discards */
772872ac97cdSTom Musta theInt=*up/powers[count];
772972ac97cdSTom Musta #endif
773072ac97cdSTom Musta if (rem!=0) return BADINT; /* non-zero fraction */
773172ac97cdSTom Musta /* it looks good */
773272ac97cdSTom Musta got=DECDPUN-count; /* number of digits so far */
773372ac97cdSTom Musta up++; /* ready for next */
773472ac97cdSTom Musta }
773572ac97cdSTom Musta }
773672ac97cdSTom Musta /* now it's known there's no fractional part */
773772ac97cdSTom Musta
773872ac97cdSTom Musta /* tricky code now, to accumulate up to 9.3 digits */
773972ac97cdSTom Musta if (got==0) {theInt=*up; got+=DECDPUN; up++;} /* ensure lsu is there */
774072ac97cdSTom Musta
774172ac97cdSTom Musta if (ilength<11) {
774272ac97cdSTom Musta Int save=theInt;
774372ac97cdSTom Musta /* collect any remaining unit(s) */
774472ac97cdSTom Musta for (; got<ilength; up++) {
774572ac97cdSTom Musta theInt+=*up*powers[got];
774672ac97cdSTom Musta got+=DECDPUN;
774772ac97cdSTom Musta }
774872ac97cdSTom Musta if (ilength==10) { /* need to check for wrap */
774972ac97cdSTom Musta if (theInt/(Int)powers[got-DECDPUN]!=(Int)*(up-1)) ilength=11;
775072ac97cdSTom Musta /* [that test also disallows the BADINT result case] */
775172ac97cdSTom Musta else if (neg && theInt>1999999997) ilength=11;
775272ac97cdSTom Musta else if (!neg && theInt>999999999) ilength=11;
775372ac97cdSTom Musta if (ilength==11) theInt=save; /* restore correct low bit */
775472ac97cdSTom Musta }
775572ac97cdSTom Musta }
775672ac97cdSTom Musta
775772ac97cdSTom Musta if (ilength>10) { /* too big */
775872ac97cdSTom Musta if (theInt&1) return BIGODD; /* bottom bit 1 */
775972ac97cdSTom Musta return BIGEVEN; /* bottom bit 0 */
776072ac97cdSTom Musta }
776172ac97cdSTom Musta
776272ac97cdSTom Musta if (neg) theInt=-theInt; /* apply sign */
776372ac97cdSTom Musta return theInt;
776472ac97cdSTom Musta } /* decGetInt */
776572ac97cdSTom Musta
776672ac97cdSTom Musta /* ------------------------------------------------------------------ */
776772ac97cdSTom Musta /* decDecap -- decapitate the coefficient of a number */
776872ac97cdSTom Musta /* */
776972ac97cdSTom Musta /* dn is the number to be decapitated */
777072ac97cdSTom Musta /* drop is the number of digits to be removed from the left of dn; */
777172ac97cdSTom Musta /* this must be <= dn->digits (if equal, the coefficient is */
777272ac97cdSTom Musta /* set to 0) */
777372ac97cdSTom Musta /* */
777472ac97cdSTom Musta /* Returns dn; dn->digits will be <= the initial digits less drop */
777572ac97cdSTom Musta /* (after removing drop digits there may be leading zero digits */
777672ac97cdSTom Musta /* which will also be removed). Only dn->lsu and dn->digits change. */
777772ac97cdSTom Musta /* ------------------------------------------------------------------ */
777872ac97cdSTom Musta static decNumber *decDecap(decNumber *dn, Int drop) {
777972ac97cdSTom Musta Unit *msu; /* -> target cut point */
778072ac97cdSTom Musta Int cut; /* work */
778172ac97cdSTom Musta if (drop>=dn->digits) { /* losing the whole thing */
778272ac97cdSTom Musta #if DECCHECK
778372ac97cdSTom Musta if (drop>dn->digits)
778472ac97cdSTom Musta printf("decDecap called with drop>digits [%ld>%ld]\n",
778572ac97cdSTom Musta (LI)drop, (LI)dn->digits);
778672ac97cdSTom Musta #endif
778772ac97cdSTom Musta dn->lsu[0]=0;
778872ac97cdSTom Musta dn->digits=1;
778972ac97cdSTom Musta return dn;
779072ac97cdSTom Musta }
779172ac97cdSTom Musta msu=dn->lsu+D2U(dn->digits-drop)-1; /* -> likely msu */
779272ac97cdSTom Musta cut=MSUDIGITS(dn->digits-drop); /* digits to be in use in msu */
779372ac97cdSTom Musta if (cut!=DECDPUN) *msu%=powers[cut]; /* clear left digits */
779472ac97cdSTom Musta /* that may have left leading zero digits, so do a proper count... */
779572ac97cdSTom Musta dn->digits=decGetDigits(dn->lsu, msu-dn->lsu+1);
779672ac97cdSTom Musta return dn;
779772ac97cdSTom Musta } /* decDecap */
779872ac97cdSTom Musta
779972ac97cdSTom Musta /* ------------------------------------------------------------------ */
780072ac97cdSTom Musta /* decBiStr -- compare string with pairwise options */
780172ac97cdSTom Musta /* */
780272ac97cdSTom Musta /* targ is the string to compare */
780372ac97cdSTom Musta /* str1 is one of the strings to compare against (length may be 0) */
780472ac97cdSTom Musta /* str2 is the other; it must be the same length as str1 */
780572ac97cdSTom Musta /* */
780672ac97cdSTom Musta /* returns 1 if strings compare equal, (that is, it is the same */
780772ac97cdSTom Musta /* length as str1 and str2, and each character of targ is in either */
780872ac97cdSTom Musta /* str1 or str2 in the corresponding position), or 0 otherwise */
780972ac97cdSTom Musta /* */
781072ac97cdSTom Musta /* This is used for generic caseless compare, including the awkward */
781172ac97cdSTom Musta /* case of the Turkish dotted and dotless Is. Use as (for example): */
781272ac97cdSTom Musta /* if (decBiStr(test, "mike", "MIKE")) ... */
781372ac97cdSTom Musta /* ------------------------------------------------------------------ */
781472ac97cdSTom Musta static Flag decBiStr(const char *targ, const char *str1, const char *str2) {
781572ac97cdSTom Musta for (;;targ++, str1++, str2++) {
781672ac97cdSTom Musta if (*targ!=*str1 && *targ!=*str2) return 0;
781772ac97cdSTom Musta /* *targ has a match in one (or both, if terminator) */
781872ac97cdSTom Musta if (*targ=='\0') break;
781972ac97cdSTom Musta } /* forever */
782072ac97cdSTom Musta return 1;
782172ac97cdSTom Musta } /* decBiStr */
782272ac97cdSTom Musta
782372ac97cdSTom Musta /* ------------------------------------------------------------------ */
782472ac97cdSTom Musta /* decNaNs -- handle NaN operand or operands */
782572ac97cdSTom Musta /* */
782672ac97cdSTom Musta /* res is the result number */
782772ac97cdSTom Musta /* lhs is the first operand */
782872ac97cdSTom Musta /* rhs is the second operand, or NULL if none */
782972ac97cdSTom Musta /* context is used to limit payload length */
783072ac97cdSTom Musta /* status contains the current status */
783172ac97cdSTom Musta /* returns res in case convenient */
783272ac97cdSTom Musta /* */
783372ac97cdSTom Musta /* Called when one or both operands is a NaN, and propagates the */
783472ac97cdSTom Musta /* appropriate result to res. When an sNaN is found, it is changed */
783572ac97cdSTom Musta /* to a qNaN and Invalid operation is set. */
783672ac97cdSTom Musta /* ------------------------------------------------------------------ */
783772ac97cdSTom Musta static decNumber * decNaNs(decNumber *res, const decNumber *lhs,
783872ac97cdSTom Musta const decNumber *rhs, decContext *set,
783972ac97cdSTom Musta uInt *status) {
784072ac97cdSTom Musta /* This decision tree ends up with LHS being the source pointer, */
784172ac97cdSTom Musta /* and status updated if need be */
784272ac97cdSTom Musta if (lhs->bits & DECSNAN)
784372ac97cdSTom Musta *status|=DEC_Invalid_operation | DEC_sNaN;
784472ac97cdSTom Musta else if (rhs==NULL);
784572ac97cdSTom Musta else if (rhs->bits & DECSNAN) {
784672ac97cdSTom Musta lhs=rhs;
784772ac97cdSTom Musta *status|=DEC_Invalid_operation | DEC_sNaN;
784872ac97cdSTom Musta }
784972ac97cdSTom Musta else if (lhs->bits & DECNAN);
785072ac97cdSTom Musta else lhs=rhs;
785172ac97cdSTom Musta
785272ac97cdSTom Musta /* propagate the payload */
785372ac97cdSTom Musta if (lhs->digits<=set->digits) decNumberCopy(res, lhs); /* easy */
785472ac97cdSTom Musta else { /* too long */
785572ac97cdSTom Musta const Unit *ul;
785672ac97cdSTom Musta Unit *ur, *uresp1;
785772ac97cdSTom Musta /* copy safe number of units, then decapitate */
785872ac97cdSTom Musta res->bits=lhs->bits; /* need sign etc. */
785972ac97cdSTom Musta uresp1=res->lsu+D2U(set->digits);
786072ac97cdSTom Musta for (ur=res->lsu, ul=lhs->lsu; ur<uresp1; ur++, ul++) *ur=*ul;
786172ac97cdSTom Musta res->digits=D2U(set->digits)*DECDPUN;
786272ac97cdSTom Musta /* maybe still too long */
786372ac97cdSTom Musta if (res->digits>set->digits) decDecap(res, res->digits-set->digits);
786472ac97cdSTom Musta }
786572ac97cdSTom Musta
786672ac97cdSTom Musta res->bits&=~DECSNAN; /* convert any sNaN to NaN, while */
786772ac97cdSTom Musta res->bits|=DECNAN; /* .. preserving sign */
786872ac97cdSTom Musta res->exponent=0; /* clean exponent */
786972ac97cdSTom Musta /* [coefficient was copied/decapitated] */
787072ac97cdSTom Musta return res;
787172ac97cdSTom Musta } /* decNaNs */
787272ac97cdSTom Musta
787372ac97cdSTom Musta /* ------------------------------------------------------------------ */
787472ac97cdSTom Musta /* decStatus -- apply non-zero status */
787572ac97cdSTom Musta /* */
787672ac97cdSTom Musta /* dn is the number to set if error */
787772ac97cdSTom Musta /* status contains the current status (not yet in context) */
787872ac97cdSTom Musta /* set is the context */
787972ac97cdSTom Musta /* */
788072ac97cdSTom Musta /* If the status is an error status, the number is set to a NaN, */
788172ac97cdSTom Musta /* unless the error was an overflow, divide-by-zero, or underflow, */
788272ac97cdSTom Musta /* in which case the number will have already been set. */
788372ac97cdSTom Musta /* */
788472ac97cdSTom Musta /* The context status is then updated with the new status. Note that */
788572ac97cdSTom Musta /* this may raise a signal, so control may never return from this */
788672ac97cdSTom Musta /* routine (hence resources must be recovered before it is called). */
788772ac97cdSTom Musta /* ------------------------------------------------------------------ */
788872ac97cdSTom Musta static void decStatus(decNumber *dn, uInt status, decContext *set) {
788972ac97cdSTom Musta if (status & DEC_NaNs) { /* error status -> NaN */
789072ac97cdSTom Musta /* if cause was an sNaN, clear and propagate [NaN is already set up] */
789172ac97cdSTom Musta if (status & DEC_sNaN) status&=~DEC_sNaN;
789272ac97cdSTom Musta else {
789372ac97cdSTom Musta decNumberZero(dn); /* other error: clean throughout */
789472ac97cdSTom Musta dn->bits=DECNAN; /* and make a quiet NaN */
789572ac97cdSTom Musta }
789672ac97cdSTom Musta }
789772ac97cdSTom Musta decContextSetStatus(set, status); /* [may not return] */
789872ac97cdSTom Musta return;
789972ac97cdSTom Musta } /* decStatus */
790072ac97cdSTom Musta
790172ac97cdSTom Musta /* ------------------------------------------------------------------ */
790272ac97cdSTom Musta /* decGetDigits -- count digits in a Units array */
790372ac97cdSTom Musta /* */
790472ac97cdSTom Musta /* uar is the Unit array holding the number (this is often an */
790572ac97cdSTom Musta /* accumulator of some sort) */
790672ac97cdSTom Musta /* len is the length of the array in units [>=1] */
790772ac97cdSTom Musta /* */
790872ac97cdSTom Musta /* returns the number of (significant) digits in the array */
790972ac97cdSTom Musta /* */
791072ac97cdSTom Musta /* All leading zeros are excluded, except the last if the array has */
791172ac97cdSTom Musta /* only zero Units. */
791272ac97cdSTom Musta /* ------------------------------------------------------------------ */
791372ac97cdSTom Musta /* This may be called twice during some operations. */
791472ac97cdSTom Musta static Int decGetDigits(Unit *uar, Int len) {
791572ac97cdSTom Musta Unit *up=uar+(len-1); /* -> msu */
791672ac97cdSTom Musta Int digits=(len-1)*DECDPUN+1; /* possible digits excluding msu */
791772ac97cdSTom Musta #if DECDPUN>4
791872ac97cdSTom Musta uInt const *pow; /* work */
791972ac97cdSTom Musta #endif
792072ac97cdSTom Musta /* (at least 1 in final msu) */
792172ac97cdSTom Musta #if DECCHECK
792272ac97cdSTom Musta if (len<1) printf("decGetDigits called with len<1 [%ld]\n", (LI)len);
792372ac97cdSTom Musta #endif
792472ac97cdSTom Musta
792572ac97cdSTom Musta for (; up>=uar; up--) {
792672ac97cdSTom Musta if (*up==0) { /* unit is all 0s */
792772ac97cdSTom Musta if (digits==1) break; /* a zero has one digit */
792872ac97cdSTom Musta digits-=DECDPUN; /* adjust for 0 unit */
792972ac97cdSTom Musta continue;}
793072ac97cdSTom Musta /* found the first (most significant) non-zero Unit */
793172ac97cdSTom Musta #if DECDPUN>1 /* not done yet */
793272ac97cdSTom Musta if (*up<10) break; /* is 1-9 */
793372ac97cdSTom Musta digits++;
793472ac97cdSTom Musta #if DECDPUN>2 /* not done yet */
793572ac97cdSTom Musta if (*up<100) break; /* is 10-99 */
793672ac97cdSTom Musta digits++;
793772ac97cdSTom Musta #if DECDPUN>3 /* not done yet */
793872ac97cdSTom Musta if (*up<1000) break; /* is 100-999 */
793972ac97cdSTom Musta digits++;
794072ac97cdSTom Musta #if DECDPUN>4 /* count the rest ... */
794172ac97cdSTom Musta for (pow=&powers[4]; *up>=*pow; pow++) digits++;
794272ac97cdSTom Musta #endif
794372ac97cdSTom Musta #endif
794472ac97cdSTom Musta #endif
794572ac97cdSTom Musta #endif
794672ac97cdSTom Musta break;
794772ac97cdSTom Musta } /* up */
794872ac97cdSTom Musta return digits;
794972ac97cdSTom Musta } /* decGetDigits */
795072ac97cdSTom Musta
7951*21d7826fSLuis Pires /* ------------------------------------------------------------------ */
7952*21d7826fSLuis Pires /* mulUInt128ByPowOf10 -- multiply a 128-bit unsigned integer by a */
7953*21d7826fSLuis Pires /* power of 10. */
7954*21d7826fSLuis Pires /* */
7955*21d7826fSLuis Pires /* The 128-bit factor composed of plow and phigh is multiplied */
7956*21d7826fSLuis Pires /* by 10^exp. */
7957*21d7826fSLuis Pires /* */
7958*21d7826fSLuis Pires /* plow pointer to the low 64 bits of the first factor */
7959*21d7826fSLuis Pires /* phigh pointer to the high 64 bits of the first factor */
7960*21d7826fSLuis Pires /* exp the exponent of the power of 10 of the second factor */
7961*21d7826fSLuis Pires /* */
7962*21d7826fSLuis Pires /* If the result fits in 128 bits, returns false and the */
7963*21d7826fSLuis Pires /* multiplication result through plow and phigh. */
7964*21d7826fSLuis Pires /* Otherwise, returns true. */
7965*21d7826fSLuis Pires /* ------------------------------------------------------------------ */
7966*21d7826fSLuis Pires static bool mulUInt128ByPowOf10(uLong *plow, uLong *phigh, uInt pow10)
7967*21d7826fSLuis Pires {
7968*21d7826fSLuis Pires while (pow10 >= ARRAY_SIZE(powers)) {
7969*21d7826fSLuis Pires if (mulu128(plow, phigh, powers[ARRAY_SIZE(powers) - 1])) {
7970*21d7826fSLuis Pires /* Overflow */
7971*21d7826fSLuis Pires return true;
7972*21d7826fSLuis Pires }
7973*21d7826fSLuis Pires pow10 -= ARRAY_SIZE(powers) - 1;
7974*21d7826fSLuis Pires }
7975*21d7826fSLuis Pires
7976*21d7826fSLuis Pires if (pow10 > 0) {
7977*21d7826fSLuis Pires return mulu128(plow, phigh, powers[pow10]);
7978*21d7826fSLuis Pires } else {
7979*21d7826fSLuis Pires return false;
7980*21d7826fSLuis Pires }
7981*21d7826fSLuis Pires }
7982*21d7826fSLuis Pires
798372ac97cdSTom Musta #if DECTRACE | DECCHECK
798472ac97cdSTom Musta /* ------------------------------------------------------------------ */
798572ac97cdSTom Musta /* decNumberShow -- display a number [debug aid] */
798672ac97cdSTom Musta /* dn is the number to show */
798772ac97cdSTom Musta /* */
798872ac97cdSTom Musta /* Shows: sign, exponent, coefficient (msu first), digits */
798972ac97cdSTom Musta /* or: sign, special-value */
799072ac97cdSTom Musta /* ------------------------------------------------------------------ */
799172ac97cdSTom Musta /* this is public so other modules can use it */
799272ac97cdSTom Musta void decNumberShow(const decNumber *dn) {
799372ac97cdSTom Musta const Unit *up; /* work */
799472ac97cdSTom Musta uInt u, d; /* .. */
799572ac97cdSTom Musta Int cut; /* .. */
799672ac97cdSTom Musta char isign='+'; /* main sign */
799772ac97cdSTom Musta if (dn==NULL) {
799872ac97cdSTom Musta printf("NULL\n");
799972ac97cdSTom Musta return;}
800072ac97cdSTom Musta if (decNumberIsNegative(dn)) isign='-';
800172ac97cdSTom Musta printf(" >> %c ", isign);
800272ac97cdSTom Musta if (dn->bits&DECSPECIAL) { /* Is a special value */
800372ac97cdSTom Musta if (decNumberIsInfinite(dn)) printf("Infinity");
800472ac97cdSTom Musta else { /* a NaN */
800572ac97cdSTom Musta if (dn->bits&DECSNAN) printf("sNaN"); /* signalling NaN */
800672ac97cdSTom Musta else printf("NaN");
800772ac97cdSTom Musta }
800872ac97cdSTom Musta /* if coefficient and exponent are 0, no more to do */
800972ac97cdSTom Musta if (dn->exponent==0 && dn->digits==1 && *dn->lsu==0) {
801072ac97cdSTom Musta printf("\n");
801172ac97cdSTom Musta return;}
801272ac97cdSTom Musta /* drop through to report other information */
801372ac97cdSTom Musta printf(" ");
801472ac97cdSTom Musta }
801572ac97cdSTom Musta
801672ac97cdSTom Musta /* now carefully display the coefficient */
801772ac97cdSTom Musta up=dn->lsu+D2U(dn->digits)-1; /* msu */
801872ac97cdSTom Musta printf("%ld", (LI)*up);
801972ac97cdSTom Musta for (up=up-1; up>=dn->lsu; up--) {
802072ac97cdSTom Musta u=*up;
802172ac97cdSTom Musta printf(":");
802272ac97cdSTom Musta for (cut=DECDPUN-1; cut>=0; cut--) {
802372ac97cdSTom Musta d=u/powers[cut];
802472ac97cdSTom Musta u-=d*powers[cut];
802572ac97cdSTom Musta printf("%ld", (LI)d);
802672ac97cdSTom Musta } /* cut */
802772ac97cdSTom Musta } /* up */
802872ac97cdSTom Musta if (dn->exponent!=0) {
802972ac97cdSTom Musta char esign='+';
803072ac97cdSTom Musta if (dn->exponent<0) esign='-';
803172ac97cdSTom Musta printf(" E%c%ld", esign, (LI)abs(dn->exponent));
803272ac97cdSTom Musta }
803372ac97cdSTom Musta printf(" [%ld]\n", (LI)dn->digits);
803472ac97cdSTom Musta } /* decNumberShow */
803572ac97cdSTom Musta #endif
803672ac97cdSTom Musta
803772ac97cdSTom Musta #if DECTRACE || DECCHECK
803872ac97cdSTom Musta /* ------------------------------------------------------------------ */
803972ac97cdSTom Musta /* decDumpAr -- display a unit array [debug/check aid] */
804072ac97cdSTom Musta /* name is a single-character tag name */
804172ac97cdSTom Musta /* ar is the array to display */
804272ac97cdSTom Musta /* len is the length of the array in Units */
804372ac97cdSTom Musta /* ------------------------------------------------------------------ */
804472ac97cdSTom Musta static void decDumpAr(char name, const Unit *ar, Int len) {
804572ac97cdSTom Musta Int i;
804672ac97cdSTom Musta const char *spec;
804772ac97cdSTom Musta #if DECDPUN==9
804872ac97cdSTom Musta spec="%09d ";
804972ac97cdSTom Musta #elif DECDPUN==8
805072ac97cdSTom Musta spec="%08d ";
805172ac97cdSTom Musta #elif DECDPUN==7
805272ac97cdSTom Musta spec="%07d ";
805372ac97cdSTom Musta #elif DECDPUN==6
805472ac97cdSTom Musta spec="%06d ";
805572ac97cdSTom Musta #elif DECDPUN==5
805672ac97cdSTom Musta spec="%05d ";
805772ac97cdSTom Musta #elif DECDPUN==4
805872ac97cdSTom Musta spec="%04d ";
805972ac97cdSTom Musta #elif DECDPUN==3
806072ac97cdSTom Musta spec="%03d ";
806172ac97cdSTom Musta #elif DECDPUN==2
806272ac97cdSTom Musta spec="%02d ";
806372ac97cdSTom Musta #else
806472ac97cdSTom Musta spec="%d ";
806572ac97cdSTom Musta #endif
806672ac97cdSTom Musta printf(" :%c: ", name);
806772ac97cdSTom Musta for (i=len-1; i>=0; i--) {
806872ac97cdSTom Musta if (i==len-1) printf("%ld ", (LI)ar[i]);
806972ac97cdSTom Musta else printf(spec, ar[i]);
807072ac97cdSTom Musta }
807172ac97cdSTom Musta printf("\n");
807272ac97cdSTom Musta return;}
807372ac97cdSTom Musta #endif
807472ac97cdSTom Musta
807572ac97cdSTom Musta #if DECCHECK
807672ac97cdSTom Musta /* ------------------------------------------------------------------ */
807772ac97cdSTom Musta /* decCheckOperands -- check operand(s) to a routine */
807872ac97cdSTom Musta /* res is the result structure (not checked; it will be set to */
807972ac97cdSTom Musta /* quiet NaN if error found (and it is not NULL)) */
808072ac97cdSTom Musta /* lhs is the first operand (may be DECUNRESU) */
808172ac97cdSTom Musta /* rhs is the second (may be DECUNUSED) */
808272ac97cdSTom Musta /* set is the context (may be DECUNCONT) */
808372ac97cdSTom Musta /* returns 0 if both operands, and the context are clean, or 1 */
808472ac97cdSTom Musta /* otherwise (in which case the context will show an error, */
808572ac97cdSTom Musta /* unless NULL). Note that res is not cleaned; caller should */
808672ac97cdSTom Musta /* handle this so res=NULL case is safe. */
808772ac97cdSTom Musta /* The caller is expected to abandon immediately if 1 is returned. */
808872ac97cdSTom Musta /* ------------------------------------------------------------------ */
808972ac97cdSTom Musta static Flag decCheckOperands(decNumber *res, const decNumber *lhs,
809072ac97cdSTom Musta const decNumber *rhs, decContext *set) {
809172ac97cdSTom Musta Flag bad=0;
809272ac97cdSTom Musta if (set==NULL) { /* oops; hopeless */
809372ac97cdSTom Musta #if DECTRACE || DECVERB
809472ac97cdSTom Musta printf("Reference to context is NULL.\n");
809572ac97cdSTom Musta #endif
809672ac97cdSTom Musta bad=1;
809772ac97cdSTom Musta return 1;}
809872ac97cdSTom Musta else if (set!=DECUNCONT
809972ac97cdSTom Musta && (set->digits<1 || set->round>=DEC_ROUND_MAX)) {
810072ac97cdSTom Musta bad=1;
810172ac97cdSTom Musta #if DECTRACE || DECVERB
810272ac97cdSTom Musta printf("Bad context [digits=%ld round=%ld].\n",
810372ac97cdSTom Musta (LI)set->digits, (LI)set->round);
810472ac97cdSTom Musta #endif
810572ac97cdSTom Musta }
810672ac97cdSTom Musta else {
810772ac97cdSTom Musta if (res==NULL) {
810872ac97cdSTom Musta bad=1;
810972ac97cdSTom Musta #if DECTRACE
811072ac97cdSTom Musta /* this one not DECVERB as standard tests include NULL */
811172ac97cdSTom Musta printf("Reference to result is NULL.\n");
811272ac97cdSTom Musta #endif
811372ac97cdSTom Musta }
811472ac97cdSTom Musta if (!bad && lhs!=DECUNUSED) bad=(decCheckNumber(lhs));
811572ac97cdSTom Musta if (!bad && rhs!=DECUNUSED) bad=(decCheckNumber(rhs));
811672ac97cdSTom Musta }
811772ac97cdSTom Musta if (bad) {
811872ac97cdSTom Musta if (set!=DECUNCONT) decContextSetStatus(set, DEC_Invalid_operation);
811972ac97cdSTom Musta if (res!=DECUNRESU && res!=NULL) {
812072ac97cdSTom Musta decNumberZero(res);
812172ac97cdSTom Musta res->bits=DECNAN; /* qNaN */
812272ac97cdSTom Musta }
812372ac97cdSTom Musta }
812472ac97cdSTom Musta return bad;
812572ac97cdSTom Musta } /* decCheckOperands */
812672ac97cdSTom Musta
812772ac97cdSTom Musta /* ------------------------------------------------------------------ */
812872ac97cdSTom Musta /* decCheckNumber -- check a number */
812972ac97cdSTom Musta /* dn is the number to check */
813072ac97cdSTom Musta /* returns 0 if the number is clean, or 1 otherwise */
813172ac97cdSTom Musta /* */
813272ac97cdSTom Musta /* The number is considered valid if it could be a result from some */
813372ac97cdSTom Musta /* operation in some valid context. */
813472ac97cdSTom Musta /* ------------------------------------------------------------------ */
813572ac97cdSTom Musta static Flag decCheckNumber(const decNumber *dn) {
813672ac97cdSTom Musta const Unit *up; /* work */
813772ac97cdSTom Musta uInt maxuint; /* .. */
813872ac97cdSTom Musta Int ae, d, digits; /* .. */
813972ac97cdSTom Musta Int emin, emax; /* .. */
814072ac97cdSTom Musta
814172ac97cdSTom Musta if (dn==NULL) { /* hopeless */
814272ac97cdSTom Musta #if DECTRACE
814372ac97cdSTom Musta /* this one not DECVERB as standard tests include NULL */
814472ac97cdSTom Musta printf("Reference to decNumber is NULL.\n");
814572ac97cdSTom Musta #endif
814672ac97cdSTom Musta return 1;}
814772ac97cdSTom Musta
814872ac97cdSTom Musta /* check special values */
814972ac97cdSTom Musta if (dn->bits & DECSPECIAL) {
815072ac97cdSTom Musta if (dn->exponent!=0) {
815172ac97cdSTom Musta #if DECTRACE || DECVERB
815272ac97cdSTom Musta printf("Exponent %ld (not 0) for a special value [%02x].\n",
815372ac97cdSTom Musta (LI)dn->exponent, dn->bits);
815472ac97cdSTom Musta #endif
815572ac97cdSTom Musta return 1;}
815672ac97cdSTom Musta
815772ac97cdSTom Musta /* 2003.09.08: NaNs may now have coefficients, so next tests Inf only */
815872ac97cdSTom Musta if (decNumberIsInfinite(dn)) {
815972ac97cdSTom Musta if (dn->digits!=1) {
816072ac97cdSTom Musta #if DECTRACE || DECVERB
816172ac97cdSTom Musta printf("Digits %ld (not 1) for an infinity.\n", (LI)dn->digits);
816272ac97cdSTom Musta #endif
816372ac97cdSTom Musta return 1;}
816472ac97cdSTom Musta if (*dn->lsu!=0) {
816572ac97cdSTom Musta #if DECTRACE || DECVERB
816672ac97cdSTom Musta printf("LSU %ld (not 0) for an infinity.\n", (LI)*dn->lsu);
816772ac97cdSTom Musta #endif
816872ac97cdSTom Musta decDumpAr('I', dn->lsu, D2U(dn->digits));
816972ac97cdSTom Musta return 1;}
817072ac97cdSTom Musta } /* Inf */
817172ac97cdSTom Musta /* 2002.12.26: negative NaNs can now appear through proposed IEEE */
817272ac97cdSTom Musta /* concrete formats (decimal64, etc.). */
817372ac97cdSTom Musta return 0;
817472ac97cdSTom Musta }
817572ac97cdSTom Musta
817672ac97cdSTom Musta /* check the coefficient */
817772ac97cdSTom Musta if (dn->digits<1 || dn->digits>DECNUMMAXP) {
817872ac97cdSTom Musta #if DECTRACE || DECVERB
817972ac97cdSTom Musta printf("Digits %ld in number.\n", (LI)dn->digits);
818072ac97cdSTom Musta #endif
818172ac97cdSTom Musta return 1;}
818272ac97cdSTom Musta
818372ac97cdSTom Musta d=dn->digits;
818472ac97cdSTom Musta
818572ac97cdSTom Musta for (up=dn->lsu; d>0; up++) {
818672ac97cdSTom Musta if (d>DECDPUN) maxuint=DECDPUNMAX;
818772ac97cdSTom Musta else { /* reached the msu */
818872ac97cdSTom Musta maxuint=powers[d]-1;
818972ac97cdSTom Musta if (dn->digits>1 && *up<powers[d-1]) {
819072ac97cdSTom Musta #if DECTRACE || DECVERB
819172ac97cdSTom Musta printf("Leading 0 in number.\n");
819272ac97cdSTom Musta decNumberShow(dn);
819372ac97cdSTom Musta #endif
819472ac97cdSTom Musta return 1;}
819572ac97cdSTom Musta }
819672ac97cdSTom Musta if (*up>maxuint) {
819772ac97cdSTom Musta #if DECTRACE || DECVERB
819872ac97cdSTom Musta printf("Bad Unit [%08lx] in %ld-digit number at offset %ld [maxuint %ld].\n",
819972ac97cdSTom Musta (LI)*up, (LI)dn->digits, (LI)(up-dn->lsu), (LI)maxuint);
820072ac97cdSTom Musta #endif
820172ac97cdSTom Musta return 1;}
820272ac97cdSTom Musta d-=DECDPUN;
820372ac97cdSTom Musta }
820472ac97cdSTom Musta
820572ac97cdSTom Musta /* check the exponent. Note that input operands can have exponents */
820672ac97cdSTom Musta /* which are out of the set->emin/set->emax and set->digits range */
820772ac97cdSTom Musta /* (just as they can have more digits than set->digits). */
820872ac97cdSTom Musta ae=dn->exponent+dn->digits-1; /* adjusted exponent */
820972ac97cdSTom Musta emax=DECNUMMAXE;
821072ac97cdSTom Musta emin=DECNUMMINE;
821172ac97cdSTom Musta digits=DECNUMMAXP;
821272ac97cdSTom Musta if (ae<emin-(digits-1)) {
821372ac97cdSTom Musta #if DECTRACE || DECVERB
821472ac97cdSTom Musta printf("Adjusted exponent underflow [%ld].\n", (LI)ae);
821572ac97cdSTom Musta decNumberShow(dn);
821672ac97cdSTom Musta #endif
821772ac97cdSTom Musta return 1;}
821872ac97cdSTom Musta if (ae>+emax) {
821972ac97cdSTom Musta #if DECTRACE || DECVERB
822072ac97cdSTom Musta printf("Adjusted exponent overflow [%ld].\n", (LI)ae);
822172ac97cdSTom Musta decNumberShow(dn);
822272ac97cdSTom Musta #endif
822372ac97cdSTom Musta return 1;}
822472ac97cdSTom Musta
822572ac97cdSTom Musta return 0; /* it's OK */
822672ac97cdSTom Musta } /* decCheckNumber */
822772ac97cdSTom Musta
822872ac97cdSTom Musta /* ------------------------------------------------------------------ */
822972ac97cdSTom Musta /* decCheckInexact -- check a normal finite inexact result has digits */
823072ac97cdSTom Musta /* dn is the number to check */
823172ac97cdSTom Musta /* set is the context (for status and precision) */
823272ac97cdSTom Musta /* sets Invalid operation, etc., if some digits are missing */
823372ac97cdSTom Musta /* [this check is not made for DECSUBSET compilation or when */
823472ac97cdSTom Musta /* subnormal is not set] */
823572ac97cdSTom Musta /* ------------------------------------------------------------------ */
823672ac97cdSTom Musta static void decCheckInexact(const decNumber *dn, decContext *set) {
823772ac97cdSTom Musta #if !DECSUBSET && DECEXTFLAG
823872ac97cdSTom Musta if ((set->status & (DEC_Inexact|DEC_Subnormal))==DEC_Inexact
823972ac97cdSTom Musta && (set->digits!=dn->digits) && !(dn->bits & DECSPECIAL)) {
824072ac97cdSTom Musta #if DECTRACE || DECVERB
824172ac97cdSTom Musta printf("Insufficient digits [%ld] on normal Inexact result.\n",
824272ac97cdSTom Musta (LI)dn->digits);
824372ac97cdSTom Musta decNumberShow(dn);
824472ac97cdSTom Musta #endif
824572ac97cdSTom Musta decContextSetStatus(set, DEC_Invalid_operation);
824672ac97cdSTom Musta }
824772ac97cdSTom Musta #else
824872ac97cdSTom Musta /* next is a noop for quiet compiler */
824972ac97cdSTom Musta if (dn!=NULL && dn->digits==0) set->status|=DEC_Invalid_operation;
825072ac97cdSTom Musta #endif
825172ac97cdSTom Musta return;
825272ac97cdSTom Musta } /* decCheckInexact */
825372ac97cdSTom Musta #endif
825472ac97cdSTom Musta
825572ac97cdSTom Musta #if DECALLOC
825672ac97cdSTom Musta #undef malloc
825772ac97cdSTom Musta #undef free
825872ac97cdSTom Musta /* ------------------------------------------------------------------ */
825972ac97cdSTom Musta /* decMalloc -- accountable allocation routine */
826072ac97cdSTom Musta /* n is the number of bytes to allocate */
826172ac97cdSTom Musta /* */
826272ac97cdSTom Musta /* Semantics is the same as the stdlib malloc routine, but bytes */
826372ac97cdSTom Musta /* allocated are accounted for globally, and corruption fences are */
826472ac97cdSTom Musta /* added before and after the 'actual' storage. */
826572ac97cdSTom Musta /* ------------------------------------------------------------------ */
826672ac97cdSTom Musta /* This routine allocates storage with an extra twelve bytes; 8 are */
826772ac97cdSTom Musta /* at the start and hold: */
826872ac97cdSTom Musta /* 0-3 the original length requested */
826972ac97cdSTom Musta /* 4-7 buffer corruption detection fence (DECFENCE, x4) */
827072ac97cdSTom Musta /* The 4 bytes at the end also hold a corruption fence (DECFENCE, x4) */
827172ac97cdSTom Musta /* ------------------------------------------------------------------ */
827272ac97cdSTom Musta static void *decMalloc(size_t n) {
827372ac97cdSTom Musta uInt size=n+12; /* true size */
827472ac97cdSTom Musta void *alloc; /* -> allocated storage */
827572ac97cdSTom Musta uInt *j; /* work */
827672ac97cdSTom Musta uByte *b, *b0; /* .. */
827772ac97cdSTom Musta
827872ac97cdSTom Musta alloc=malloc(size); /* -> allocated storage */
827972ac97cdSTom Musta if (alloc==NULL) return NULL; /* out of strorage */
828072ac97cdSTom Musta b0=(uByte *)alloc; /* as bytes */
828172ac97cdSTom Musta decAllocBytes+=n; /* account for storage */
828272ac97cdSTom Musta j=(uInt *)alloc; /* -> first four bytes */
828372ac97cdSTom Musta *j=n; /* save n */
828472ac97cdSTom Musta /* printf(" alloc ++ dAB: %ld (%d)\n", decAllocBytes, n); */
828572ac97cdSTom Musta for (b=b0+4; b<b0+8; b++) *b=DECFENCE;
828672ac97cdSTom Musta for (b=b0+n+8; b<b0+n+12; b++) *b=DECFENCE;
828772ac97cdSTom Musta return b0+8; /* -> play area */
828872ac97cdSTom Musta } /* decMalloc */
828972ac97cdSTom Musta
829072ac97cdSTom Musta /* ------------------------------------------------------------------ */
829172ac97cdSTom Musta /* decFree -- accountable free routine */
829272ac97cdSTom Musta /* alloc is the storage to free */
829372ac97cdSTom Musta /* */
829472ac97cdSTom Musta /* Semantics is the same as the stdlib malloc routine, except that */
829572ac97cdSTom Musta /* the global storage accounting is updated and the fences are */
829672ac97cdSTom Musta /* checked to ensure that no routine has written 'out of bounds'. */
829772ac97cdSTom Musta /* ------------------------------------------------------------------ */
829872ac97cdSTom Musta /* This routine first checks that the fences have not been corrupted. */
829972ac97cdSTom Musta /* It then frees the storage using the 'truw' storage address (that */
830072ac97cdSTom Musta /* is, offset by 8). */
830172ac97cdSTom Musta /* ------------------------------------------------------------------ */
830272ac97cdSTom Musta static void decFree(void *alloc) {
830372ac97cdSTom Musta uInt *j, n; /* pointer, original length */
830472ac97cdSTom Musta uByte *b, *b0; /* work */
830572ac97cdSTom Musta
830672ac97cdSTom Musta if (alloc==NULL) return; /* allowed; it's a nop */
830772ac97cdSTom Musta b0=(uByte *)alloc; /* as bytes */
830872ac97cdSTom Musta b0-=8; /* -> true start of storage */
830972ac97cdSTom Musta j=(uInt *)b0; /* -> first four bytes */
831072ac97cdSTom Musta n=*j; /* lift */
831172ac97cdSTom Musta for (b=b0+4; b<b0+8; b++) if (*b!=DECFENCE)
831272ac97cdSTom Musta printf("=== Corrupt byte [%02x] at offset %d from %ld ===\n", *b,
831372ac97cdSTom Musta b-b0-8, (Int)b0);
831472ac97cdSTom Musta for (b=b0+n+8; b<b0+n+12; b++) if (*b!=DECFENCE)
831572ac97cdSTom Musta printf("=== Corrupt byte [%02x] at offset +%d from %ld, n=%ld ===\n", *b,
831672ac97cdSTom Musta b-b0-8, (Int)b0, n);
831772ac97cdSTom Musta free(b0); /* drop the storage */
831872ac97cdSTom Musta decAllocBytes-=n; /* account for storage */
831972ac97cdSTom Musta /* printf(" free -- dAB: %d (%d)\n", decAllocBytes, -n); */
832072ac97cdSTom Musta } /* decFree */
832172ac97cdSTom Musta #define malloc(a) decMalloc(a)
832272ac97cdSTom Musta #define free(a) decFree(a)
832372ac97cdSTom Musta #endif
8324