Пример #1
0
 public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc)
     : this(unscaledVal, scale)
 {
     inplaceRound(mc);
 }
Пример #2
0
 public BigDecimal divide(BigDecimal rhs,int round)
 {
     MathContext set;
     set=new MathContext(0,MathContext.PLAIN,false,round); // [checks round, too]
     return this.dodivide('D',rhs,set,-1); // take scale from LHS
 }
Пример #3
0
 public BigDecimal divide(BigDecimal rhs,MathContext set)
 {
     return this.dodivide('D',rhs,set,-1);
 }
Пример #4
0
 private BigDecimal round(MathContext set)
 {
     return round(set.digits,set.roundingMode);
 }
Пример #5
0
        public BigDecimal add(BigDecimal rhs,MathContext set)
        {
            BigDecimal lhs;
            int reqdig;
            BigDecimal res;
            sbyte[] usel;
            int usellen;
            sbyte[] user;
            int userlen;
            int newlen=0;
            int tlen=0;
            int mult=0;
            sbyte[] t=null;
            int ia=0;
            int ib=0;
            int ea=0;
            int eb=0;
            sbyte ca=0;
            sbyte cb=0;
            /* determine requested digits and form */
            if (set.lostDigits)
                checkdigits(rhs,set.digits);
            lhs=this; // name for clarity and proxy

            /* Quick exit for add floating 0 */
            // plus() will optimize to return same object if possible
            if (lhs.ind==0)
                if (set.form!=MathContext.PLAIN)
                    return rhs.plus(set);
            if (rhs.ind==0)
                if (set.form!=MathContext.PLAIN)
                    return lhs.plus(set);

            /* Prepare numbers (round, unless unlimited precision) */
            reqdig=set.digits; // local copy (heavily used)
            if (reqdig>0)
                {
                    if (lhs.mant.Length>reqdig)
                        lhs=clone(lhs).round(set);
                    if (rhs.mant.Length>reqdig)
                        rhs=clone(rhs).round(set);
                    // [we could reuse the new LHS for result in this case]
                }

            res=new BigDecimal(); // build result here

            /* Now see how much we have to pad or truncate lhs or rhs in order
               to align the numbers.  If one number is much larger than the
               other, then the smaller cannot affect the answer [but we may
               still need to pad with up to DIGITS trailing zeros]. */
            // Note sign may be 0 if digits (reqdig) is 0
            // usel and user will be the sbyte arrays passed to the adder; we'll
            // use them on all paths except quick exits
            usel=lhs.mant;
            usellen=lhs.mant.Length;
            user=rhs.mant;
            userlen=rhs.mant.Length;
                    if (lhs.exp==rhs.exp)
                        {/* no padding needed */
                            // This is the most common, and fastest, path
                            res.exp=lhs.exp;
                        }
                    else if (lhs.exp>rhs.exp)
                        { // need to pad lhs and/or truncate rhs
                            newlen=(usellen+lhs.exp)-rhs.exp;
                            /* If, after pad, lhs would be longer than rhs by digits+1 or
                               more (and digits>0) then rhs cannot affect answer, so we only
                               need to pad up to a length of DIGITS+1. */
                            if (newlen>=((userlen+reqdig)+1))
                                if (reqdig>0)
                                    {
                                        // LHS is sufficient
                                        res.mant=usel;
                                        res.exp=lhs.exp;
                                        res.ind=lhs.ind;
                                        if (usellen<reqdig)
                                            { // need 0 padding
                                                res.mant=extend(lhs.mant,reqdig);
                                                res.exp=res.exp-((reqdig-usellen));
                                            }
                                        return res.finish(set,false);
                                    }
                            // RHS may affect result
                            res.exp=rhs.exp; // expected final exponent
                            if (newlen>(reqdig+1))
                                if (reqdig>0)
                                    {
                                        // LHS will be max; RHS truncated
                                        tlen=(newlen-reqdig)-1; // truncation length
                                        userlen=userlen-tlen;
                                        res.exp=res.exp+tlen;
                                        newlen=reqdig+1;
                                    }
                            if (newlen>usellen)
                                usellen=newlen; // need to pad LHS
                        }
                    else{ // need to pad rhs and/or truncate lhs
                        newlen=(userlen+rhs.exp)-lhs.exp;
                        if (newlen>=((usellen+reqdig)+1))
                            if (reqdig>0)
                                {
                                    // RHS is sufficient
                                    res.mant=user;
                                    res.exp=rhs.exp;
                                    res.ind=rhs.ind;
                                    if (userlen<reqdig)
                                        { // need 0 padding
                                            res.mant=extend(rhs.mant,reqdig);
                                            res.exp=res.exp-((reqdig-userlen));
                                        }
                                    return res.finish(set,false);
                                }
                        // LHS may affect result
                        res.exp=lhs.exp; // expected final exponent
                        if (newlen>(reqdig+1))
                            if (reqdig>0)
                                {
                                    // RHS will be max; LHS truncated
                                    tlen=(newlen-reqdig)-1; // truncation length
                                    usellen=usellen-tlen;
                                    res.exp=res.exp+tlen;
                                    newlen=reqdig+1;
                                }
                        if (newlen>userlen)
                            userlen=newlen; // need to pad RHS
                    }

            if (lhs.ind==iszero)
                res.ind=ispos;
            else
                res.ind=lhs.ind; // likely sign, all paths
            if (((lhs.ind==isneg)?1:0)==((rhs.ind==isneg)?1:0))  // same sign, 0 non-negative
                mult=1;
            else {
                        mult=-1; // will cause subtract
                        /* Before we can subtract we must determine which is the larger,
                           as our add/subtract routine only handles non-negative results
                           so we may need to swap the operands. */

                                if (rhs.ind==iszero){
                                    // original A bigger
                                }else if ((usellen<userlen)|(lhs.ind==iszero))
                                    { // original B bigger
                                        t=usel;
                                        usel=user;
                                        user=t; // swap
                                        tlen=usellen;
                                        usellen=userlen;
                                        userlen=tlen; // ..
                                        res.ind=(sbyte)-res.ind; // and set sign
                                    }
                                else if (usellen>userlen){
                                    // original A bigger
                                }else{
                                    {/* logical lengths the same */ // need compare
                                        /* may still need to swap: compare the strings */
                                        ia=0;
                                        ib=0;
                                        ea=usel.Length-1;
                                        eb=user.Length-1;
                                        for(;;){
                                                if (ia<=ea)
                                                    ca=usel[ia];
                                                else
                                                    {
                                                        if (ib>eb)
                                                            {/* identical */
                                                                if (set.form!=MathContext.PLAIN)
                                                                    return ZERO;
                                                                // [if PLAIN we must do the subtract, in case of 0.000 results]
                                                                break;
                                                            }
                                                        ca=(sbyte)0;
                                                    }
                                                if (ib<=eb)
                                                    cb=user[ib];
                                                else
                                                    cb=(sbyte)0;
                                                if (ca!=cb)
                                                    {
                                                        if (ca<cb)
                                                            {/* swap needed */
                                                                t=usel;
                                                                usel=user;
                                                                user=t; // swap
                                                                tlen=usellen;
                                                                usellen=userlen;
                                                                userlen=tlen; // ..
                                                                res.ind=(sbyte)-res.ind;
                                                            }
                                                        break;
                                                    }
                                                /* mantissas the same, so far */
                                                ia++;
                                                ib++;
                                            }
                                    } // lengths the same
                                }
            }
            res.mant=byteaddsub(usel,usellen,user,userlen,mult,false);
            return res.finish(set,false);
        }
