📄 floatmul.java
字号:
* Rescale dividend or divisor (whichever can be "upscaled" to * produce correctly scaled quotient). * Take care to detect out-of-range scales */ BigDecimal dividend; if (checkScale((long)scale + divisor.scale) >= this.scale) { dividend = this.setScale(scale + divisor.scale); } else { dividend = this; divisor = divisor.setScale(checkScale((long)this.scale - scale)); } boolean compact = dividend.intCompact != INFLATED && divisor.intCompact != INFLATED; long div = INFLATED; long rem = INFLATED;; BigInteger q=null, r=null; if (compact) { div = dividend.intCompact / divisor.intCompact; rem = dividend.intCompact % divisor.intCompact; } else { // Do the division and return result if it's exact. BigInteger i[] = dividend.inflate().intVal.divideAndRemainder(divisor.inflate().intVal); q = i[0]; r = i[1]; } // Check for exact result if (compact) { if (rem == 0) return new BigDecimal(div, scale); } else { if (r.signum() == 0) return new BigDecimal(q, scale); } if (roundingMode == ROUND_UNNECESSARY) // Rounding prohibited throw new ArithmeticException("Rounding necessary"); /* Round as appropriate */ int signum = dividend.signum() * divisor.signum(); // Sign of result boolean increment; if (roundingMode == ROUND_UP) { // Away from zero increment = true; } else if (roundingMode == ROUND_DOWN) { // Towards zero increment = false; } else if (roundingMode == ROUND_CEILING) { // Towards +infinity increment = (signum > 0); } else if (roundingMode == ROUND_FLOOR) { // Towards -infinity increment = (signum < 0); } else { // Remaining modes based on nearest-neighbor determination int cmpFracHalf; if (compact) { cmpFracHalf = longCompareTo(Math.abs(2*rem), Math.abs(divisor.intCompact)); } else { // add(r) here is faster than multiply(2) or shiftLeft(1) cmpFracHalf= r.add(r).abs().compareTo(divisor.intVal.abs()); } if (cmpFracHalf < 0) { // We're closer to higher digit increment = false; } else if (cmpFracHalf > 0) { // We're closer to lower digit increment = true; } else { // We're dead-center if (roundingMode == ROUND_HALF_UP) increment = true; else if (roundingMode == ROUND_HALF_DOWN) increment = false; else { // roundingMode == ROUND_HALF_EVEN if (compact) increment = (div & 1L) != 0L; else increment = q.testBit(0); // true iff q is odd } } } if (compact) { if (increment) div += signum; // guaranteed not to overflow return new BigDecimal(div, scale); } else { return (increment ? new BigDecimal(q.add(BigInteger.valueOf(signum)), scale) : new BigDecimal(q, scale)); } } /** * Returns a <tt>BigDecimal</tt> whose value is <tt>(this / * divisor)</tt>, and whose scale is as specified. If rounding must * be performed to generate a result with the specified scale, the * specified rounding mode is applied. * * @param divisor value by which this <tt>BigDecimal</tt> is to be divided. * @param scale scale of the <tt>BigDecimal</tt> quotient to be returned. * @param roundingMode rounding mode to apply. * @return <tt>this / divisor</tt> * @throws ArithmeticException if <tt>divisor</tt> is zero, * <tt>roundingMode==RoundingMode.UNNECESSARY</tt> and * the specified scale is insufficient to represent the result * of the division exactly. * @since 1.5 */ public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode) { return divide(divisor, scale, roundingMode.oldMode); } /** * Returns a <tt>BigDecimal</tt> whose value is <tt>(this / * divisor)</tt>, and whose scale is <tt>this.scale()</tt>. If * rounding must be performed to generate a result with the given * scale, the specified rounding mode is applied. * * <p>The new {@link #divide(BigDecimal, RoundingMode)} method * should be used in preference to this legacy method. * * @param divisor value by which this <tt>BigDecimal</tt> is to be divided. * @param roundingMode rounding mode to apply. * @return <tt>this / divisor</tt> * @throws ArithmeticException if <tt>divisor==0</tt>, or * <tt>roundingMode==ROUND_UNNECESSARY</tt> and * <tt>this.scale()</tt> is insufficient to represent the result * of the division exactly. * @throws IllegalArgumentException if <tt>roundingMode</tt> does not * represent a valid rounding mode. * @see #ROUND_UP * @see #ROUND_DOWN * @see #ROUND_CEILING * @see #ROUND_FLOOR * @see #ROUND_HALF_UP * @see #ROUND_HALF_DOWN * @see #ROUND_HALF_EVEN * @see #ROUND_UNNECESSARY */ public BigDecimal divide(BigDecimal divisor, int roundingMode) { return this.divide(divisor, scale, roundingMode); } /** * Returns a <tt>BigDecimal</tt> whose value is <tt>(this / * divisor)</tt>, and whose scale is <tt>this.scale()</tt>. If * rounding must be performed to generate a result with the given * scale, the specified rounding mode is applied. * * @param divisor value by which this <tt>BigDecimal</tt> is to be divided. * @param roundingMode rounding mode to apply. * @return <tt>this / divisor</tt> * @throws ArithmeticException if <tt>divisor==0</tt>, or * <tt>roundingMode==RoundingMode.UNNECESSARY</tt> and * <tt>this.scale()</tt> is insufficient to represent the result * of the division exactly. * @since 1.5 */ public BigDecimal divide(BigDecimal divisor, RoundingMode roundingMode) { return this.divide(divisor, scale, roundingMode.oldMode); } /** * Returns a <tt>BigDecimal</tt> whose value is <tt>(this / * divisor)</tt>, and whose preferred scale is <tt>(this.scale() - * divisor.scale())</tt>; if the exact quotient cannot be * represented (because it has a non-terminating decimal * expansion) an <tt>ArithmeticException</tt> is thrown. * * @param divisor value by which this <tt>BigDecimal</tt> is to be divided. * @throws ArithmeticException if the exact quotient does not have a * terminating decimal expansion * @return <tt>this / divisor</tt> * @since 1.5 * @author Joseph D. Darcy */ public BigDecimal divide(BigDecimal divisor) { /* * Handle zero cases first. */ if (divisor.signum() == 0) { // x/0 if (this.signum() == 0) // 0/0 throw new ArithmeticException("Division undefined"); // NaN throw new ArithmeticException("Division by zero"); } // Calculate preferred scale int preferredScale = (int)Math.max(Math.min((long)this.scale() - divisor.scale(), Integer.MAX_VALUE), Integer.MIN_VALUE); if (this.signum() == 0) // 0/y return new BigDecimal(0, preferredScale); else { this.inflate(); divisor.inflate(); /* * If the quotient this/divisor has a terminating decimal * expansion, the expansion can have no more than * (a.precision() + ceil(10*b.precision)/3) digits. * Therefore, create a MathContext object with this * precision and do a divide with the UNNECESSARY rounding * mode. */ MathContext mc = new MathContext( (int)Math.min(this.precision() + (long)Math.ceil(10.0*divisor.precision()/3.0), Integer.MAX_VALUE), RoundingMode.UNNECESSARY); BigDecimal quotient; try { quotient = this.divide(divisor, mc); } catch (ArithmeticException e) { throw new ArithmeticException("Non-terminating decimal expansion; " + "no exact representable decimal result."); } int quotientScale = quotient.scale(); // divide(BigDecimal, mc) tries to adjust the quotient to // the desired one by removing trailing zeros; since the // exact divide method does not have an explicit digit // limit, we can add zeros too. if (preferredScale > quotientScale) return quotient.setScale(preferredScale); return quotient; } } /** * Returns a <tt>BigDecimal</tt> whose value is <tt>(this / * divisor)</tt>, with rounding according to the context settings. * * @param divisor value by which this <tt>BigDecimal</tt> is to be divided. * @param mc the context to use. * @return <tt>this / divisor</tt>, rounded as necessary. * @throws ArithmeticException if the result is inexact but the * rounding mode is <tt>UNNECESSARY</tt> or * <tt>mc.precision == 0</tt> and the quotient has a * non-terminating decimal expansion. * @since 1.5 */ public BigDecimal divide(BigDecimal divisor, MathContext mc) { if (mc.precision == 0) return divide(divisor); BigDecimal lhs = this.inflate(); // left-hand-side BigDecimal rhs = divisor.inflate(); // right-hand-side BigDecimal result; // work long preferredScale = (long)lhs.scale() - rhs.scale(); // Now calculate the answer. We use the existing // divide-and-round method, but as this rounds to scale we have // to normalize the values here to achieve the desired result. // For x/y we first handle y=0 and x=0, and then normalize x and // y to give x' and y' with the following constraints: // (a) 0.1 <= x' < 1 // (b) x' <= y' < 10*x' // Dividing x'/y' with the required scale set to mc.precision then // will give a result in the range 0.1 to 1 rounded to exactly // the right number of digits (except in the case of a result of // 1.000... which can arise when x=y, or when rounding overflows // The 1.000... case will reduce properly to 1. if (rhs.signum() == 0) { // x/0 if (lhs.signum() == 0) // 0/0 throw new ArithmeticException("Division undefined"); // NaN throw new ArithmeticException("Division by zero"); } if (lhs.signum() == 0) // 0/y return new BigDecimal(BigInteger.ZERO, (int)Math.max(Math.min(preferredScale, Integer.MAX_VALUE), Integer.MIN_VALUE)); BigDecimal xprime = new BigDecimal(lhs.intVal.abs(), lhs.precision()); BigDecimal yprime = new BigDecimal(rhs.intVal.abs(), rhs.precision()); // xprime and yprime are now both in range 0.1 through 0.999... if (mc.roundingMode == RoundingMode.CEILING || mc.roundingMode == RoundingMode.FLOOR) { // The floor (round toward negative infinity) and ceil // (round toward positive infinity) rounding modes are not // invariant under a sign flip. If xprime/yprime has a // different sign than lhs/rhs, the rounding mode must be // changed. if ((xprime.signum() != lhs.signum()) ^ (yprime.signum() != rhs.signum())) { mc = new MathContext(mc.precision, (mc.roundingMode==RoundingMode.CEILING)? RoundingMode.FLOOR:RoundingMode.CEILING); } } if (xprime.compareTo(yprime) > 0) // satisfy constraint (b) yprime.scale -= 1; // [that is, yprime *= 10] result = xprime.divide(yprime, mc.precision, mc.roundingMode.oldMode); // correct the scale of the result... result.scale = checkScale((long)yprime.scale - xprime.scale - (rhs.scale - lhs.scale) + mc.precision); // apply the sign if (lhs.signum() != rhs.signum()) result = result.negate(); // doRound, here, only affects 1000000000 case. result = result.doRound(mc); if (result.multiply(divisor).compareTo(this) == 0) { // Apply preferred scale rules for exact quotients return result.stripZerosToMatchScale(preferredScale); } else { return result; } } /** * Returns a <tt>BigDecimal</tt> whose value is the integer part * of the quotient <tt>(this / divisor)</tt> rounded down. The * preferred scale of the result is <code>(this.scale() - * divisor.scale())</code>. * * @param divisor value by which this <tt>BigDecimal</tt> is to be divided. * @return The integer part of <tt>this / divisor</tt>. * @throws ArithmeticException if <tt>divisor==0</tt> * @since 1.5 */ public BigDecimal divideToIntegralValue(BigDecimal divisor) { // Calculate preferred scale int preferredScale = (int)Math.max(Math.min((long)this.scale() - divisor.scale(), Integer.MAX_VALUE), Integer.MIN_VALUE); this.inflate(); divisor.inflate(); if (this.abs().compareTo(divisor.ab
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -