public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) : this(unscaledVal, scale) { inplaceRound(mc); }
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 }
public BigDecimal divide(BigDecimal rhs,MathContext set) { return this.dodivide('D',rhs,set,-1); }
private BigDecimal round(MathContext set) { return round(set.digits,set.roundingMode); }
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); }
public BigDecimal remainder(BigDecimal rhs,MathContext set) { return this.dodivide('R',rhs,set,-1); }
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); }
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; }
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; }
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); }
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); }
public BigDecimal abs(MathContext mc) { return round(mc).abs(); }
public BigDecimal(long val, MathContext mc) : this(val) { inplaceRound(mc); }
public BigDecimal(int val, MathContext mc) : this(val,0) { inplaceRound(mc); }
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); }
public BigDecimal multiply(BigDecimal multiplicand, MathContext mc) { BigDecimal result = multiply(multiplicand); result.inplaceRound(mc); return result; }
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] }
public BigDecimal negate(MathContext mc) { return round(mc).negate(); }
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 }
public BigDecimal plus(MathContext mc) { return round(mc); }
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; }
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; }
public BigDecimal abs(MathContext set) { if (this.ind==isneg) return this.negate(set); return this.plus(set); }
public BigDecimal min(BigDecimal rhs,MathContext set) { if ((this.CompareTo(rhs,set))<=0) return this.plus(set); else return rhs.plus(set); }
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 }
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); }
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); }
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); }
public BigDecimal divideInteger(BigDecimal rhs,MathContext set) { // scale 0 to drop .000 when plain return this.dodivide('I',rhs,set,0); }
public BigDecimal(BigInteger val, MathContext mc) : this(val) { inplaceRound(mc); }