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 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 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); }