예제 #1
0
파일: BigDecimal.cs 프로젝트: vic/ioke
        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)));
        }
예제 #2
0
파일: BigDecimal.cs 프로젝트: vic/ioke
 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);
 }
예제 #3
0
파일: BigDecimal.cs 프로젝트: vic/ioke
 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);
 }
예제 #4
0
파일: BigDecimal.cs 프로젝트: vic/ioke
        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;
            }
        }
예제 #5
0
파일: BigDecimal.cs 프로젝트: vic/ioke
 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);
 }