如果基本类型 long / double 不能满足整数和浮点数运算的 精度要求, 则可以使用 java.math 包 下的 BigInteger / BigDecimal 工具类, 实现任何精度的运算;
使用 BigInteger 实现了任意精度的整型运算
使用 BigDecimal 实现了任意精度的浮点型运算
1. 基本用法与常用方法
/*
* 以 BigInteger 为例 (BigDecimal 方法与 BigInteger 相同)
*/
public static void main(String[] args) {
// 1. 构造实例:
// 两种方法: 通过静态方法 valueOf() 和 new Instance 方法
BigInteger bi = BigInteger.valueOf(3_123_456_789L);
BigInteger bi2 = new BigInteger("2333333333333333");
// BigInteger(byte[])
// BigInteger(int[])
// BigInteger(int, byte[])
// BigInteger(int, int[])
// BigInteger(String, int)
// BigInteger(char[], int, int)
// 2. add / sub / multiply / divide / mod
// 在 BigInteger 和 BigDecimal 中, 没有算数运算符, 只能通过实例方法进行运算
// 注意: 在使用实例方法运算的时候, 如: 使用 bi.add(bi2), 不会改变 bi 和 bi2 的值;
System.out.println(bi.add(bi2));;
System.out.println(bi.subtract(bi2));
System.out.println(bi.multiply(bi2));
System.out.println(bi.divide(bi2));
System.out.println(bi.mod(bi2));
}
2. 源码分析
2.1 BigInteger 源码
/**
* Immutable arbitrary-precision (任意精度) integers. All operations behave as if
* BigIntegers were represented in two's-complement notation (like Java's
* primitive integer types). BigInteger provides analogues(类似物, 这里指的是实例方法,
* 如: add() / substract() 方法, 替代 + / - 运算符) to all of Java's
* primitive integer operators, and all relevant methods from java.lang.Math.
* Additionally, BigInteger provides operations for modular arithmetic, GCD
* calculation, primality testing, prime generation, bit manipulation,
* and a few other miscellaneous operations.
*
* @see BigDecimal
* @since JDK1.1
*/
public class BigInteger extends Number implements Comparable<BigInteger> {
/**
* The signum of this BigInteger: -1 for negative, 0 for zero, or
* 1 for positive. Note that the BigInteger zero <i>must</i> have
* a signum of 0. This is necessary to ensures that there is exactly one
* representation for each BigInteger value.
*
* @serial
*/
final int signum;
/**
* The magnitude of this BigInteger, in <i>big-endian</i> order: the
* zeroth element of this array is the most-significant int of the
* magnitude. The magnitude must be "minimal" in that the most-significant
* int ({@code mag[0]}) must be non-zero. This is necessary to
* ensure that there is exactly one representation for each BigInteger
* value. Note that this implies that the BigInteger zero has a
* zero-length mag array.
*/
final int[] mag;
/**
* Translates a byte array containing the two's-complement binary
* representation of a BigInteger into a BigInteger. The input array is
* assumed to be in <i>big-endian</i> byte-order: the most significant
* byte is in the zeroth element.
*
* @param val big-endian two's-complement binary representation of
* BigInteger.
* @throws NumberFormatException {@code val} is zero bytes long.
*/
public BigInteger(byte[] val) {
// ...
}
/**
* This private constructor translates an int array containing the
* two's-complement binary representation of a BigInteger into a
* BigInteger. The input array is assumed to be in <i>big-endian</i>
* int-order: the most significant int is in the zeroth element.
*/
private BigInteger(int[] val) {
//...
}
/**
* Translates the sign-magnitude representation of a BigInteger into a
* BigInteger. The sign is represented as an integer signum value: -1 for
* negative, 0 for zero, or 1 for positive. The magnitude is a byte array
* in <i>big-endian</i> byte-order: the most significant byte is in the
* zeroth element. A zero-length magnitude array is permissible, and will
* result in a BigInteger value of 0, whether signum is -1, 0 or 1.
*
* @param signum signum of the number (-1 for negative, 0 for zero, 1
* for positive).
* @param magnitude big-endian binary representation of the magnitude of
* the number.
* @throws NumberFormatException {@code signum} is not one of the three
* legal values (-1, 0, and 1), or {@code signum} is 0 and
* {@code magnitude} contains one or more non-zero bytes.
*/
public BigInteger(int signum, byte[] magnitude) {
//...
}
/**
* A constructor for internal use that translates the sign-magnitude
* representation of a BigInteger into a BigInteger. It checks the
* arguments and copies the magnitude so this constructor would be
* safe for external use.
*/
private BigInteger(int signum, int[] magnitude) {
// ...
}
/**
* Translates the String representation of a BigInteger in the
* specified radix into a BigInteger. The String representation
* consists of an optional minus or plus sign followed by a
* sequence of one or more digits in the specified radix. The
* character-to-digit mapping is provided by {@code
* Character.digit}. The String may not contain any extraneous
* characters (whitespace, for example).
*
* @param val String representation of BigInteger.
* @param radix radix to be used in interpreting {@code val}.
* @throws NumberFormatException {@code val} is not a valid representation
* of a BigInteger in the specified radix, or {@code radix} is
* outside the range from {@link Character#MIN_RADIX} to
* {@link Character#MAX_RADIX}, inclusive.
* @see Character#digit
*/
public BigInteger(String val, int radix) {
//...
}
/*
* Constructs a new BigInteger using a char array with radix=10.
* Sign is precalculated outside and not allowed in the val.
*/
BigInteger(char[] val, int sign, int len) {
// ...
}
2.2 BigDecimal 源码
/**
* Immutable, arbitrary-precision signed decimal numbers. A
* {@code BigDecimal} consists of an arbitrary precision integer
* <i>unscaled value</i> and a 32-bit integer <i>scale</i>. If zero
* or positive, the scale is the number of digits to the right of the
* decimal point. If negative, the unscaled value of the number is
* multiplied by ten to the power of the negation of the scale. The
* value of the number represented by the {@code BigDecimal} is
* therefore <tt>(unscaledValue × 10<sup>-scale</sup>)</tt>.
* 不可变的, 可以执行任何精度运算的, 带符号的浮点运算工具类: BigDecimal
*
* @see BigInteger
*/
public class BigDecimal extends Number implements Comparable<BigDecimal> {
/**
* The unscaled value of this BigDecimal, as returned by {@link
* #unscaledValue}.
*
* @serial
* @see #unscaledValue
*/
private final BigInteger intVal;
/**
* The scale of this BigDecimal, as returned by {@link #scale}.
*
* @serial
* @see #scale
*/
private final int scale; // Note: this may have any value, so
// calculations must be done in longs
/**
* The number of decimal digits in this BigDecimal, or 0 if the
* number of digits are not known (lookaside information). If
* nonzero, the value is guaranteed correct. Use the precision()
* method to obtain and set the value if it might be 0. This
* field is mutable until set nonzero.
*
* @since 1.5
*/
private transient int precision;
/**
* Used to store the canonical string representation, if computed.
*/
private transient String stringCache;
/**
* Trusted package private constructor.
* Trusted simply means if val is INFLATED, intVal could not be null and
* if intVal is null, val could not be INFLATED.
*/
BigDecimal(BigInteger intVal, long val, int scale, int prec) {
this.scale = scale;
this.precision = prec;
this.intCompact = val;
this.intVal = intVal;
}
/**
* Translates a character array representation of a
* {@code BigDecimal} into a {@code BigDecimal}, accepting the
* same sequence of characters as the {@link #BigDecimal(String)}
* constructor, while allowing a sub-array to be specified.
*
* <p>Note that if the sequence of characters is already available
* within a character array, using this constructor is faster than
* converting the {@code char} array to string and using the
* {@code BigDecimal(String)} constructor .
*
* @param in {@code char} array that is the source of characters.
* @param offset first character in the array to inspect.
* @param len number of characters to consider.
* @throws NumberFormatException if {@code in} is not a valid
* representation of a {@code BigDecimal} or the defined subarray
* is not wholly within {@code in}.
* @since 1.5
*/
public BigDecimal(char[] in, int offset, int len) {
this(in,offset,len,MathContext.UNLIMITED);
}
/**
* Translates a character array representation of a
* {@code BigDecimal} into a {@code BigDecimal}, accepting the
* same sequence of characters as the {@link #BigDecimal(String)}
* constructor, while allowing a sub-array to be specified and
* with rounding according to the context settings.
*
* <p>Note that if the sequence of characters is already available
* within a character array, using this constructor is faster than
* converting the {@code char} array to string and using the
* {@code BigDecimal(String)} constructor .
*
* @param in {@code char} array that is the source of characters.
* @param offset first character in the array to inspect.
* @param len number of characters to consider..
* @param mc the context to use.
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
* @throws NumberFormatException if {@code in} is not a valid
* representation of a {@code BigDecimal} or the defined subarray
* is not wholly within {@code in}.
* @since 1.5
*/
public BigDecimal(char[] in, int offset, int len, MathContext mc) {
// ...
}
/*
* parse exponent
*/
private static long parseExp(char[] in, int offset, int len){
// ....
}
/**
* Translates a character array representation of a
* {@code BigDecimal} into a {@code BigDecimal}, accepting the
* same sequence of characters as the {@link #BigDecimal(String)}
* constructor.
*
* <p>Note that if the sequence of characters is already available
* as a character array, using this constructor is faster than
* converting the {@code char} array to string and using the
* {@code BigDecimal(String)} constructor .
*
* @param in {@code char} array that is the source of characters.
* @throws NumberFormatException if {@code in} is not a valid
* representation of a {@code BigDecimal}.
* @since 1.5
*/
public BigDecimal(char[] in) {
this(in, 0, in.length);
}
/**
* Translates a character array representation of a
* {@code BigDecimal} into a {@code BigDecimal}, accepting the
* same sequence of characters as the {@link #BigDecimal(String)}
* constructor and with rounding according to the context
* settings.
*
* <p>Note that if the sequence of characters is already available
* as a character array, using this constructor is faster than
* converting the {@code char} array to string and using the
* {@code BigDecimal(String)} constructor .
*
* @param in {@code char} array that is the source of characters.
* @param mc the context to use.
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
* @throws NumberFormatException if {@code in} is not a valid
* representation of a {@code BigDecimal}.
* @since 1.5
*/
public BigDecimal(char[] in, MathContext mc) {
this(in, 0, in.length, mc);
}
/**
* Translates the string representation of a {@code BigDecimal}
* into a {@code BigDecimal}. The string representation consists
* of an optional sign, {@code '+'} (<tt> '\u002B'</tt>) or
* {@code '-'} (<tt>'\u002D'</tt>), followed by a sequence of
* zero or more decimal digits ("the integer"), optionally
* followed by a fraction, optionally followed by an exponent.
*
* <p>The fraction consists of a decimal point followed by zero
* or more decimal digits. The string must contain at least one
* digit in either the integer or the fraction. The number formed
* by the sign, the integer and the fraction is referred to as the
* <i>significand</i>.
*
* <p>The exponent consists of the character {@code 'e'}
* (<tt>'\u0065'</tt>) or {@code 'E'} (<tt>'\u0045'</tt>)
* followed by one or more decimal digits. The value of the
* exponent must lie between -{@link Integer#MAX_VALUE} ({@link
* Integer#MIN_VALUE}+1) and {@link Integer#MAX_VALUE}, inclusive.
*
* <p>More formally, the strings this constructor accepts are
* described by the following grammar:
* <blockquote>
* <dl>
* <dt><i>BigDecimalString:</i>
* <dd><i>Sign<sub>opt</sub> Significand Exponent<sub>opt</sub></i>
* <dt><i>Sign:</i>
* <dd>{@code +}
* <dd>{@code -}
* <dt><i>Significand:</i>
* <dd><i>IntegerPart</i> {@code .} <i>FractionPart<sub>opt</sub></i>
* <dd>{@code .} <i>FractionPart</i>
* <dd><i>IntegerPart</i>
* <dt><i>IntegerPart:</i>
* <dd><i>Digits</i>
* <dt><i>FractionPart:</i>
* <dd><i>Digits</i>
* <dt><i>Exponent:</i>
* <dd><i>ExponentIndicator SignedInteger</i>
* <dt><i>ExponentIndicator:</i>
* <dd>{@code e}
* <dd>{@code E}
* <dt><i>SignedInteger:</i>
* <dd><i>Sign<sub>opt</sub> Digits</i>
* <dt><i>Digits:</i>
* <dd><i>Digit</i>
* <dd><i>Digits Digit</i>
* <dt><i>Digit:</i>
* <dd>any character for which {@link Character#isDigit}
* returns {@code true}, including 0, 1, 2 ...
* </dl>
* </blockquote>
*
* <p>The scale of the returned {@code BigDecimal} will be the
* number of digits in the fraction, or zero if the string
* contains no decimal point, subject to adjustment for any
* exponent; if the string contains an exponent, the exponent is
* subtracted from the scale. The value of the resulting scale
* must lie between {@code Integer.MIN_VALUE} and
* {@code Integer.MAX_VALUE}, inclusive.
*
* <p>The character-to-digit mapping is provided by {@link
* java.lang.Character#digit} set to convert to radix 10. The
* String may not contain any extraneous characters (whitespace,
* for example).
*
* <p><b>Examples:</b><br>
* The value of the returned {@code BigDecimal} is equal to
* <i>significand</i> × 10<sup> <i>exponent</i></sup>.
* For each string on the left, the resulting representation
* [{@code BigInteger}, {@code scale}] is shown on the right.
* <pre>
* "0" [0,0]
* "0.00" [0,2]
* "123" [123,0]
* "-123" [-123,0]
* "1.23E3" [123,-1]
* "1.23E+3" [123,-1]
* "12.3E+7" [123,-6]
* "12.0" [120,1]
* "12.3" [123,1]
* "0.00123" [123,5]
* "-1.23E-12" [-123,14]
* "1234.5E-4" [12345,5]
* "0E+7" [0,-7]
* "-0" [0,0]
* </pre>
*
* <p>Note: For values other than {@code float} and
* {@code double} NaN and ±Infinity, this constructor is
* compatible with the values returned by {@link Float#toString}
* and {@link Double#toString}. This is generally the preferred
* way to convert a {@code float} or {@code double} into a
* BigDecimal, as it doesn't suffer from the unpredictability of
* the {@link #BigDecimal(double)} constructor.
*
* @param val String representation of {@code BigDecimal}.
*
* @throws NumberFormatException if {@code val} is not a valid
* representation of a {@code BigDecimal}.
*/
public BigDecimal(String val) {
this(val.toCharArray(), 0, val.length());
}
/**
* Translates the string representation of a {@code BigDecimal}
* into a {@code BigDecimal}, accepting the same strings as the
* {@link #BigDecimal(String)} constructor, with rounding
* according to the context settings.
*
* @param val string representation of a {@code BigDecimal}.
* @param mc the context to use.
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
* @throws NumberFormatException if {@code val} is not a valid
* representation of a BigDecimal.
* @since 1.5
*/
public BigDecimal(String val, MathContext mc) {
this(val.toCharArray(), 0, val.length(), mc);
}
/**
* Translates a {@code double} into a {@code BigDecimal} which
* is the exact decimal representation of the {@code double}'s
* binary floating-point value. The scale of the returned
* {@code BigDecimal} is the smallest value such that
* <tt>(10<sup>scale</sup> × val)</tt> is an integer.
* <p>
* <b>Notes:</b>
* <ol>
* <li>
* The results of this constructor can be somewhat unpredictable.
* One might assume that writing {@code new BigDecimal(0.1)} in
* Java creates a {@code BigDecimal} which is exactly equal to
* 0.1 (an unscaled value of 1, with a scale of 1), but it is
* actually equal to
* 0.1000000000000000055511151231257827021181583404541015625.
* This is because 0.1 cannot be represented exactly as a
* {@code double} (or, for that matter, as a binary fraction of
* any finite length). Thus, the value that is being passed
* <i>in</i> to the constructor is not exactly equal to 0.1,
* appearances notwithstanding.
*
* <li>
* The {@code String} constructor, on the other hand, is
* perfectly predictable: writing {@code new BigDecimal("0.1")}
* creates a {@code BigDecimal} which is <i>exactly</i> equal to
* 0.1, as one would expect. Therefore, it is generally
* recommended that the {@linkplain #BigDecimal(String)
* <tt>String</tt> constructor} be used in preference to this one.
*
* <li>
* When a {@code double} must be used as a source for a
* {@code BigDecimal}, note that this constructor provides an
* exact conversion; it does not give the same result as
* converting the {@code double} to a {@code String} using the
* {@link Double#toString(double)} method and then using the
* {@link #BigDecimal(String)} constructor. To get that result,
* use the {@code static} {@link #valueOf(double)} method.
* </ol>
*
* @param val {@code double} value to be converted to
* {@code BigDecimal}.
* @throws NumberFormatException if {@code val} is infinite or NaN.
*/
public BigDecimal(double val) {
this(val,MathContext.UNLIMITED);
}
/**
* Translates a {@code double} into a {@code BigDecimal}, with
* rounding according to the context settings. The scale of the
* {@code BigDecimal} is the smallest value such that
* <tt>(10<sup>scale</sup> × val)</tt> is an integer.
*
* <p>The results of this constructor can be somewhat unpredictable
* and its use is generally not recommended; see the notes under
* the {@link #BigDecimal(double)} constructor.
*
* @param val {@code double} value to be converted to
* {@code BigDecimal}.
* @param mc the context to use.
* @throws ArithmeticException if the result is inexact but the
* RoundingMode is UNNECESSARY.
* @throws NumberFormatException if {@code val} is infinite or NaN.
* @since 1.5
*/
public BigDecimal(double val, MathContext mc) {
// ...
}
/**
* Translates a {@code BigInteger} into a {@code BigDecimal}.
* The scale of the {@code BigDecimal} is zero.
*
* @param val {@code BigInteger} value to be converted to
* {@code BigDecimal}.
*/
public BigDecimal(BigInteger val) {
scale = 0;
intVal = val;
intCompact = compactValFor(val);
}
/**
* Translates a {@code BigInteger} into a {@code BigDecimal}
* rounding according to the context settings. The scale of the
* {@code BigDecimal} is zero.
*
* @param val {@code BigInteger} value to be converted to
* {@code BigDecimal}.
* @param mc the context to use.
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
* @since 1.5
*/
public BigDecimal(BigInteger val, MathContext mc) {
this(val,0,mc);
}
/**
* Translates a {@code BigInteger} unscaled value and an
* {@code int} scale into a {@code BigDecimal}. The value of
* the {@code BigDecimal} is
* <tt>(unscaledVal × 10<sup>-scale</sup>)</tt>.
*
* @param unscaledVal unscaled value of the {@code BigDecimal}.
* @param scale scale of the {@code BigDecimal}.
*/
public BigDecimal(BigInteger unscaledVal, int scale) {
// Negative scales are now allowed
this.intVal = unscaledVal;
this.intCompact = compactValFor(unscaledVal);
this.scale = scale;
}
/**
* Translates a {@code BigInteger} unscaled value and an
* {@code int} scale into a {@code BigDecimal}, with rounding
* according to the context settings. The value of the
* {@code BigDecimal} is <tt>(unscaledVal ×
* 10<sup>-scale</sup>)</tt>, rounded according to the
* {@code precision} and rounding mode settings.
*
* @param unscaledVal unscaled value of the {@code BigDecimal}.
* @param scale scale of the {@code BigDecimal}.
* @param mc the context to use.
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
* @since 1.5
*/
public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) {
// ...
}
/**
* Translates an {@code int} into a {@code BigDecimal}. The
* scale of the {@code BigDecimal} is zero.
*
* @param val {@code int} value to be converted to
* {@code BigDecimal}.
* @since 1.5
*/
public BigDecimal(int val) {
this.intCompact = val;
this.scale = 0;
this.intVal = null;
}
/**
* Translates an {@code int} into a {@code BigDecimal}, with
* rounding according to the context settings. The scale of the
* {@code BigDecimal}, before any rounding, is zero.
*
* @param val {@code int} value to be converted to {@code BigDecimal}.
* @param mc the context to use.
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
* @since 1.5
*/
public BigDecimal(int val, MathContext mc) {
//...
}
/**
* Translates a {@code long} into a {@code BigDecimal}, with
* rounding according to the context settings. The scale of the
* {@code BigDecimal}, before any rounding, is zero.
*
* @param val {@code long} value to be converted to {@code BigDecimal}.
* @param mc the context to use.
* @throws ArithmeticException if the result is inexact but the
* rounding mode is {@code UNNECESSARY}.
* @since 1.5
*/
public BigDecimal(long val, MathContext mc) {
// ...
}
}