/trunk/JavApi/java/math/BigDecimal.cs
C# | 3036 lines | 1445 code | 164 blank | 1427 comment | 459 complexity | e336d87ccc04bf8517a4b6b2029237be MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- /*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
- using System;
- using System.Text;
- using java = biz.ritter.javapi;
- namespace biz.ritter.javapi.math
- {
- /**
- * This class represents immutable arbitrary precision decimal numbers. Each
- * {@code BigDecimal} instance is represented with a unscaled arbitrary
- * precision mantissa (the unscaled value) and a scale. The value of the {@code
- * BigDecimal} is {@code unscaledValue} 10^(-{@code scale}).
- */
- [Serializable]
- public class BigDecimal : java.lang.Number, java.lang.Comparable<BigDecimal>, java.io.Serializable {
- /**
- * The constant zero as a {@code BigDecimal}.
- */
- public static readonly BigDecimal ZERO = new BigDecimal(0, 0);
- /**
- * The constant one as a {@code BigDecimal}.
- */
- public static readonly BigDecimal ONE = new BigDecimal(1, 0);
- /**
- * The constant ten as a {@code BigDecimal}.
- */
- public static readonly BigDecimal TEN = new BigDecimal(10, 0);
- /**
- * Rounding mode where positive values are rounded towards positive infinity
- * and negative values towards negative infinity.
- *
- * @see RoundingMode#UP
- */
- public const int ROUND_UP = 0;
- /**
- * Rounding mode where the values are rounded towards zero.
- *
- * @see RoundingMode#DOWN
- */
- public const int ROUND_DOWN = 1;
- /**
- * Rounding mode to round towards positive infinity. For positive values
- * this rounding mode behaves as {@link #ROUND_UP}, for negative values as
- * {@link #ROUND_DOWN}.
- *
- * @see RoundingMode#CEILING
- */
- public const int ROUND_CEILING = 2;
- /**
- * Rounding mode to round towards negative infinity. For positive values
- * this rounding mode behaves as {@link #ROUND_DOWN}, for negative values as
- * {@link #ROUND_UP}.
- *
- * @see RoundingMode#FLOOR
- */
- public const int ROUND_FLOOR = 3;
- /**
- * Rounding mode where values are rounded towards the nearest neighbor.
- * Ties are broken by rounding up.
- *
- * @see RoundingMode#HALF_UP
- */
- public const int ROUND_HALF_UP = 4;
- /**
- * Rounding mode where values are rounded towards the nearest neighbor.
- * Ties are broken by rounding down.
- *
- * @see RoundingMode#HALF_DOWN
- */
- public const int ROUND_HALF_DOWN = 5;
- /**
- * Rounding mode where values are rounded towards the nearest neighbor.
- * Ties are broken by rounding to the even neighbor.
- *
- * @see RoundingMode#HALF_EVEN
- */
- public const int ROUND_HALF_EVEN = 6;
- /**
- * Rounding mode where the rounding operations throws an {@code
- * ArithmeticException} for the case that rounding is necessary, i.e. for
- * the case that the value cannot be represented exactly.
- *
- * @see RoundingMode#UNNECESSARY
- */
- public const int ROUND_UNNECESSARY = 7;
- /** This is the serialVersionUID used by the sun implementation. */
- private static readonly long serialVersionUID = 6108874887143696463L;
- /** The double closer to <code>Log10(2)</code>. */
- private static readonly double LOG10_2 = 0.3010299956639812;
- /** The <code>String</code> representation is cached. */
- [NonSerialized]
- private String toStringImage = null;
- /** Cache for the hash code. */
- [NonSerialized]
- private int hashCode = 0;
- /**
- * An array with powers of five that fit in the type <code>long</code>
- * (<code>5^0,5^1,...,5^27</code>).
- */
- private static readonly BigInteger[] FIVE_POW;
- /**
- * An array with powers of ten that fit in the type <code>long</code>
- * (<code>10^0,10^1,...,10^18</code>).
- */
- private static readonly BigInteger []TEN_POW;
- /**
- * An array with powers of ten that fit in the type <code>long</code>
- * (<code>10^0,10^1,...,10^18</code>).
- */
- private static readonly long[] LONG_TEN_POW = new long[]
- { 1L,
- 10L,
- 100L,
- 1000L,
- 10000L,
- 100000L,
- 1000000L,
- 10000000L,
- 100000000L,
- 1000000000L,
- 10000000000L,
- 100000000000L,
- 1000000000000L,
- 10000000000000L,
- 100000000000000L,
- 1000000000000000L,
- 10000000000000000L,
- 100000000000000000L,
- 1000000000000000000L, };
-
-
- private static readonly long[] LONG_FIVE_POW = new long[]
- { 1L,
- 5L,
- 25L,
- 125L,
- 625L,
- 3125L,
- 15625L,
- 78125L,
- 390625L,
- 1953125L,
- 9765625L,
- 48828125L,
- 244140625L,
- 1220703125L,
- 6103515625L,
- 30517578125L,
- 152587890625L,
- 762939453125L,
- 3814697265625L,
- 19073486328125L,
- 95367431640625L,
- 476837158203125L,
- 2384185791015625L,
- 11920928955078125L,
- 59604644775390625L,
- 298023223876953125L,
- 1490116119384765625L,
- 7450580596923828125L, };
-
- private static readonly int[] LONG_FIVE_POW_BIT_LENGTH = new int[LONG_FIVE_POW.Length];
- private static readonly int[] LONG_TEN_POW_BIT_LENGTH = new int[LONG_TEN_POW.Length];
-
- private static readonly int BI_SCALED_BY_ZERO_LENGTH = 11;
- /**
- * An array with the first <code>BigInteger</code> scaled by zero.
- * (<code>[0,0],[1,0],...,[10,0]</code>).
- */
- private static readonly BigDecimal[] BI_SCALED_BY_ZERO = new BigDecimal[BI_SCALED_BY_ZERO_LENGTH];
- /**
- * An array with the zero number scaled by the first positive scales.
- * (<code>0*10^0, 0*10^1, ..., 0*10^10</code>).
- */
- private static readonly BigDecimal []ZERO_SCALED_BY = new BigDecimal[11];
- /** An array filled with characters <code>'0'</code>. */
- private static readonly char[] CH_ZEROS = new char[100];
- static BigDecimal() {
- // To fill all static arrays.
- int i = 0;
- for (; i < ZERO_SCALED_BY.Length; i++) {
- BI_SCALED_BY_ZERO[i] = new BigDecimal(i, 0);
- ZERO_SCALED_BY[i] = new BigDecimal(0, i);
- CH_ZEROS[i] = '0';
- }
-
- for (; i < CH_ZEROS.Length; i++) {
- CH_ZEROS[i] = '0';
- }
- for(int j=0; j<LONG_FIVE_POW_BIT_LENGTH.Length; j++) {
- LONG_FIVE_POW_BIT_LENGTH[j] = bitLength(LONG_FIVE_POW[j]);
- }
- for(int j=0; j<LONG_TEN_POW_BIT_LENGTH.Length; j++) {
- LONG_TEN_POW_BIT_LENGTH[j] = bitLength(LONG_TEN_POW[j]);
- }
-
- // Taking the references of useful powers.
- TEN_POW = Multiplication.bigTenPows;
- FIVE_POW = Multiplication.bigFivePows;
- }
- /**
- * The arbitrary precision integer (unscaled value) in the internal
- * representation of {@code BigDecimal}.
- */
- private BigInteger intVal;
- [NonSerialized]
- private int bitLengthJ;
- [NonSerialized]
- private long smallValue;
- /**
- * The 32-bit integer scale in the internal representation of {@code BigDecimal}.
- */
- private int scaleJ;
- /**
- * Represent the number of decimal digits in the unscaled value. This
- * precision is calculated the first time, and used in the following calls
- * of method <code>precision()</code>. Note that some call to the private
- * method <code>inplaceRound()</code> could update this field.
- *
- * @see #precision()
- * @see #inplaceRound(MathContext)
- */
- [NonSerialized]
- private int precisionJ = 0;
- private BigDecimal(long smallValue, int scale){
- this.smallValue = smallValue;
- this.scaleJ = scale;
- this.bitLengthJ = bitLength(smallValue);
- }
-
- private BigDecimal(int smallValue, int scale){
- this.smallValue = smallValue;
- this.scaleJ = scale;
- this.bitLengthJ = bitLength(smallValue);
- }
- /**
- * Constructs a new {@code BigDecimal} instance from a string representation
- * given as a character array.
- *
- * @param in
- * array of characters containing the string representation of
- * this {@code BigDecimal}.
- * @param offset
- * first index to be copied.
- * @param len
- * number of characters to be used.
- * @throws NullPointerException
- * if {@code in == null}.
- * @throws NumberFormatException
- * if {@code offset < 0} or {@code len <= 0} or {@code
- * offset+len-1 < 0} or {@code offset+len-1 >= in.length}.
- * @throws NumberFormatException
- * if in does not contain a valid string representation of a big
- * decimal.
- */
- public BigDecimal(char[] inJ, int offset, int len) {
- int begin = offset; // first index to be copied
- int last = offset + (len - 1); // last index to be copied
- String scaleString = null; // buffer for scale
- StringBuilder unscaledBuffer; // buffer for unscaled value
- long newScale; // the new scale
- if (inJ == null) {
- throw new java.lang.NullPointerException();
- }
- if ((last >= inJ.Length) || (offset < 0) || (len <= 0) || (last < 0)) {
- throw new java.lang.NumberFormatException();
- }
- unscaledBuffer = new StringBuilder(len);
- int bufLength = 0;
- // To skip a possible '+' symbol
- if ((offset <= last) && (inJ[offset] == '+')) {
- offset++;
- begin++;
- }
- int counter = 0;
- bool wasNonZero = false;
- // Accumulating all digits until a possible decimal point
- for (; (offset <= last) && (inJ[offset] != '.')
- && (inJ[offset] != 'e') && (inJ[offset] != 'E'); offset++) {
- if (!wasNonZero) {
- if (inJ[offset] == '0') {
- counter++;
- } else {
- wasNonZero = true;
- }
- }
- }
- unscaledBuffer.Append(inJ, begin, offset - begin);
- bufLength += offset - begin;
- // A decimal point was found
- if ((offset <= last) && (inJ[offset] == '.')) {
- offset++;
- // Accumulating all digits until a possible exponent
- begin = offset;
- for (; (offset <= last) && (inJ[offset] != 'e')
- && (inJ[offset] != 'E'); offset++) {
- if (!wasNonZero) {
- if (inJ[offset] == '0') {
- counter++;
- } else {
- wasNonZero = true;
- }
- }
- }
- scaleJ = offset - begin;
- bufLength +=scaleJ;
- unscaledBuffer.Append(inJ, begin, scaleJ);
- } else {
- scaleJ = 0;
- }
- // An exponent was found
- if ((offset <= last) && ((inJ[offset] == 'e') || (inJ[offset] == 'E'))) {
- offset++;
- // Checking for a possible sign of scale
- begin = offset;
- if ((offset <= last) && (inJ[offset] == '+')) {
- offset++;
- if ((offset <= last) && (inJ[offset] != '-')) {
- begin++;
- }
- }
- // Accumulating all remaining digits
- scaleString = java.lang.StringJ.valueOf(inJ, begin, last + 1 - begin).ToString();
- // Checking if the scale is defined
- newScale = (long)scaleJ - java.lang.Integer.parseInt(scaleString);
- scaleJ = (int)newScale;
- if (newScale != scaleJ) {
- // math.02=Scale out of range.
- throw new java.lang.NumberFormatException("Scale out of range."); //$NON-NLS-1$
- }
- }
- // Parsing the unscaled value
- if (bufLength < 19) {
- smallValue = java.lang.Long.parseLong(unscaledBuffer.toString());
- bitLengthJ = bitLength(smallValue);
- } else {
- setUnscaledValue(new BigInteger(unscaledBuffer.toString()));
- }
- precisionJ = unscaledBuffer.Length - counter;
- if (unscaledBuffer[0] == '-') {
- precisionJ --;
- }
- }
- /**
- * Constructs a new {@code BigDecimal} instance from a string representation
- * given as a character array.
- *
- * @param in
- * array of characters containing the string representation of
- * this {@code BigDecimal}.
- * @param offset
- * first index to be copied.
- * @param len
- * number of characters to be used.
- * @param mc
- * rounding mode and precision for the result of this operation.
- * @throws NullPointerException
- * if {@code in == null}.
- * @throws NumberFormatException
- * if {@code offset < 0} or {@code len <= 0} or {@code
- * offset+len-1 < 0} or {@code offset+len-1 >= in.length}.
- * @throws NumberFormatException
- * if {@code in} does not contain a valid string representation
- * of a big decimal.
- * @throws ArithmeticException
- * if {@code mc.precision > 0} and {@code mc.roundingMode ==
- * UNNECESSARY} and the new big decimal cannot be represented
- * within the given precision without rounding.
- */
- public BigDecimal(char[] inJ, int offset, int len, MathContext mc) :this(inJ, offset, len){
- inplaceRound(mc);
- }
- /**
- * Constructs a new {@code BigDecimal} instance from a string representation
- * given as a character array.
- *
- * @param in
- * array of characters containing the string representation of
- * this {@code BigDecimal}.
- * @throws NullPointerException
- * if {@code in == null}.
- * @throws NumberFormatException
- * if {@code in} does not contain a valid string representation
- * of a big decimal.
- */
- public BigDecimal(char[] inJ) :this(inJ, 0, inJ.Length){
- }
- /**
- * Constructs a new {@code BigDecimal} instance from a string representation
- * given as a character array. The result is rounded according to the
- * specified math context.
- *
- * @param in
- * array of characters containing the string representation of
- * this {@code BigDecimal}.
- * @param mc
- * rounding mode and precision for the result of this operation.
- * @throws NullPointerException
- * if {@code in == null}.
- * @throws NumberFormatException
- * if {@code in} does not contain a valid string representation
- * of a big decimal.
- * @throws ArithmeticException
- * if {@code mc.precision > 0} and {@code mc.roundingMode ==
- * UNNECESSARY} and the new big decimal cannot be represented
- * within the given precision without rounding.
- */
- public BigDecimal(char[] inJ, MathContext mc) :this(inJ, 0, inJ.Length){
- inplaceRound(mc);
- }
- /**
- * Constructs a new {@code BigDecimal} instance from a string
- * representation.
- *
- * @param val
- * string containing the string representation of this {@code
- * BigDecimal}.
- * @throws NumberFormatException
- * if {@code val} does not contain a valid string representation
- * of a big decimal.
- */
- public BigDecimal(String val) :this(val.toCharArray(), 0, val.length()){
- }
- /**
- * Constructs a new {@code BigDecimal} instance from a string
- * representation. The result is rounded according to the specified math
- * context.
- *
- * @param val
- * string containing the string representation of this {@code
- * BigDecimal}.
- * @param mc
- * rounding mode and precision for the result of this operation.
- * @throws NumberFormatException
- * if {@code val} does not contain a valid string representation
- * of a big decimal.
- * @throws ArithmeticException
- * if {@code mc.precision > 0} and {@code mc.roundingMode ==
- * UNNECESSARY} and the new big decimal cannot be represented
- * within the given precision without rounding.
- */
- public BigDecimal(String val, MathContext mc) :this(val.toCharArray(), 0, val.length()){
- inplaceRound(mc);
- }
- /**
- * Constructs a new {@code BigDecimal} instance from the 64bit double
- * {@code val}. The constructed big decimal is equivalent to the given
- * double. For example, {@code new BigDecimal(0.1)} is equal to {@code
- * 0.1000000000000000055511151231257827021181583404541015625}. This happens
- * as {@code 0.1} cannot be represented exactly in binary.
- * <p>
- * To generate a big decimal instance which is equivalent to {@code 0.1} use
- * the {@code BigDecimal(String)} constructor.
- *
- * @param val
- * double value to be converted to a {@code BigDecimal} instance.
- * @throws NumberFormatException
- * if {@code val} is infinity or not a number.
- */
- public BigDecimal(double val) {
- if (java.lang.Double.isInfinite(val) || java.lang.Double.isNaN(val)) {
- // math.03=Infinity or NaN
- throw new java.lang.NumberFormatException("Infinity or NaN"); //$NON-NLS-1$
- }
- long bits = java.lang.Double.doubleToLongBits(val); // IEEE-754
- long mantisa;
- int trailingZeros;
- // Extracting the exponent, note that the bias is 1023
- scaleJ = 1075 - (int)((bits >> 52) & 0x7FFL);
- // Extracting the 52 bits of the mantisa.
- mantisa = (scaleJ == 1075) ? (bits & 0xFFFFFFFFFFFFFL) << 1
- : (bits & 0xFFFFFFFFFFFFFL) | 0x10000000000000L;
- if (mantisa == 0) {
- scaleJ = 0;
- precisionJ = 1;
- }
- // To simplify all factors '2' in the mantisa
- if (scaleJ > 0) {
- trailingZeros = java.lang.Math.min(scaleJ, java.lang.Long.numberOfTrailingZeros(mantisa));
- mantisa= java.dotnet.lang.Operator.shiftRightUnsignet(mantisa, trailingZeros);
- scaleJ -= trailingZeros;
- }
- // Calculating the new unscaled value and the new scale
- if((bits >> 63) != 0) {
- mantisa = -mantisa;
- }
- int mantisaBits = bitLength(mantisa);
- if (scaleJ < 0) {
- bitLengthJ = mantisaBits == 0 ? 0 : mantisaBits - scaleJ;
- if(bitLengthJ < 64) {
- smallValue = mantisa << (-scaleJ);
- } else {
- intVal = BigInteger.valueOf(mantisa).shiftLeft(-scaleJ);
- }
- scaleJ = 0;
- } else if (scaleJ > 0) {
- // m * 2^e = (m * 5^(-e)) * 10^e
- if(scaleJ < LONG_FIVE_POW.Length
- && mantisaBits+LONG_FIVE_POW_BIT_LENGTH[scaleJ] < 64) {
- smallValue = mantisa * LONG_FIVE_POW[scaleJ];
- bitLengthJ = bitLength(smallValue);
- } else {
- setUnscaledValue(Multiplication.multiplyByFivePow(BigInteger.valueOf(mantisa), scaleJ));
- }
- } else { // scale == 0
- smallValue = mantisa;
- bitLengthJ = mantisaBits;
- }
- }
- /**
- * Constructs a new {@code BigDecimal} instance from the 64bit double
- * {@code val}. The constructed big decimal is equivalent to the given
- * double. For example, {@code new BigDecimal(0.1)} is equal to {@code
- * 0.1000000000000000055511151231257827021181583404541015625}. This happens
- * as {@code 0.1} cannot be represented exactly in binary.
- * <p>
- * To generate a big decimal instance which is equivalent to {@code 0.1} use
- * the {@code BigDecimal(String)} constructor.
- *
- * @param val
- * double value to be converted to a {@code BigDecimal} instance.
- * @param mc
- * rounding mode and precision for the result of this operation.
- * @throws NumberFormatException
- * if {@code val} is infinity or not a number.
- * @throws ArithmeticException
- * if {@code mc.precision > 0} and {@code mc.roundingMode ==
- * UNNECESSARY} and the new big decimal cannot be represented
- * within the given precision without rounding.
- */
- public BigDecimal(double val, MathContext mc) :this(val){
- inplaceRound(mc);
- }
- /**
- * Constructs a new {@code BigDecimal} instance from the given big integer
- * {@code val}. The scale of the result is {@code 0}.
- *
- * @param val
- * {@code BigInteger} value to be converted to a {@code
- * BigDecimal} instance.
- */
- public BigDecimal(BigInteger val):this(val, 0){
- }
- /**
- * Constructs a new {@code BigDecimal} instance from the given big integer
- * {@code val}. The scale of the result is {@code 0}.
- *
- * @param val
- * {@code BigInteger} value to be converted to a {@code
- * BigDecimal} instance.
- * @param mc
- * rounding mode and precision for the result of this operation.
- * @throws ArithmeticException
- * if {@code mc.precision > 0} and {@code mc.roundingMode ==
- * UNNECESSARY} and the new big decimal cannot be represented
- * within the given precision without rounding.
- */
- public BigDecimal(BigInteger val, MathContext mc) :this(val){
- inplaceRound(mc);
- }
- /**
- * Constructs a new {@code BigDecimal} instance from a given unscaled value
- * {@code unscaledVal} and a given scale. The value of this instance is
- * {@code unscaledVal} 10^(-{@code scale}).
- *
- * @param unscaledVal
- * {@code BigInteger} representing the unscaled value of this
- * {@code BigDecimal} instance.
- * @param scale
- * scale of this {@code BigDecimal} instance.
- * @throws NullPointerException
- * if {@code unscaledVal == null}.
- */
- public BigDecimal(BigInteger unscaledVal, int scale) {
- if (unscaledVal == null) {
- throw new java.lang.NullPointerException();
- }
- this.scaleJ = scale;
- setUnscaledValue(unscaledVal);
- }
- /**
- * Constructs a new {@code BigDecimal} instance from a given unscaled value
- * {@code unscaledVal} and a given scale. The value of this instance is
- * {@code unscaledVal} 10^(-{@code scale}). The result is rounded according
- * to the specified math context.
- *
- * @param unscaledVal
- * {@code BigInteger} representing the unscaled value of this
- * {@code BigDecimal} instance.
- * @param scale
- * scale of this {@code BigDecimal} instance.
- * @param mc
- * rounding mode and precision for the result of this operation.
- * @throws ArithmeticException
- * if {@code mc.precision > 0} and {@code mc.roundingMode ==
- * UNNECESSARY} and the new big decimal cannot be represented
- * within the given precision without rounding.
- * @throws NullPointerException
- * if {@code unscaledVal == null}.
- */
- public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) :this(unscaledVal, scale){
- inplaceRound(mc);
- }
- /**
- * Constructs a new {@code BigDecimal} instance from the given int
- * {@code val}. The scale of the result is 0.
- *
- * @param val
- * int value to be converted to a {@code BigDecimal} instance.
- */
- public BigDecimal(int val) :this(val,0){
- }
- /**
- * Constructs a new {@code BigDecimal} instance from the given int {@code
- * val}. The scale of the result is {@code 0}. The result is rounded
- * according to the specified math context.
- *
- * @param val
- * int value to be converted to a {@code BigDecimal} instance.
- * @param mc
- * rounding mode and precision for the result of this operation.
- * @throws ArithmeticException
- * if {@code mc.precision > 0} and {@code c.roundingMode ==
- * UNNECESSARY} and the new big decimal cannot be represented
- * within the given precision without rounding.
- */
- public BigDecimal(int val, MathContext mc) :this(val,0){
- inplaceRound(mc);
- }
- /**
- * Constructs a new {@code BigDecimal} instance from the given long {@code
- * val}. The scale of the result is {@code 0}.
- *
- * @param val
- * long value to be converted to a {@code BigDecimal} instance.
- */
- public BigDecimal(long val) :this(val,0){
- }
- /**
- * Constructs a new {@code BigDecimal} instance from the given long {@code
- * val}. The scale of the result is {@code 0}. The result is rounded
- * according to the specified math context.
- *
- * @param val
- * long value to be converted to a {@code BigDecimal} instance.
- * @param mc
- * rounding mode and precision for the result of this operation.
- * @throws ArithmeticException
- * if {@code mc.precision > 0} and {@code mc.roundingMode ==
- * UNNECESSARY} and the new big decimal cannot be represented
- * within the given precision without rounding.
- */
- public BigDecimal(long val, MathContext mc) :this(val){
- inplaceRound(mc);
- }
- /* Public Methods */
- /**
- * Returns a new {@code BigDecimal} instance whose value is equal to {@code
- * unscaledVal} 10^(-{@code scale}). The scale of the result is {@code
- * scale}, and its unscaled value is {@code unscaledVal}.
- *
- * @param unscaledVal
- * unscaled value to be used to construct the new {@code
- * BigDecimal}.
- * @param scale
- * scale to be used to construct the new {@code BigDecimal}.
- * @return {@code BigDecimal} instance with the value {@code unscaledVal}*
- * 10^(-{@code unscaledVal}).
- */
- public static BigDecimal valueOf(long unscaledVal, int scale) {
- if (scale == 0) {
- return valueOf(unscaledVal);
- }
- if ((unscaledVal == 0) && (scale >= 0)
- && (scale < ZERO_SCALED_BY.Length)) {
- return ZERO_SCALED_BY[scale];
- }
- return new BigDecimal(unscaledVal, scale);
- }
- /**
- * Returns a new {@code BigDecimal} instance whose value is equal to {@code
- * unscaledVal}. The scale of the result is {@code 0}, and its unscaled
- * value is {@code unscaledVal}.
- *
- * @param unscaledVal
- * value to be converted to a {@code BigDecimal}.
- * @return {@code BigDecimal} instance with the value {@code unscaledVal}.
- */
- public static BigDecimal valueOf(long unscaledVal) {
- if ((unscaledVal >= 0) && (unscaledVal < BI_SCALED_BY_ZERO_LENGTH)) {
- return BI_SCALED_BY_ZERO[(int)unscaledVal];
- }
- return new BigDecimal(unscaledVal,0);
- }
- /**
- * Returns a new {@code BigDecimal} instance whose value is equal to {@code
- * val}. The new decimal is constructed as if the {@code BigDecimal(String)}
- * constructor is called with an argument which is equal to {@code
- * Double.toString(val)}. For example, {@code valueOf("0.1")} is converted to
- * (unscaled=1, scale=1), although the double {@code 0.1} cannot be
- * represented exactly as a double value. In contrast to that, a new {@code
- * BigDecimal(0.1)} instance has the value {@code
- * 0.1000000000000000055511151231257827021181583404541015625} with an
- * unscaled value {@code 1000000000000000055511151231257827021181583404541015625}
- * and the scale {@code 55}.
- *
- * @param val
- * double value to be converted to a {@code BigDecimal}.
- * @return {@code BigDecimal} instance with the value {@code val}.
- * @throws NumberFormatException
- * if {@code val} is infinite or {@code val} is not a number
- */
- public static BigDecimal valueOf(double val) {
- if (java.lang.Double.isInfinite(val) || java.lang.Double.isNaN(val)) {
- // math.03=Infinity or NaN
- throw new java.lang.NumberFormatException("Infinity or NaN"); //$NON-NLS-1$
- }
- return new BigDecimal(java.lang.Double.toString(val));
- }
- /**
- * Returns a new {@code BigDecimal} whose value is {@code this + augend}.
- * The scale of the result is the maximum of the scales of the two
- * arguments.
- *
- * @param augend
- * value to be added to {@code this}.
- * @return {@code this + augend}.
- * @throws NullPointerException
- * if {@code augend == null}.
- */
- public BigDecimal add(BigDecimal augend) {
- int diffScale = this.scaleJ - augend.scaleJ;
- // Fast return when some operand is zero
- if (this.isZero()) {
- if (diffScale <= 0) {
- return augend;
- }
- if (augend.isZero()) {
- return this;
- }
- } else if (augend.isZero()) {
- if (diffScale >= 0) {
- return this;
- }
- }
- // Let be: this = [u1,s1] and augend = [u2,s2]
- if (diffScale == 0) {
- // case s1 == s2: [u1 + u2 , s1]
- if (java.lang.Math.max(this.bitLengthJ, augend.bitLengthJ) + 1 < 64) {
- return valueOf(this.smallValue + augend.smallValue, this.scaleJ);
- }
- return new BigDecimal(this.getUnscaledValue().add(augend.getUnscaledValue()), this.scaleJ);
- } else if (diffScale > 0) {
- // case s1 > s2 : [(u1 + u2) * 10 ^ (s1 - s2) , s1]
- return addAndMult10(this, augend, diffScale);
- } else {// case s2 > s1 : [(u2 + u1) * 10 ^ (s2 - s1) , s2]
- return addAndMult10(augend, this, -diffScale);
- }
- }
- private static BigDecimal addAndMult10(BigDecimal thisValue,BigDecimal augend, int diffScale) {
- if(diffScale < LONG_TEN_POW.Length &&
- java.lang.Math.max(thisValue.bitLengthJ,augend.bitLengthJ+LONG_TEN_POW_BIT_LENGTH[diffScale])+1<64) {
- return valueOf(thisValue.smallValue+augend.smallValue*LONG_TEN_POW[diffScale],thisValue.scaleJ);
- }
- return new BigDecimal(thisValue.getUnscaledValue().add(
- Multiplication.multiplyByTenPow(augend.getUnscaledValue(),diffScale)), thisValue.scaleJ);
- }
-
- /**
- * Returns a new {@code BigDecimal} whose value is {@code this + augend}.
- * The result is rounded according to the passed context {@code mc}.
- *
- * @param augend
- * value to be added to {@code this}.
- * @param mc
- * rounding mode and precision for the result of this operation.
- * @return {@code this + augend}.
- * @throws NullPointerException
- * if {@code augend == null} or {@code mc == null}.
- */
- 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.scaleJ - augend.scaleJ;
- 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.scaleJ + 1);
- return larger.round(mc);
- }
- /**
- * Returns a new {@code BigDecimal} whose value is {@code this - subtrahend}.
- * The scale of the result is the maximum of the scales of the two arguments.
- *
- * @param subtrahend
- * value to be subtracted from {@code this}.
- * @return {@code this - subtrahend}.
- * @throws NullPointerException
- * if {@code subtrahend == null}.
- */
- public BigDecimal subtract(BigDecimal subtrahend) {
- int diffScale = this.scaleJ - subtrahend.scaleJ;
- // Fast return when some operand is zero
- if (this.isZero()) {
- if (diffScale <= 0) {
- return subtrahend.negate();
- }
- if (subtrahend.isZero()) {
- return this;
- }
- } else if (subtrahend.isZero()) {
- if (diffScale >= 0) {
- return this;
- }
- }
- // Let be: this = [u1,s1] and subtrahend = [u2,s2] so:
- if (diffScale == 0) {
- // case s1 = s2 : [u1 - u2 , s1]
- if (java.lang.Math.max(this.bitLengthJ, subtrahend.bitLengthJ) + 1 < 64) {
- return valueOf(this.smallValue - subtrahend.smallValue,this.scaleJ);
- }
- return new BigDecimal(this.getUnscaledValue().subtract(subtrahend.getUnscaledValue()), this.scaleJ);
- } else if (diffScale > 0) {
- // case s1 > s2 : [ u1 - u2 * 10 ^ (s1 - s2) , s1 ]
- if(diffScale < LONG_TEN_POW.Length &&
- java.lang.Math.max(this.bitLengthJ,subtrahend.bitLengthJ+LONG_TEN_POW_BIT_LENGTH[diffScale])+1<64) {
- return valueOf(this.smallValue-subtrahend.smallValue*LONG_TEN_POW[diffScale],this.scaleJ);
- }
- return new BigDecimal(this.getUnscaledValue().subtract(
- Multiplication.multiplyByTenPow(subtrahend.getUnscaledValue(),diffScale)), this.scaleJ);
- } else {// case s2 > s1 : [ u1 * 10 ^ (s2 - s1) - u2 , s2 ]
- diffScale = -diffScale;
- if(diffScale < LONG_TEN_POW.Length &&
- java.lang.Math.max(this.bitLengthJ+LONG_TEN_POW_BIT_LENGTH[diffScale],subtrahend.bitLengthJ)+1<64) {
- return valueOf(this.smallValue*LONG_TEN_POW[diffScale]-subtrahend.smallValue,subtrahend.scaleJ);
- }
- return new BigDecimal(Multiplication.multiplyByTenPow(this.getUnscaledValue(),diffScale)
- .subtract(subtrahend.getUnscaledValue()), subtrahend.scaleJ);
- }
- }
- /**
- * Returns a new {@code BigDecimal} whose value is {@code this - subtrahend}.
- * The result is rounded according to the passed context {@code mc}.
- *
- * @param subtrahend
- * value to be subtracted from {@code this}.
- * @param mc
- * rounding mode and precision for the result of this operation.
- * @return {@code this - subtrahend}.
- * @throws NullPointerException
- * if {@code subtrahend == null} or {@code mc == null}.
- */
- public BigDecimal subtract(BigDecimal subtrahend, MathContext mc) {
- long diffScale = subtrahend.scaleJ - (long)this.scaleJ;
- 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.scaleJ + 1);
- return leftOperand.round(mc);
- }
- }
- // No optimization is done
- return subtract(subtrahend).round(mc);
- }
- /**
- * Returns a new {@code BigDecimal} whose value is {@code this *
- * multiplicand}. The scale of the result is the sum of the scales of the
- * two arguments.
- *
- * @param multiplicand
- * value to be multiplied with {@code this}.
- * @return {@code this * multiplicand}.
- * @throws NullPointerException
- * if {@code multiplicand == null}.
- */
- public BigDecimal multiply(BigDecimal multiplicand) {
- long newScale = (long)this.scaleJ + multiplicand.scaleJ;
- if ((this.isZero()) || (multiplicand.isZero())) {
- return zeroScaledBy(newScale);
- }
- /* Let be: this = [u1,s1] and multiplicand = [u2,s2] so:
- * this x multiplicand = [ s1 * s2 , s1 + s2 ] */
- if(this.bitLengthJ + multiplicand.bitLengthJ < 64) {
- return valueOf(this.smallValue*multiplicand.smallValue,toIntScale(newScale));
- }
- return new BigDecimal(this.getUnscaledValue().multiply(
- multiplicand.getUnscaledValue()), toIntScale(newScale));
- }
- /**
- * Returns a new {@code BigDecimal} whose value is {@code this *
- * multiplicand}. The result is rounded according to the passed context
- * {@code mc}.
- *
- * @param multiplicand
- * value to be multiplied with {@code this}.
- * @param mc
- * rounding mode and precision for the result of this operation.
- * @return {@code this * multiplicand}.
- * @throws NullPointerException
- * if {@code multiplicand == null} or {@code mc == null}.
- */
- public BigDecimal multiply(BigDecimal multiplicand, MathContext mc) {
- BigDecimal result = multiply(multiplicand);
- result.inplaceRound(mc);
- return result;
- }
- /**
- * Returns a new {@code BigDecimal} whose value is {@code this / divisor}.
- * As scale of the result the parameter {@code scale} is used. If rounding
- * is required to meet the specified scale, then the specified rounding mode
- * {@code roundingMode} is applied.
- *
- * @param divisor
- * value by which {@code this} is divided.
- * @param scale
- * the scale of the result returned.
- * @param roundingMode
- * rounding mode to be used to round the result.
- * @return {@code this / divisor} rounded according to the given rounding
- * mode.
- * @throws NullPointerException
- * if {@code divisor == null}.
- * @throws IllegalArgumentException
- * if {@code roundingMode} is not a valid rounding mode.
- * @throws ArithmeticException
- * if {@code divisor == 0}.
- * @throws ArithmeticException
- * if {@code roundingMode == ROUND_UNNECESSARY} and rounding is
- * necessary according to the given scale.
- */
- public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) {
- return divide(divisor, scale, RoundingMode.valueOf(roundingMode));
- }
- /**
- * Returns a new {@code BigDecimal} whose value is {@code this / divisor}.
- * As scale of the result the parameter {@code scale} is used. If rounding
- * is required to meet the specified scale, then the specified rounding mode
- * {@code roundingMode} is applied.
- *
- * @param divisor
- * value by which {@code this} is divided.
- * @param scale
- * the scale of the result returned.
- * @param roundingMode
- * rounding mode to be used to round the result.
- * @return {@code this / divisor} rounded according to the given rounding
- * mode.
- * @throws NullPointerException
- * if {@code divisor == null} or {@code roundingMode == null}.
- * @throws ArithmeticException
- * if {@code divisor == 0}.
- * @throws ArithmeticException
- * if {@code roundingMode == RoundingMode.UNNECESSAR}Y and
- * rounding is necessary according to the given scale and given
- * precision.
- */
- public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode) {
- // Let be: this = [u1,s1] and divisor = [u2,s2]
- if (roundingMode == null) {
- throw new java.lang.NullPointerException();
- }
- if (divisor.isZero()) {
- // math.04=Division by zero
- throw new java.lang.ArithmeticException("Division by zero"); //$NON-NLS-1$
- }
-
- long diffScale = ((long)this.scaleJ - divisor.scaleJ) - scale;
- if(this.bitLengthJ < 64 && divisor.bitLengthJ < 64 ) {
- if(diffScale == 0) {
- return dividePrimitiveLongs(this.smallValue,
- divisor.smallValue,
- scale,
- roundingMode );
- } else if(diffScale > 0) {
- if(diffScale < LONG_TEN_POW.Length &&
- divisor.bitLengthJ + LONG_TEN_POW_BIT_LENGTH[(int)diffScale] < 64) {
- return dividePrimitiveLongs(this.smallValue,
- divisor.smallValue*LONG_TEN_POW[(int)diffScale],
- scale,
- roundingMode);
- }
- } else { // diffScale < 0
- if(-diffScale < LONG_TEN_POW.Length &&
- this.bitLengthJ + LONG_TEN_POW_BIT_LENGTH[(int)-diffScale] < 64) {
- return dividePrimitiveLongs(this.smallValue*LONG_TEN_POW[(int)-diffScale],
- divisor.smallValue,
- scale,
- roundingMode);
- }
-
- }
- }
- BigInteger scaledDividend = this.getUnscaledValue();
- BigInteger scaledDivisor = divisor.getUnscaledValue(); // for scaling of 'u2'
-
- if (diffScale > 0) {
- // Multiply 'u2' by: 10^((s1 - s2) - scale)
- scaledDivisor = Multiplication.multiplyByTenPow(scaledDivisor, (int)diffScale);
- } else if (diffScale < 0) {
- // Multiply 'u1' by: 10^(scale - (s1 - s2))
- scaledDividend = Multiplication.multiplyByTenPow(scaledDividend, (int)-diffScale);
- }
- return divideBigIntegers(scaledDividend, scaledDivisor, scale, roundingMode);
- }
-
- private static BigDecimal divideBigIntegers(BigInteger scaledDividend, BigInteger scaledDivisor, int scale, RoundingMode roundingMode) {
-
- BigInteger[] quotAndRem = scaledDividend.divideAndRemainder(scaledDivisor); // quotient and remainder
- // If after division there is a remainder...
- BigInteger quotient = quotAndRem[0];
- BigInteger remainder = quotAndRem[1];
- if (remainder.signum() == 0) {
- return new BigDecimal(quotient, scale);
- }
- int sign = scaledDividend.signum() * scaledDivisor.signum();
- int compRem; // 'compare to remainder'
- if(scaledDivisor.bitLength() < 63) { // 63 in order to avoid out of long after <<1
- long rem = remainder.longValue();
- long divisor = scaledDivisor.longValue();
- compRem = longCompareTo(java.lang.Math.abs(rem) << 1,java.lang.Math.abs(divisor));
- // To look if there is a carry
- compRem = roundingBehavior(quotient.testBit(0) ? 1 : 0,
- sign * (5 + compRem), roundingMode);
-
- } else {
- // Checking if: remainder * 2 >= scaledDivisor
- compRem = remainder.abs().shiftLeftOneBit().compareTo(scaledDivisor.abs());
- c…
Large files files are truncated, but you can click here to view the full file