Пример #6
0
 public BigDecimal remainder(BigDecimal rhs,MathContext set)
 {
     return this.dodivide('R',rhs,set,-1);
 }
Пример #7
0
        private BigDecimal dodivide(char code,BigDecimal rhs,MathContext set,int scale)
        {
            BigDecimal lhs;
            int reqdig;
            int newexp;
            BigDecimal res;
            int newlen;
            sbyte[] var1;
            int var1len;
            sbyte[] var2;
            int var2len;
            int b2b;
            int have;
            int thisdigit=0;
            int i=0;
            int ix=0;
            sbyte v2=0;
            int ba=0;
            int mult=0;
            int start=0;
            int padding=0;
            int d=0;
            sbyte[] newvar1=null;
            sbyte lasthave=0;
            int actdig=0;
            sbyte[] newmant=null;

            if (set.lostDigits)
                checkdigits(rhs,set.digits);
            lhs=this; // name for clarity

            // [note we must have checked lostDigits before the following checks]
            if (rhs.ind==0)
                throw new System.ArithmeticException("Divide by 0"); // includes 0/0
            if (lhs.ind==0)
                { // 0/x => 0 [possibly with .0s]
                    if (set.form!=MathContext.PLAIN)
                        return ZERO;
                    if (scale==(-1))
                        return lhs;
                    return lhs.setScale(scale);
                }

            /* Prepare numbers according to BigDecimal rules */
            reqdig=set.digits; // local copy (heavily used)
            if (reqdig>0)
                {
                    if (lhs.mant.Length>reqdig)
                        lhs=clone(lhs).round(set);
                    if (rhs.mant.Length>reqdig)
                        rhs=clone(rhs).round(set);
                }
            else
                {/* scaled divide */
                    if (scale==(-1))
                        scale=lhs.scale();
                    // set reqdig to be at least large enough for the computation
                    reqdig=lhs.mant.Length; // base length
                    // next line handles both positive lhs.exp and also scale mismatch
                    if (scale!=((int)-lhs.exp))
                        reqdig=(reqdig+scale)+lhs.exp;
                    reqdig=(reqdig-((rhs.mant.Length-1)))-rhs.exp; // reduce by RHS effect
                    if (reqdig<lhs.mant.Length)
                        reqdig=lhs.mant.Length; // clamp
                    if (reqdig<rhs.mant.Length)
                        reqdig=rhs.mant.Length; // ..
                }

            /* precalculate exponent */
            newexp=((lhs.exp-rhs.exp)+lhs.mant.Length)-rhs.mant.Length;
            /* If new exponent -ve, then some quick exits are possible */
            if (newexp<0)
                if (code!='D')
                    {
                        if (code=='I')
                            return ZERO; // easy - no integer part
                        /* Must be 'R'; remainder is [finished clone of] input value */
                        return clone(lhs).finish(set,false);
                    }

            /* We need slow division */
            res=new BigDecimal(); // where we'll build result
            res.ind=(sbyte)(lhs.ind*rhs.ind); // final sign (for D/I)
            res.exp=newexp; // initial exponent (for D/I)
            res.mant=new sbyte[reqdig+1]; // where build the result

            /* Now [virtually pad the mantissae with trailing zeros */
            // Also copy the LHS, which will be our working array
            newlen=(reqdig+reqdig)+1;
            var1=extend(lhs.mant,newlen); // always makes longer, so new safe array
            var1len=newlen; // [remaining digits are 0]

            var2=rhs.mant;
            var2len=newlen;

            /* Calculate first two digits of rhs (var2), +1 for later estimations */
            b2b=(var2[0]*10)+1;
            if (var2.Length>1)
                b2b=b2b+var2[1];

            /* start the long-division loops */
            have=0;
            {for(;;){
                    thisdigit=0;
                    /* find the next digit */
                    {inner:for(;;){
                            if (var1len<var2len)
                                break; // V1 too low
                            if (var1len==var2len)
                                { // compare needed
                                            for(ix=var1len,i=0;ix>0;ix--,i++){
                                                    // var1len is always <= var1.Length
                                                    if (i<var2.Length)
                                                        v2=var2[i];
                                                    else
                                                        v2=(sbyte)0;
                                                    if (var1[i]<v2)
                                                        goto breakInner; // V1 too low
                                                    if (var1[i]>v2)
                                                        goto breakCompare; // OK to subtract
                                                }
                                            /* reach here if lhs and rhs are identical; subtraction will
                                               increase digit by one, and the residue will be 0 so we
                                               are done; leave the loop with residue set to 0 (in case
                                               code is 'R' or ROUND_UNNECESSARY or a ROUND_HALF_xxxx is
                                               being checked) */
                                            thisdigit++;
                                            res.mant[have]=(sbyte)thisdigit;
                                            have++;
                                            var1[0]=(sbyte)0; // residue to 0 [this is all we'll test]
                                            // var1len=1      -- [optimized out]
                                            goto breakOuter;
                                    breakCompare:
                                    /* prepare for subtraction.  Estimate BA (lengths the same) */
                                    ba=(int)var1[0]; // use only first digit
                                } // lengths the same
                            else
                                {/* lhs longer than rhs */
                                    /* use first two digits for estimate */
                                    ba=var1[0]*10;
                                    if (var1len>1)
                                        ba=ba+var1[1];
                                }
                            /* subtraction needed; V1>=V2 */
                            mult=(ba*10)/b2b;
                            if (mult==0)
                                mult=1;
                            thisdigit=thisdigit+mult;
                            // subtract; var1 reusable
                            var1=byteaddsub(var1,var1len,var2,var2len,(int)-mult,true);
                            if (var1[0]!=0)
                                goto inner; // maybe another subtract needed
                            /* V1 now probably has leading zeros, remove leading 0's and try
                               again. (It could be longer than V2) */
                            for(ix=var1len-2,start=0;start<=ix;start++){
                                    if (var1[start]!=0)
                                        break;
                                    var1len--;
                                }
                            if (start==0)
                                goto inner;
                            // shift left
                            System.Array.Copy(var1,start,var1,0,var1len);
                        }
                    }/*inner*/
                    breakInner:

                    /* We have the next digit */
                    if ((have!=0)|(thisdigit!=0))
                        { // put the digit we got
                            res.mant[have]=(sbyte)thisdigit;
                            have++;
                            if (have==(reqdig+1))
                                goto breakOuter; // we have all we need
                            if (var1[0]==0)
                                goto breakOuter; // residue now 0
                        }
                    /* can leave now if a scaled divide and exponent is small enough */
                    if (scale>=0)
                        if (((int)-res.exp)>scale)
                            goto breakOuter;
                    /* can leave now if not Divide and no integer part left  */
                    if (code!='D')
                        if (res.exp<=0)
                            goto breakOuter;
                    res.exp=res.exp-1; // reduce the exponent
                    /* to get here, V1 is less than V2, so divide V2 by 10 and go for
                       the next digit */
                    var2len--;
                }
            }/*outer*/
            breakOuter:

            /* here when we have finished dividing, for some reason */
            // have is the number of digits we collected in res.mant
            if (have==0)
                have=1; // res.mant[0] is 0; we always want a digit

            if ((code=='I')|(code=='R'))
                {/* check for integer overflow needed */
                    if ((have+res.exp)>reqdig)
                        throw new System.ArithmeticException("Integer overflow");

                    if (code=='R') {
                                /* We were doing Remainder -- return the residue */
                                if (res.mant[0]==0)  // no integer part was found
                                    return clone(lhs).finish(set,false); // .. so return lhs, canonical
                                if (var1[0]==0)
                                    return ZERO; // simple 0 residue
                                res.ind=lhs.ind; // sign is always as LHS
                                /* Calculate the exponent by subtracting the number of padding zeros
                                   we added and adding the original exponent */
                                padding=((reqdig+reqdig)+1)-lhs.mant.Length;
                                res.exp=(res.exp-padding)+lhs.exp;

                                /* strip insignificant padding zeros from residue, and create/copy
                                   the resulting mantissa if need be */
                                d=var1len;
                                for(i=d-1;i>=1;i--){if(!((res.exp<lhs.exp)&(res.exp<rhs.exp)))break;
                                        if (var1[i]!=0)
                                            break;
                                        d--;
                                        res.exp=res.exp+1;
                                    }
                                if (d<var1.Length)
                                    {/* need to reduce */
                                        newvar1=new sbyte[d];
                                        System.Array.Copy(var1,0,newvar1,0,d); // shorten
                                        var1=newvar1;
                                    }
                                res.mant=var1;
                                return res.finish(set,false);
                    }
                }

            else
                {/* 'D' -- no overflow check needed */
                    // If there was a residue then bump the final digit (iff 0 or 5)
                    // so that the residue is visible for ROUND_UP, ROUND_HALF_xxx and
                    // ROUND_UNNECESSARY checks (etc.) later.
                    // [if we finished early, the residue will be 0]
                    if (var1[0]!=0)
                        { // residue not 0
                            lasthave=res.mant[have-1];
                            if (((lasthave%5))==0)
                                res.mant[have-1]=(sbyte)(lasthave+1);
                        }
                }

            /* Here for Divide or Integer Divide */
            // handle scaled results first ['I' always scale 0, optional for 'D']
            if (scale>=0) {
                        // say 'scale have res.exp len' scale have res.exp res.mant.Length
                        if (have!=res.mant.Length)
                            // already padded with 0's, so just adjust exponent
                            res.exp=res.exp-((res.mant.Length-have));
                        // calculate number of digits we really want [may be 0]
                        actdig=res.mant.Length-((((int)-res.exp)-scale));
                        res.round(actdig,set.roundingMode); // round to desired length
                        // This could have shifted left if round (say) 0.9->1[.0]
                        // Repair if so by adding a zero and reducing exponent
                        if (res.exp!=((int)-scale))
                            {
                                res.mant=extend(res.mant,res.mant.Length+1);
                                res.exp=res.exp-1;
                            }
                        return res.finish(set,true); // [strip if not PLAIN]
            }
            // reach here only if a non-scaled
            if (have==res.mant.Length)
                { // got digits+1 digits
                    res.round(set);
                    have=reqdig;
                }
            else
                {/* have<=reqdig */
                    if (res.mant[0]==0)
                        return ZERO; // fastpath
                    // make the mantissa truly just 'have' long
                    // [we could let finish do this, during strip, if we adjusted
                    // the exponent; however, truncation avoids the strip loop]
                    newmant=new sbyte[have]; // shorten
                    System.Array.Copy(res.mant,0,newmant,0,have);
                    res.mant=newmant;
                }
            return res.finish(set,true);
        }
