public BigDecimal divideToIntegralValue(BigDecimal divisor) { BigInteger integralValue; // the integer of result BigInteger powerOfTen; // some power of ten BigInteger[] quotAndRem = {getUnscaledValue()}; long newScale = (long)this._scale - divisor._scale; long tempScale = 0; int i = 1; int lastPow = TEN_POW.Length - 1; if (divisor.isZero()) { throw new ArithmeticException("Division by zero"); } if ((divisor.aproxPrecision() + newScale > this.aproxPrecision() + 1L) || (this.isZero())) { /* If the divisor's integer part is greater than this's integer part, * the result must be zero with the appropriate scale */ integralValue = BigInteger.ZERO; } else if (newScale == 0) { integralValue = getUnscaledValue().divide( divisor.getUnscaledValue() ); } else if (newScale > 0) { powerOfTen = Multiplication.powerOf10(newScale); integralValue = getUnscaledValue().divide( divisor.getUnscaledValue().multiply(powerOfTen) ); integralValue = integralValue.multiply(powerOfTen); } else {// (newScale < 0) powerOfTen = Multiplication.powerOf10(-newScale); integralValue = getUnscaledValue().multiply(powerOfTen).divide( divisor.getUnscaledValue() ); // To strip trailing zeros approximating to the preferred scale while (!integralValue.testBit(0)) { quotAndRem = integralValue.divideAndRemainder(TEN_POW[i]); if ((quotAndRem[1].signum() == 0) && (tempScale - i >= newScale)) { tempScale -= i; if (i < lastPow) { i++; } integralValue = quotAndRem[0]; } else { if (i == 1) { break; } i = 1; } } newScale = tempScale; } return ((integralValue.signum() == 0) ? zeroScaledBy(newScale) : new BigDecimal(integralValue, toIntScale(newScale))); }
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 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 int compareTo(BigDecimal val) { int thisSign = signum(); int valueSign = val.signum(); if( thisSign == valueSign) { if(this._scale == val._scale && this._bitLength<64 && val._bitLength<64 ) { return (smallValue < val.smallValue) ? -1 : (smallValue > val.smallValue) ? 1 : 0; } long diffScale = (long)this._scale - val._scale; int diffPrecision = this.aproxPrecision() - val.aproxPrecision(); if (diffPrecision > diffScale + 1) { return thisSign; } else if (diffPrecision < diffScale - 1) { return -thisSign; } else {// thisSign == val.signum() and diffPrecision is aprox. diffScale BigInteger thisUnscaled = this.getUnscaledValue(); BigInteger valUnscaled = val.getUnscaledValue(); // If any of both precision is bigger, append zeros to the shorter one if (diffScale < 0) { thisUnscaled = thisUnscaled.multiply(Multiplication.powerOf10(-diffScale)); } else if (diffScale > 0) { valUnscaled = valUnscaled.multiply(Multiplication.powerOf10(diffScale)); } return thisUnscaled.compareTo(valUnscaled); } } else if (thisSign < valueSign) { return -1; } else { return 1; } }
public BigDecimal subtract(BigDecimal subtrahend, MathContext mc) { long diffScale = subtrahend._scale - (long)this._scale; int thisSignum; BigDecimal leftOperand; // it will be only the left operand (this) BigInteger tempBI; // Some operand is zero or the precision is infinity if ((subtrahend.isZero()) || (this.isZero()) || (mc.getPrecision() == 0)) { return subtract(subtrahend).round(mc); } // Now: this != 0 and subtrahend != 0 if (subtrahend.aproxPrecision() < diffScale - 1) { // Cases where it is unnecessary to subtract two numbers with very different scales if (mc.getPrecision() < this.aproxPrecision()) { thisSignum = this.signum(); if (thisSignum != subtrahend.signum()) { tempBI = Multiplication.multiplyByPositiveInt(this.getUnscaledValue(), 10) .add(BigInteger.valueOf(thisSignum)); } else { tempBI = this.getUnscaledValue().subtract(BigInteger.valueOf(thisSignum)); tempBI = Multiplication.multiplyByPositiveInt(tempBI, 10) .add(BigInteger.valueOf(thisSignum * 9)); } // Rounding the improved subtracting leftOperand = new BigDecimal(tempBI, this._scale + 1); return leftOperand.round(mc); } } // No optimization is done return subtract(subtrahend).round(mc); }