summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--java/math/BigDecimal.java217
2 files changed, 214 insertions, 12 deletions
diff --git a/ChangeLog b/ChangeLog
index 62316f879..dfcf8b48d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2006-02-22 Anthony Balkissoon <abalkiss@redhat.com>
+
+ * java/math/BigDecimal.java:
+ (BigDecimal(char[], int, int, MathContext)): New constructor.
+ (BigDecimal(char[], MathContext)): Likewise.
+ (BigDecimal(char[])): Likewise.
+ (BigDecimal(char[], int, int)): Likewise.
+ (BigDecimal(String)): Fixed handling of exponent and scale.
+
2006-02-21 Anthony Balkissoon <abalkiss@redhat.com>
* java/math/BigDecimal.java:
diff --git a/java/math/BigDecimal.java b/java/math/BigDecimal.java
index a666c7714..d4a369c06 100644
--- a/java/math/BigDecimal.java
+++ b/java/math/BigDecimal.java
@@ -170,6 +170,209 @@ public class BigDecimal extends Number implements Comparable<BigDecimal>
}
}
+ /**
+ * Constructs a BigDecimal from the char subarray and rounding
+ * according to the MathContext.
+ * @param in the char array
+ * @param offset the start of the subarray
+ * @param len the length of the subarray
+ * @param mc the MathContext for rounding
+ * @throws NumberFormatException if the char subarray is not a valid
+ * BigDecimal representation
+ * @throws ArithmeticException if the result is inexact but the rounding
+ * mode is RoundingMode.UNNECESSARY
+ * @since 1.5
+ */
+ public BigDecimal(char[] in, int offset, int len, MathContext mc)
+ {
+ this(in, offset, len);
+ // If mc has precision other than zero then we must round.
+ if (mc.getPrecision() != 0)
+ {
+ BigDecimal temp = this.round(mc);
+ this.intVal = temp.intVal;
+ this.scale = temp.scale;
+ this.precision = temp.precision;
+ }
+ }
+
+ /**
+ * Constructs a BigDecimal from the char array and rounding according
+ * to the MathContext.
+ * @param in the char array
+ * @param mc the MathContext
+ * @throws NumberFormatException if <code>in</code> is not a valid BigDecimal
+ * representation
+ * @throws ArithmeticException if the result is inexact but the rounding mode
+ * is RoundingMode.UNNECESSARY
+ * @since 1.5
+ */
+ public BigDecimal(char[] in, MathContext mc)
+ {
+ this(in, 0, in.length);
+ // If mc has precision other than zero then we must round.
+ if (mc.getPrecision() != 0)
+ {
+ BigDecimal temp = this.round(mc);
+ this.intVal = temp.intVal;
+ this.scale = temp.scale;
+ this.precision = temp.precision;
+ }
+ }
+
+ /**
+ * Constructs a BigDecimal from the given char array, accepting the same
+ * sequence of characters as the BigDecimal(String) constructor.
+ * @param in the char array
+ * @throws NumberFormatException if <code>in</code> is not a valid BigDecimal
+ * representation
+ * @since 1.5
+ */
+ public BigDecimal(char[] in)
+ {
+ this(in, 0, in.length);
+ }
+
+ /**
+ * Constructs a BigDecimal from a char subarray, accepting the same sequence
+ * of characters as the BigDecimal(String) constructor.
+ * @param in the char array
+ * @param offset the start of the subarray
+ * @param len the length of the subarray
+ * @throws NumberFormatException if <code>in</code> is not a valid
+ * BigDecimal representation.
+ * @since 1.5
+ */
+ public BigDecimal(char[] in, int offset, int len)
+ {
+ // start is the index into the char array where the significand starts
+ int start = offset;
+ // end is one greater than the index of the last character used
+ int end = offset + len;
+ // point is the index into the char array where the exponent starts
+ // (or, if there is no exponent, this is equal to end)
+ int point = offset;
+ // dot is the index into the char array where the decimal point is
+ // found, or -1 if there is no decimal point
+ int dot = -1;
+
+ // The following examples show what these variables mean. Note that
+ // point and dot don't yet have the correct values, they will be
+ // properly assigned in a loop later on in this method.
+ //
+ // Example 1
+ //
+ // + 1 0 2 . 4 6 9
+ // __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
+ //
+ // offset = 2, len = 8, start = 3, dot = 6, point = end = 10
+ //
+ // Example 2
+ //
+ // + 2 3 4 . 6 1 3 E - 1
+ // __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
+ //
+ // offset = 2, len = 11, start = 3, dot = 6, point = 10, end = 13
+ //
+ // Example 3
+ //
+ // - 1 2 3 4 5 e 7
+ // __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
+ //
+ // offset = 2, len = 8, start = 3, dot = -1, point = 8, end = 10
+
+ // Determine the sign of the number.
+ boolean negative = false;
+ if (in[offset] == '+')
+ {
+ ++start;
+ ++point;
+ }
+ else if (in[offset] == '-')
+ {
+ ++start;
+ ++point;
+ negative = true;
+ }
+
+ // Check each character looking for the decimal point and the
+ // start of the exponent.
+ while (point < end)
+ {
+ char c = in[point];
+ if (c == '.')
+ {
+ // If dot != -1 then we've seen more than one decimal point.
+ if (dot != -1)
+ throw new NumberFormatException("multiple `.'s in number");
+ dot = point;
+ }
+ // Break when we reach the start of the exponent.
+ else if (c == 'e' || c == 'E')
+ break;
+ // Throw an exception if the character was not a decimal or an
+ // exponent and is not a digit.
+ else if (!Character.isDigit(c))
+ throw new NumberFormatException("unrecognized character at " + point
+ + ": " + c);
+ ++point;
+ }
+
+ // val is a StringBuilder from which we'll create a BigInteger
+ // which will be the unscaled value for this BigDecimal
+ StringBuilder val = new StringBuilder(point - start - 1);
+ if (dot != -1)
+ {
+ // If there was a decimal we must combine the two parts that
+ // contain only digits and we must set the scale properly.
+ val.append(in, start, dot - start);
+ val.append(in, dot + 1, point - dot - 1);
+ scale = point - 1 - dot;
+ }
+ else
+ {
+ // If there was no decimal then the unscaled value is just the number
+ // formed from all the digits and the scale is zero.
+ val.append(in, start, point - start);
+ scale = 0;
+ }
+ if (val.length() == 0)
+ throw new NumberFormatException("no digits seen");
+
+ // Prepend a negative sign if necessary.
+ if (negative)
+ val.insert(0, '-');
+ intVal = new BigInteger(val.toString());
+
+ // Now parse exponent.
+ // If point < end that means we broke out of the previous loop when we
+ // saw an 'e' or an 'E'.
+ if (point < end)
+ {
+ point++;
+ // Ignore a '+' sign.
+ if (in[point] == '+')
+ point++;
+
+ // Throw an exception if there were no digits found after the 'e'
+ // or 'E'.
+ if (point >= end)
+ throw new NumberFormatException("no exponent following e or E");
+
+ try
+ {
+ // Adjust the scale according to the exponent.
+ // Remember that the value of a BigDecimal is
+ // unscaledValue x Math.pow(10, -scale)
+ scale -= Integer.parseInt(new String(in, point, end - point));
+ }
+ catch (NumberFormatException ex)
+ {
+ throw new NumberFormatException("malformed exponent");
+ }
+ }
+ }
+
public BigDecimal (String num) throws NumberFormatException
{
int len = num.length();
@@ -233,18 +436,8 @@ public class BigDecimal extends Number implements Comparable<BigDecimal>
throw new NumberFormatException ("no exponent following e or E");
try
- {
- int exp = Integer.parseInt (num.substring (point));
- exp -= scale;
- if (signum () == 0)
- scale = 0;
- else if (exp > 0)
- {
- intVal = intVal.multiply (BigInteger.valueOf (10).pow (exp));
- scale = 0;
- }
- else
- scale = - exp;
+ {
+ scale -= Integer.parseInt (num.substring (point));
}
catch (NumberFormatException ex)
{