Пример #8
0
        public BigDecimal[] divideAndRemainder(BigDecimal divisor, MathContext mc)
        {
            BigDecimal[] quotAndRem = new BigDecimal[2];

            quotAndRem[0] = this.divideToIntegralValue(divisor, mc);
            quotAndRem[1] = this.subtract( quotAndRem[0].multiply(divisor) );
            return quotAndRem;
        }
Пример #9
0
 public BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc)
 {
     int mcPrecision = mc.getPrecision();
     int diffPrecision = this.precision() - divisor.precision();
     int lastPow = TEN_POW.Length - 1;
     long diffScale = (long)this._scale - divisor._scale;
     long newScale = diffScale;
     long quotPrecision = diffPrecision - diffScale + 1;
     BigInteger[] quotAndRem = new BigInteger[2];
     // In special cases it call the dual method
     if ((mcPrecision == 0) || (this.isZero()) || (divisor.isZero())) {
         return this.divideToIntegralValue(divisor);
     }
     // Let be:   this = [u1,s1]   and   divisor = [u2,s2]
     if (quotPrecision <= 0) {
         quotAndRem[0] = BigInteger.ZERO;
     } else if (diffScale == 0) {
         // CASE s1 == s2:  to calculate   u1 / u2
         quotAndRem[0] = this.getUnscaledValue().divide( divisor.getUnscaledValue() );
     } else if (diffScale > 0) {
         // CASE s1 >= s2:  to calculate   u1 / (u2 * 10^(s1-s2)
         quotAndRem[0] = this.getUnscaledValue().divide(
             divisor.getUnscaledValue().multiply(Multiplication.powerOf10(diffScale)) );
         // To chose  10^newScale  to get a quotient with at least 'mc.precision()' digits
         newScale = Math.Min(diffScale, Math.Max(mcPrecision - quotPrecision + 1, 0));
         // To calculate: (u1 / (u2 * 10^(s1-s2)) * 10^newScale
         quotAndRem[0] = quotAndRem[0].multiply(Multiplication.powerOf10(newScale));
     } else {// CASE s2 > s1:
         /* To calculate the minimum power of ten, such that the quotient
          *   (u1 * 10^exp) / u2   has at least 'mc.precision()' digits. */
         long exp = Math.Min(-diffScale, Math.Max((long)mcPrecision - diffPrecision, 0));
         long compRemDiv;
         // Let be:   (u1 * 10^exp) / u2 = [q,r]
         quotAndRem = this.getUnscaledValue().multiply(Multiplication.powerOf10(exp)).
             divideAndRemainder(divisor.getUnscaledValue());
         newScale += exp; // To fix the scale
         exp = -newScale; // The remaining power of ten
         // If after division there is a remainder...
         if ((quotAndRem[1].signum() != 0) && (exp > 0)) {
             // Log10(r) + ((s2 - s1) - exp) > mc.precision ?
             compRemDiv = (new BigDecimal(quotAndRem[1])).precision()
                 + exp - divisor.precision();
             if (compRemDiv == 0) {
                 // To calculate:  (r * 10^exp2) / u2
                 quotAndRem[1] = quotAndRem[1].multiply(Multiplication.powerOf10(exp)).
                     divide(divisor.getUnscaledValue());
                 compRemDiv = Math.Abs(quotAndRem[1].signum());
             }
             if (compRemDiv > 0) {
                 // The quotient won't fit in 'mc.precision()' digits
                 throw new ArithmeticException("Division impossible");
             }
         }
     }
     // Fast return if the quotient is zero
     if (quotAndRem[0].signum() == 0) {
         return zeroScaledBy(diffScale);
     }
     BigInteger strippedBI = quotAndRem[0];
     BigDecimal integralValue = new BigDecimal(quotAndRem[0]);
     long resultPrecision = integralValue.precision();
     int i = 1;
     // To strip trailing zeros until the specified precision is reached
     while (!strippedBI.testBit(0)) {
         quotAndRem = strippedBI.divideAndRemainder(TEN_POW[i]);
         if ((quotAndRem[1].signum() == 0) &&
             ((resultPrecision - i >= mcPrecision)
              || (newScale - i >= diffScale)) ) {
             resultPrecision -= i;
             newScale -= i;
             if (i < lastPow) {
                 i++;
             }
             strippedBI = quotAndRem[0];
         } else {
             if (i == 1) {
                 break;
             }
             i = 1;
         }
     }
     // To check if the result fit in 'mc.precision()' digits
     if (resultPrecision > mcPrecision) {
         throw new ArithmeticException("Division impossible");
     }
     integralValue._scale = toIntScale(newScale);
     integralValue.setUnscaledValue(strippedBI);
     return integralValue;
 }
Пример #10
0
 public BigDecimal add(BigDecimal augend, MathContext mc)
 {
     BigDecimal larger; // operand with the largest unscaled value
     BigDecimal smaller; // operand with the smallest unscaled value
     BigInteger tempBI;
     long diffScale = (long)this._scale - augend._scale;
     int largerSignum;
     // Some operand is zero or the precision is infinity
     if ((augend.isZero()) || (this.isZero())
         || (mc.getPrecision() == 0)) {
         return add(augend).round(mc);
     }
     // Cases where there is room for optimizations
     if (this.aproxPrecision() < diffScale - 1) {
         larger = augend;
         smaller = this;
     } else if (augend.aproxPrecision() < -diffScale - 1) {
         larger = this;
         smaller = augend;
     } else {// No optimization is done
         return add(augend).round(mc);
     }
     if (mc.getPrecision() >= larger.aproxPrecision()) {
         // No optimization is done
         return add(augend).round(mc);
     }
     // Cases where it's unnecessary to add two numbers with very different scales
     largerSignum = larger.signum();
     if (largerSignum == smaller.signum()) {
         tempBI = Multiplication.multiplyByPositiveInt(larger.getUnscaledValue(),10)
             .add(BigInteger.valueOf(largerSignum));
     } else {
         tempBI = larger.getUnscaledValue().subtract(
             BigInteger.valueOf(largerSignum));
         tempBI = Multiplication.multiplyByPositiveInt(tempBI,10)
             .add(BigInteger.valueOf(largerSignum * 9));
     }
     // Rounding the improved adding
     larger = new BigDecimal(tempBI, larger._scale + 1);
     return larger.round(mc);
 }
Пример #11
0
 public BigDecimal divide(BigDecimal divisor, MathContext mc)
 {
     /* Calculating how many zeros must be append to 'dividend'
      * to obtain a  quotient with at least 'mc.precision()' digits */
     long traillingZeros = mc.getPrecision() + 2L
         + divisor.aproxPrecision() - aproxPrecision();
     long diffScale = (long)_scale - divisor._scale;
     long newScale = diffScale; // scale of the final quotient
     int compRem; // to compare the remainder
     int i = 1; // index
     int lastPow = TEN_POW.Length - 1; // last power of ten
     BigInteger integerQuot; // for temporal results
     BigInteger[] quotAndRem = {getUnscaledValue()};
     // In special cases it reduces the problem to call the dual method
     if ((mc.getPrecision() == 0) || (this.isZero())
         || (divisor.isZero())) {
         return this.divide(divisor);
     }
     if (traillingZeros > 0) {
         // To append trailing zeros at end of dividend
         quotAndRem[0] = getUnscaledValue().multiply( Multiplication.powerOf10(traillingZeros) );
         newScale += traillingZeros;
     }
     quotAndRem = quotAndRem[0].divideAndRemainder( divisor.getUnscaledValue() );
     integerQuot = quotAndRem[0];
     // Calculating the exact quotient with at least 'mc.precision()' digits
     if (quotAndRem[1].signum() != 0) {
         // Checking if:   2 * remainder >= divisor ?
         compRem = quotAndRem[1].shiftLeftOneBit().compareTo( divisor.getUnscaledValue() );
         // quot := quot * 10 + r;     with 'r' in {-6,-5,-4, 0,+4,+5,+6}
         integerQuot = integerQuot.multiply(BigInteger.TEN)
             .add(BigInteger.valueOf(quotAndRem[0].signum() * (5 + compRem)));
         newScale++;
     } else {
         // To strip trailing zeros until the preferred scale is reached
         while (!integerQuot.testBit(0)) {
             quotAndRem = integerQuot.divideAndRemainder(TEN_POW[i]);
             if ((quotAndRem[1].signum() == 0)
                 && (newScale - i >= diffScale)) {
                 newScale -= i;
                 if (i < lastPow) {
                     i++;
                 }
                 integerQuot = quotAndRem[0];
             } else {
                 if (i == 1) {
                     break;
                 }
                 i = 1;
             }
         }
     }
     // To perform rounding
     return new BigDecimal(integerQuot, toIntScale(newScale), mc);
 }
Пример #12
0
 public BigDecimal abs(MathContext mc)
 {
     return round(mc).abs();
 }
Пример #13
0
 public BigDecimal(long val, MathContext mc)
     : this(val)
 {
     inplaceRound(mc);
 }
Пример #14
0
 public BigDecimal(int val, MathContext mc)
     : this(val,0)
 {
     inplaceRound(mc);
 }
Пример #15
0
 public BigDecimal plus(MathContext set)
 {
     // This clones and forces the result to the new settings
     // May return same object
     if (set.lostDigits)
         checkdigits((BigDecimal)null,set.digits);
     // Optimization: returns same object for some common cases
     if (set.form==MathContext.PLAIN)
         if (this.form==MathContext.PLAIN)
             {
                 if (this.mant.Length<=set.digits)
                     return this;
                 if (set.digits==0)
                     return this;
             }
     return clone(this).finish(set,false);
 }
Пример #16
0
        public BigDecimal multiply(BigDecimal multiplicand, MathContext mc)
        {
            BigDecimal result = multiply(multiplicand);

            result.inplaceRound(mc);
            return result;
        }
Пример #17
0
        public BigDecimal pow(BigDecimal rhs,MathContext set)
        {
            int n;
            BigDecimal lhs;
            int reqdig;
            int workdigits=0;
            int L=0;
            MathContext workset;
            BigDecimal res;
            bool seenbit;
            int i=0;
            if (set.lostDigits)
                checkdigits(rhs,set.digits);
            n=rhs.intcheck(MinArg,MaxArg); // check RHS by the rules
            lhs=this; // clarified name

            reqdig=set.digits; // local copy (heavily used)
            if (reqdig==0)
                {
                    if (rhs.ind==isneg)
                        throw new System.ArithmeticException("Negative power:"+" "+rhs.ToString());
                    workdigits=0;
                }
            else
                {/* non-0 digits */
                    if ((rhs.mant.Length+rhs.exp)>reqdig)
                        throw new System.ArithmeticException("Too many digits:"+" "+rhs.ToString());

                    /* Round the lhs to DIGITS if need be */
                    if (lhs.mant.Length>reqdig)
                        lhs=clone(lhs).round(set);

                    /* L for precision calculation [see ANSI X3.274-1996] */
                    L=rhs.mant.Length+rhs.exp; // length without decimal zeros/exp
                    workdigits=(reqdig+L)+1; // calculate the working DIGITS
                }

            workset=new MathContext(workdigits,set.form,false,set.roundingMode);

            res=ONE; // accumulator
            if (n==0)
                return res; // x**0 == 1
            if (n<0)
                n=(int)-n; // [rhs.ind records the sign]
            seenbit=false; // set once we've seen a 1-bit
            for(i=1;;i++){ // for each bit [top bit ignored]
                    n=n+n; // shift left 1 bit
                    if (n<0)
                        { // top bit is set
                            seenbit=true; // OK, we're off
                            res=res.multiply(lhs,workset); // acc=acc*x
                        }
                    if (i==31)
                        break; // that was the last bit
                    if ((!seenbit))
                        continue; // we don't have to square 1
                    res=res.multiply(res,workset); // acc=acc*acc [square]
                }
            if (rhs.ind<0)  // was a **-n [hence digits>0]
                res=ONE.divide(res,workset); // .. so acc=1/acc
            return res.finish(set,true); // round and strip [original digits]
        }
Пример #18
0
 public BigDecimal negate(MathContext mc)
 {
     return round(mc).negate();
 }
Пример #19
0
 public BigDecimal subtract(BigDecimal rhs,MathContext set)
 {
     BigDecimal newrhs;
     if (set.lostDigits)
         checkdigits(rhs,set.digits);
     // [add will recheck .. but would report -rhs]
     /* carry out the subtraction */
     // we could fastpath -0, but it is too rare.
     newrhs=clone(rhs); // safe copy
     newrhs.ind=(sbyte)-newrhs.ind; // prepare to subtract
     return this.add(newrhs,set); // arithmetic
 }
Пример #20
0
 public BigDecimal plus(MathContext mc)
 {
     return round(mc);
 }
Пример #21
0
        private BigDecimal finish(MathContext set, bool strip)
        {
            int d=0;
            int i=0;
            int ix=0;
            sbyte[] newmant=null;
            int mag=0;
            int sig=0;
            /* Round if mantissa too long and digits requested */
            if (set.digits!=0)
                if (this.mant.Length>set.digits)
                    this.round(set);

            /* If strip requested (and standard formatting), remove
               insignificant trailing zeros. */
            if (strip)
                if (set.form!=MathContext.PLAIN)
                    {
                        d=this.mant.Length;
                        /* see if we need to drop any trailing zeros */
                        for(i=d-1;i>=1;i--){
                                if (this.mant[i]!=0)
                                    break;
                                d--;
                                exp++;
                        }
                        if (d<this.mant.Length)
                            {/* need to reduce */
                                newmant=new sbyte[d];
                                System.Array.Copy(this.mant,0,newmant,0,d);
                                this.mant=newmant;
                            }
                    }

            form=(sbyte)MathContext.PLAIN; // preset

            /* Now check for leading- and all- zeros in mantissa */
            for(ix=this.mant.Length,i=0;ix>0;ix--,i++){
                    if (this.mant[i]!=0)
                        {
                            // non-0 result; ind will be correct
                            // remove leading zeros [e.g., after subtract]
                            if (i>0)
                                {do{
                                        newmant=new sbyte[this.mant.Length-i];
                                        System.Array.Copy(this.mant,i,newmant,0,this.mant.Length-i);
                                        this.mant=newmant;
                                    }while(false);}/*delead*/
                            // now determine form if not PLAIN
                            mag=exp+mant.Length;
                            if (mag>0)
                                { // most common path
                                    if (mag>set.digits)
                                        if (set.digits!=0)
                                            form=(sbyte)set.form;
                                    if ((mag-1)<=MaxExp)
                                        return this; // no overflow; quick return
                                }
                            else
                                if (mag<(-5))
                                    form=(sbyte)set.form;
                            /* check for overflow */
                            mag--;
                            if ((mag<MinExp)|(mag>MaxExp)) {
                                        // possible reprieve if form is engineering
                                        if (form==MathContext.ENGINEERING)
                                            {
                                                sig=mag%3; // leftover
                                                if (sig<0)
                                                    sig=3+sig; // negative exponent
                                                mag=mag-sig; // exponent to use
                                                // 1999.06.29: second test here must be MaxExp
                                                if (mag>=MinExp)
                                                    if (mag<=MaxExp)
                                                        return this;
                                            }
                                        throw new System.ArithmeticException("Exponent Overflow:"+" "+mag);
                            }
                            return this;
                        }
                }

            // Drop through to here only if mantissa is all zeros
            ind=iszero;
            {/*select*/
                if (set.form!=MathContext.PLAIN)
                    exp=0; // standard result; go to '0'
                else if (exp>0)
                    exp=0; // +ve exponent also goes to '0'
                else{
                    // a plain number with -ve exponent; preserve and check exponent
                    if (exp<MinExp)
                        throw new System.ArithmeticException("Exponent Overflow:"+" "+exp);
                }
            }
            mant=ZERO.mant; // canonical mantissa
            return this;
        }
Пример #22
0
        public BigDecimal pow(int n, MathContext mc)
        {
            // The ANSI standard X3.274-1996 algorithm
            int m = Math.Abs(n);
            int mcPrecision = mc.getPrecision();
            int elength = (int)Math.Log10(m) + 1;   // decimal digits in 'n'
            int oneBitMask; // mask of bits
            BigDecimal accum; // the single accumulator
            MathContext newPrecision = mc; // MathContext by default

            // In particular cases, it reduces the problem to call the other 'pow()'
            if ((n == 0) || ((isZero()) && (n > 0))) {
                return pow(n);
            }
            if ((m > 999999999) || ((mcPrecision == 0) && (n < 0))
                || ((mcPrecision > 0) && (elength > mcPrecision))) {
                // math.07=Invalid Operation
                throw new ArithmeticException("Invalid Operation");
            }
            if (mcPrecision > 0) {
                newPrecision = new MathContext( mcPrecision + elength + 1,
                                                mc.getRoundingMode());
            }
            // The result is calculated as if 'n' were positive
            accum = round(newPrecision);
            oneBitMask = highestOneBit(m) >> 1;

            while (oneBitMask > 0) {
                accum = accum.multiply(accum, newPrecision);
                if ((m & oneBitMask) == oneBitMask) {
                    accum = accum.multiply(this, newPrecision);
                }
                oneBitMask >>= 1;
            }
            // If 'n' is negative, the value is divided into 'ONE'
            if (n < 0) {
                accum = ONE.divide(accum, newPrecision);
            }
            // The final value is rounded to the destination precision
            accum.inplaceRound(mc);
            return accum;
        }
Пример #23
0
 public BigDecimal abs(MathContext set)
 {
     if (this.ind==isneg)
         return this.negate(set);
     return this.plus(set);
 }
Пример #24
0
 public BigDecimal min(BigDecimal rhs,MathContext set)
 {
     if ((this.CompareTo(rhs,set))<=0)
         return this.plus(set);
     else
         return rhs.plus(set);
 }
Пример #25
0
 public int CompareTo(BigDecimal rhs,MathContext set)
 {
     int thislength=0;
     int i=0;
     int ix=0;
     BigDecimal newrhs;
     // rhs=null will raise NullPointerException, as per Comparable interface
     if (set.lostDigits)
         checkdigits(rhs,set.digits);
     // [add will recheck in slowpath cases .. but would report -rhs]
     if ((this.ind==rhs.ind)&(this.exp==rhs.exp))
         {
             /* sign & exponent the same [very common] */
             thislength=this.mant.Length;
             if (thislength<rhs.mant.Length)
                 return (sbyte)-this.ind;
             if (thislength>rhs.mant.Length)
                 return this.ind;
             /* lengths are the same; we can do a straight mantissa compare
                unless maybe rounding [rounding is very unusual] */
             if ((thislength<=set.digits)|(set.digits==0))
                 {
                     for(ix=thislength,i=0;ix>0;ix--,i++){
                             if (this.mant[i]<rhs.mant[i])
                                 return (sbyte)-this.ind;
                             if (this.mant[i]>rhs.mant[i])
                                 return this.ind;
                         }
                     return 0; // identical
                 }
             /* drop through for full comparison */
         }
     else
         {
             /* More fastpaths possible */
             if (this.ind<rhs.ind)
                 return -1;
             if (this.ind>rhs.ind)
                 return 1;
         }
     /* carry out a subtract to make the comparison */
     newrhs=clone(rhs); // safe copy
     newrhs.ind=(sbyte)-newrhs.ind; // prepare to subtract
     return this.add(newrhs,set).ind; // add, and return sign of result
 }
Пример #26
0
        public BigDecimal multiply(BigDecimal rhs,MathContext set)
        {
            BigDecimal lhs;
            int padding;
            int reqdig;
            sbyte[] multer=null;
            sbyte[] multand=null;
            int multandlen;
            int acclen=0;
            BigDecimal res;
            sbyte[] acc;
            int n=0;
            int ix;
            sbyte mult=0;
            if (set.lostDigits)
                checkdigits(rhs,set.digits);
            lhs=this; // name for clarity and proxy

            /* Prepare numbers (truncate, unless unlimited precision) */
            padding=0; // trailing 0's to add
            reqdig=set.digits; // local copy
            if (reqdig>0)
                {
                    if (lhs.mant.Length>reqdig)
                        lhs=clone(lhs).round(set);
                    if (rhs.mant.Length>reqdig)
                        rhs=clone(rhs).round(set);
                    // [we could reuse the new LHS for result in this case]
                }
            else
                {/* unlimited */
                    // fixed point arithmetic will want every trailing 0; we add these
                    // after the calculation rather than before, for speed.
                    if (lhs.exp>0)
                        padding=padding+lhs.exp;
                    if (rhs.exp>0)
                        padding=padding+rhs.exp;
                }

            // For best speed, as in DMSRCN, we use the shorter number as the
            // multiplier and the longer as the multiplicand.
            // 1999.12.22: We used to special case when the result would fit in
            //             a long, but with Java 1.3 this gave no advantage.
            if (lhs.mant.Length<rhs.mant.Length)
                {
                    multer=lhs.mant;
                    multand=rhs.mant;
                }
            else
                {
                    multer=rhs.mant;
                    multand=lhs.mant;
                }

            /* Calculate how long result sbyte array will be */
            multandlen=(multer.Length+multand.Length)-1; // effective length
            // optimize for 75% of the cases where a carry is expected...
            if ((multer[0]*multand[0])>9)
                acclen=multandlen+1;
            else
                acclen=multandlen;

            /* Now the main long multiplication loop */
            res=new BigDecimal(); // where we'll build result
            acc=new sbyte[acclen]; // accumulator, all zeros
            for(ix=multer.Length,n=0;ix>0;ix--,n++){
                    mult=multer[n];
                    if (mult!=0)
                        { // [optimization]
                            // accumulate [accumulator is reusable array]
                            acc=byteaddsub(acc,acc.Length,multand,multandlen,mult,true);
                        }
                    // divide multiplicand by 10 for next digit to right
                    multandlen--; // 'virtual length'
                }

            res.ind=(sbyte)(lhs.ind*rhs.ind); // final sign
            res.exp=(lhs.exp+rhs.exp)-padding; // final exponent
            // [overflow is checked by finish]

            /* add trailing zeros to the result, if necessary */
            if (padding==0)
                res.mant=acc;
            else
                res.mant=extend(acc,acc.Length+padding); // add trailing 0s
            return res.finish(set,false);
        }
Пример #27
0
 public BigDecimal divide(BigDecimal rhs,int scale,int round)
 {
     MathContext set;
     if (scale<0)
         throw new System.ArithmeticException("Negative scale:"+" "+scale);
     set=new MathContext(0,MathContext.PLAIN,false,round); // [checks round]
     return this.dodivide('D',rhs,set,scale);
 }
Пример #28
0
 public BigDecimal negate(MathContext set)
 {
     BigDecimal res;
     if (set.lostDigits)
         checkdigits((BigDecimal)null,set.digits);
     res=clone(this); // safe copy
     res.ind=(sbyte)-res.ind;
     return res.finish(set,false);
 }
Пример #29
0
 public BigDecimal divideInteger(BigDecimal rhs,MathContext set)
 {
     // scale 0 to drop .000 when plain
     return this.dodivide('I',rhs,set,0);
 }
Пример #30
0
 public BigDecimal(BigInteger val, MathContext mc)
     : this(val)
 {
     inplaceRound(mc);
 }