Add BigDecimal/etc support.

This is what was previously rolled back in r7359 with a couple of
fixes.

Public review: http://gwt-code-reviews.appspot.com/126811

Patch by: jat
Review by: rice


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7618 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/i18n/client/NumberFormat.java b/user/src/com/google/gwt/i18n/client/NumberFormat.java
index 7b2ba5c..6d3a60d 100644
--- a/user/src/com/google/gwt/i18n/client/NumberFormat.java
+++ b/user/src/com/google/gwt/i18n/client/NumberFormat.java
@@ -15,9 +15,11 @@
  */
 package com.google.gwt.i18n.client;
 
-import com.google.gwt.core.client.GWT;
 import com.google.gwt.i18n.client.constants.NumberConstants;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
 /**
  * Formats and parses numbers using locale-sensitive patterns.
  * 
@@ -349,7 +351,7 @@
   public static boolean forcedLatinDigits() {
     return defaultNumberConstants != localizedNumberConstants;
   }
-  
+
   /**
    * Provides the standard currency format for the default locale.
    * 
@@ -363,7 +365,7 @@
     }
     return cachedCurrencyFormat;
   }
-  
+
   /**
    * Provides the standard currency format for the default locale using a
    * specified currency.
@@ -376,7 +378,7 @@
     return new NumberFormat(defaultNumberConstants.currencyPattern(),
         currencyData, false);
   }
-  
+
   /**
    * Provides the standard currency format for the default locale using a
    * specified currency.
@@ -609,6 +611,47 @@
   }
 
   /**
+   * Appends a scaled string representation to a buffer, returning the scale
+   * (which is the number of places to the right of the end of the string the
+   * decimal point should be moved -- i.e., 3.5 would be added to the buffer
+   * as "35" and a returned scale of -1).
+   * 
+   * @param buf
+   * @param val
+   * @return scale to apply to the result
+   */
+  // @VisibleForTesting
+  static int toScaledString(StringBuilder buf, double val) {
+    int startLen = buf.length();
+    buf.append(toPrecision(val, 20));
+    int scale = 0;
+
+    // remove exponent if present, adjusting scale
+    int expIdx = buf.indexOf("e", startLen);
+    if (expIdx < 0) {
+      expIdx = buf.indexOf("E", startLen);
+    }
+    if (expIdx >= 0) {
+      int expDigits = expIdx + 1;
+      if (expDigits < buf.length() && buf.charAt(expDigits) == '+') {
+        ++expDigits;
+      }
+      if (expDigits < buf.length()) {
+        scale = Integer.parseInt(buf.substring(expDigits));
+      }
+      buf.delete(expIdx, buf.length());
+    }
+
+    // remove decimal point if present, adjusting scale
+    int dot = buf.indexOf(".", startLen);
+    if (dot >= 0) {
+      buf.deleteCharAt(dot);
+      scale -= buf.length() - dot;
+    }
+    return scale;
+  }
+
+  /**
    * Lookup a currency code.
    * 
    * @param currencyCode ISO4217 currency code
@@ -625,26 +668,43 @@
     return currencyData;
   }
 
-  private static native String toFixed(double d, int digits) /*-{
-    return d.toFixed(digits);
+  /**
+   * Convert a double to a string with {@code digits} precision.  The resulting
+   * string may still be in exponential notation.
+   * 
+   * @param d double value
+   * @param digits number of digits of precision to include
+   * @return non-localized string representation of {@code d}
+   */
+  private static native String toPrecision(double d, int digits) /*-{
+    return d.toPrecision(digits);
   }-*/;
 
-  // The currency code.
+  /**
+   * The currency code.
+   */
   private final String currencyCode;
 
-  // Currency setting.
+  /**
+   * Currency symbol to use.
+   */
   private final String currencySymbol;
 
-  // Forces the decimal separator to always appear in a formatted number.
+  /**
+   * Forces the decimal separator to always appear in a formatted number.
+   */
   private boolean decimalSeparatorAlwaysShown = false;
 
-  // The number of digits between grouping separators in the integer
-  // portion of a number.
+  /**
+   * The number of digits between grouping separators in the integer portion of
+   * a number.
+   */
   private int groupingSize = 3;
-  
+
   private boolean isCurrencyFormat = false;
-  
+
   private int maximumFractionDigits = 3; // invariant, >= minFractionDigits.
+
   private int maximumIntegerDigits = 40;
   private int minExponentDigits;
   private int minimumFractionDigits = 0;
@@ -671,6 +731,24 @@
   private boolean useExponentialNotation = false;
 
   /**
+   * Holds the current exponent during one call to
+   * {@link #format(boolean, StringBuilder, int)}.
+   */
+  private transient int exponent;
+
+  /**
+   * Holds the current decimal position during one call to
+   * {@link #format(boolean, StringBuilder, int)}.
+   */
+  private transient int decimalPosition;
+
+  /**
+   * Holds the current digits length during one call to
+   * {@link #format(boolean, StringBuilder, int)}.
+   */
+  private transient int digitsLength;
+
+  /**
    * Constructs a format object based on the specified settings.
    * 
    * @param numberConstants the locale-specific number constants to use for this
@@ -719,33 +797,75 @@
    * @return the formatted number string
    */
   public String format(double number) {
-    StringBuffer result = new StringBuffer();
-
     if (Double.isNaN(number)) {
-      result.append(numberConstants.notANumber());
-      return result.toString();
+      return numberConstants.notANumber();
     }
-
-    boolean isNegative = ((number < 0.0) || (number == 0.0 && 1 / number < 0.0));
-
-    result.append(isNegative ? negativePrefix : positivePrefix);
+    boolean isNegative = ((number < 0.0)
+        || (number == 0.0 && 1 / number < 0.0));
+    if (isNegative) {
+      number = -number;
+    }
+    StringBuilder buf = new StringBuilder();
     if (Double.isInfinite(number)) {
-      result.append(numberConstants.infinity());
-    } else {
-      if (isNegative) {
-        number = -number;
-      }
-      number *= multiplier;
-      if (useExponentialNotation) {
-        subformatExponential(number, result);
-      } else {
-        subformatFixed(number, result, minimumIntegerDigits);
-      }
+      buf.append(isNegative ? negativePrefix : positivePrefix);
+      buf.append(numberConstants.infinity());
+      buf.append(isNegative ? negativeSuffix : positiveSuffix);
+      return buf.toString();
+    }
+    number *= multiplier;
+    int scale = toScaledString(buf, number);
+
+    // pre-round value to deal with .15 being represented as .149999... etc
+    // check at 3 more digits than will be required in the output
+    int preRound = buf.length() + scale + maximumFractionDigits + 3;
+    if (preRound > 0 && preRound < buf.length()
+        && buf.charAt(preRound) == '9') {
+      propagateCarry(buf, preRound - 1);
+      scale += buf.length() - preRound;
+      buf.delete(preRound, buf.length());
     }
 
-    result.append(isNegative ? negativeSuffix : positiveSuffix);
+    format(isNegative, buf, scale);
+    return buf.toString();
+  }
 
-    return result.toString();
+  /**
+   * This method formats a Number to produce a string.
+   * <p>
+   * Any {@link Number} which is not a {@link BigDecimal}, {@link BigInteger},
+   * or {@link Long} instance is formatted as a {@code double} value.
+   * 
+   * @param number The Number instance to format
+   * @return the formatted number string
+   */
+  public String format(Number number) {
+    if (number instanceof BigDecimal) {
+      BigDecimal bigDec = (BigDecimal) number;
+      boolean isNegative = bigDec.signum() < 0;
+      if (isNegative) {
+        bigDec = bigDec.negate();
+      }
+      bigDec = bigDec.multiply(BigDecimal.valueOf(multiplier));
+      StringBuilder buf = new StringBuilder();
+      buf.append(bigDec.unscaledValue().toString());
+      format(isNegative, buf, -bigDec.scale());
+      return buf.toString();
+    } else if (number instanceof BigInteger) {
+      BigInteger bigInt = (BigInteger) number;
+      boolean isNegative = bigInt.signum() < 0;
+      if (isNegative) {
+        bigInt = bigInt.negate();
+      }
+      bigInt = bigInt.multiply(BigInteger.valueOf(multiplier));
+      StringBuilder buf = new StringBuilder();
+      buf.append(bigInt.toString());
+      format(isNegative, buf, 0);
+      return buf.toString();
+    } else if (number instanceof Long) {
+      return format(number.longValue(), 0);
+    } else {
+      return format(number.doubleValue());
+    }
   }
 
   /**
@@ -761,9 +881,9 @@
    * characters of the text.
    * 
    * @param text the string being parsed
-   * @return a parsed number value
+   * @return a double value representing the parsed number
    * @throws NumberFormatException if the entire text could not be converted
-   *           into a number
+   *     into a double
    */
   public double parse(String text) throws NumberFormatException {
     int[] pos = {0};
@@ -789,9 +909,9 @@
    * 
    * @param text the string to be parsed
    * @param inOutPos position to pass in and get back
-   * @return a double value representing the parsed number, or <code>0.0</code>
-   *         if the parse fails
-   * @throws NumberFormatException if the text segment could not be converted into a number
+   * @return a double value representing the parsed number
+   * @throws NumberFormatException if the text segment could not be converted
+   *     into a double
    */
   public double parse(String text, int[] inOutPos) throws NumberFormatException {
     double ret = 0.0;
@@ -863,56 +983,294 @@
     return ret;
   }
 
+  /**
+   * Format a number with its significant digits already represented in string
+   * form.  This is done so both double and BigInteger/Decimal formatting can
+   * share code without requiring all users to pay the code size penalty for
+   * BigDecimal/etc.
+   * <p>
+   * Example values passed in:
+   * <ul>
+   * <li>-13e2
+   * <br>{@code isNegative=true, digits="13", scale=2}
+   * <li>3.14158
+   * <br>{@code isNegative=false, digits="314158", scale=-5}
+   * <li>.0001
+   * <br>{@code isNegative=false, digits="1" ("0001" would be ok), scale=-4}
+   * </ul>
+   *  
+   * @param isNegative true if the value to be formatted is negative
+   * @param digits a StringBuilder containing just the significant digits in
+   *     the value to be formatted, the formatted result will be left here
+   * @param scale the number of places to the right the decimal point should
+   *     be moved in the digit string -- negative means the value contains
+   *     fractional digits
+   */
+  protected void format(boolean isNegative, StringBuilder digits, int scale) {
+    char decimalSeparator;
+    char groupingSeparator;
+    if (isCurrencyFormat) {
+      decimalSeparator = numberConstants.monetarySeparator().charAt(0);
+      groupingSeparator = numberConstants.monetaryGroupingSeparator().charAt(0);
+    } else {
+      decimalSeparator = numberConstants.decimalSeparator().charAt(0);
+      groupingSeparator = numberConstants.groupingSeparator().charAt(0);
+    }
+
+    // Set these transient fields, which will be adjusted/used by the routines
+    // called in this method.
+    exponent = 0;
+    digitsLength = digits.length();
+    decimalPosition = digitsLength + scale;
+
+    boolean useExponent = this.useExponentialNotation;
+    int currentGroupingSize = this.groupingSize;
+    if (decimalPosition > 1024) {
+      // force really large numbers to be in exponential form
+      useExponent = true;
+    }
+
+    if (useExponent) {
+      computeExponent(digits);
+    }
+    processLeadingZeros(digits);
+    roundValue(digits);
+    insertGroupingSeparators(digits, groupingSeparator, currentGroupingSize);
+    adjustFractionDigits(digits);
+    addZeroAndDecimal(digits, decimalSeparator);
+    if (useExponent) {
+      addExponent(digits);
+      // the above call has invalidated digitsLength == digits.length()
+    }
+    char zeroChar = numberConstants.zeroDigit().charAt(0);
+    if (zeroChar != '0') {
+      localizeDigits(digits, zeroChar);
+    }
+
+    // add prefix/suffix
+    digits.insert(0, isNegative ? negativePrefix : positivePrefix);
+    digits.append(isNegative ? negativeSuffix : positiveSuffix);
+  }
+
+  /**
+   * Parses text to produce a numeric value. A {@link NumberFormatException} is
+   * thrown if either the text is empty or if the parse does not consume all
+   * characters of the text.
+   * 
+   * param text the string to be parsed
+   * return a parsed number value, which may be a Double, BigInteger, or
+   *     BigDecimal
+   * throws NumberFormatException if the text segment could not be converted
+   *     into a number
+   */
+//  public Number parseBig(String text) throws NumberFormatException {
+//    // TODO(jat): implement
+//    return Double.valueOf(parse(text));
+//  }
+
+  /**
+   * Parses text to produce a numeric value.
+   * 
+   * <p>
+   * The method attempts to parse text starting at the index given by pos. If
+   * parsing succeeds, then the index of <code>pos</code> is updated to the
+   * index after the last character used (parsing does not necessarily use all
+   * characters up to the end of the string), and the parsed number is returned.
+   * The updated <code>pos</code> can be used to indicate the starting point
+   * for the next call to this method. If an error occurs, then the index of
+   * <code>pos</code> is not changed.
+   * </p>
+   * 
+   * param text the string to be parsed
+   * pparam inOutPos position to pass in and get back
+   * return a parsed number value, which may be a Double, BigInteger, or
+   *     BigDecimal
+   * throws NumberFormatException if the text segment could not be converted
+   *     into a number
+   */
+//  public Number parseBig(String text, int[] inOutPos)
+//      throws NumberFormatException {
+//    // TODO(jat): implement
+//    return Double.valueOf(parse(text, inOutPos));
+//  }
+
+  /**
+   * Format a possibly scaled long value.
+   * 
+   * @param value value to format
+   * @param scale the number of places to the right the decimal point should
+   *     be moved in the digit string -- negative means the value contains
+   *     fractional digits
+   * @return formatted value
+   */
+  protected String format(long value, int scale) {
+    boolean isNegative = value < 0;
+    if (isNegative) {
+      value = -value;
+    }
+    value *= multiplier;
+    StringBuilder buf = new StringBuilder();
+    buf.append(String.valueOf(value));
+    format(isNegative, buf, scale);
+    return buf.toString();
+  }
+
+  /**
+   * @return the number of digits between grouping separators in the integer
+   *         portion of a number.
+   */
   protected int getGroupingSize() {
     return groupingSize;
   }
 
+  /**
+   * @return the prefix to use for negative values.
+   */
   protected String getNegativePrefix() {
     return negativePrefix;
   }
 
+  /**
+   * @return the suffix to use for negative values.
+   */
   protected String getNegativeSuffix() {
     return negativeSuffix;
   }
 
+  /**
+   * @return the NumberConstants instance for this formatter.
+   */
   protected NumberConstants getNumberConstants() {
     return numberConstants;
   }
 
+  /**
+   * @return the prefix to use for positive values.
+   */
   protected String getPositivePrefix() {
     return positivePrefix;
   }
 
+  /**
+   * @return the suffix to use for positive values.
+   */
   protected String getPositiveSuffix() {
     return positiveSuffix;
   }
 
+  /**
+   * @return true if the decimal separator should always be shown.
+   */
   protected boolean isDecimalSeparatorAlwaysShown() {
     return decimalSeparatorAlwaysShown;
   }
 
   /**
-   * This method formats the exponent part of a double.
+   * Add exponent suffix.
    * 
-   * @param exponent exponential value
-   * @param result formatted exponential part will be append to it
+   * @param digits
    */
-  private void addExponentPart(int exponent, StringBuffer result) {
-    result.append(numberConstants.exponentialSymbol());
-
+  private void addExponent(StringBuilder digits) {
+    digits.append(numberConstants.exponentialSymbol());
     if (exponent < 0) {
       exponent = -exponent;
-      result.append(numberConstants.minusSign());
+      digits.append(numberConstants.minusSign());
+    }
+    String exponentDigits = String.valueOf(exponent);
+    for (int i = exponentDigits.length(); i < minExponentDigits; ++i) {
+      digits.append('0');
+    }
+    digits.append(exponentDigits);
+  }
+
+  /**
+   * @param digits
+   * @param decimalSeparator
+   */
+  private void addZeroAndDecimal(StringBuilder digits, char decimalSeparator) {
+    // add zero and decimal point if required
+    if (digitsLength == 0) {
+      digits.insert(0, '0');
+      ++decimalPosition;
+      ++digitsLength;
+    }
+    if (decimalPosition < digitsLength || decimalSeparatorAlwaysShown) {
+      digits.insert(decimalPosition, decimalSeparator);
+      ++digitsLength;
+    }
+  }
+
+  /**
+   * Adjust the fraction digits, adding trailing zeroes if necessary or removing
+   * excess trailing zeroes.
+   * 
+   * @param digits
+   */
+  private void adjustFractionDigits(StringBuilder digits) {
+    // adjust fraction digits as required
+    int requiredDigits = decimalPosition + minimumFractionDigits;
+    if (digitsLength < requiredDigits) {
+      // add trailing zeros
+      while (digitsLength < requiredDigits) {
+        digits.append('0');
+        ++digitsLength;
+      }
+    } else {
+      // remove excess trailing zeros
+      int toRemove = decimalPosition + maximumFractionDigits;
+      if (toRemove > digitsLength) {
+        toRemove = digitsLength;
+      }
+      while (toRemove > requiredDigits
+          && digits.charAt(toRemove - 1) == '0') {
+        --toRemove;
+      }
+      if (toRemove < digitsLength) {
+        digits.delete(toRemove, digitsLength);
+        digitsLength = toRemove;
+      }
+    }
+  }
+
+  /**
+   * Compute the exponent to use and adjust decimal position if we are using
+   * exponential notation.
+   * 
+   * @param digits
+   */
+  private void computeExponent(StringBuilder digits) {
+    // always trim leading zeros
+    int strip = 0;
+    while (strip < digitsLength - 1 && digits.charAt(strip) == '0') {
+      ++strip;
+    }
+    if (strip > 0) {
+      digits.delete(0, strip);
+      digitsLength -= strip;
+      exponent -= strip;
     }
 
-    String exponentDigits = String.valueOf(exponent);
-    int len = exponentDigits.length();
-    for (int i = len; i < minExponentDigits; ++i) {
-      result.append(numberConstants.zeroDigit());
+    // decimal should wind up between minimum & maximumIntegerDigits
+    if (maximumIntegerDigits > minimumIntegerDigits
+        && maximumIntegerDigits > 0) {
+      // in this case, the exponent should be a multiple of
+      // maximumIntegerDigits and 1 <= decimal <= maximumIntegerDigits
+      exponent += decimalPosition - 1;
+      int remainder = exponent % maximumIntegerDigits;
+      if (remainder < 0) {
+        remainder += maximumIntegerDigits;
+      }
+      decimalPosition = remainder + 1;
+      exponent -= remainder;
+    } else {
+      exponent += decimalPosition - minimumIntegerDigits;
+      decimalPosition = minimumIntegerDigits;
     }
-    int zeroDelta = numberConstants.zeroDigit().charAt(0) - '0';
-    for (int i = 0; i < len; ++i) {
-      result.append((char) (exponentDigits.charAt(i) + zeroDelta));
+
+    // special-case 0 to have an exponent of 0
+    if (digitsLength == 1 && digits.charAt(0) == '0') {
+      exponent = 0;
+      decimalPosition = minimumIntegerDigits;
     }
   }
 
@@ -933,47 +1291,41 @@
   }
 
   /**
-   * This does the work of String.valueOf(long), but given a double as input
-   * and avoiding our emulated longs.  Contrasted with String.valueOf(double),
-   * it ensures (a) there will be no trailing .0, and (b) unwinds E-notation.
-   *  
-   * @param number the integral value to convert
-   * @return the string representing that integer
+   * Insert grouping separators if needed.
+   * 
+   * @param digits
+   * @param groupingSeparator
+   * @param g
    */
-  private String makeIntString(double number) {
-    String intPart = String.valueOf(number);
-    if (GWT.isScript()) {
-      return intPart; // JavaScript does the right thing for integral doubles
+  private void insertGroupingSeparators(StringBuilder digits,
+      char groupingSeparator, int g) {
+    if (g > 0) {
+      for (int i = g; i < decimalPosition; i += g + 1) {
+        digits.insert(decimalPosition - i, groupingSeparator);
+        ++decimalPosition;
+        ++digitsLength;
+      }
     }
-    // ...but bytecode (hosted mode) does not... String.valueOf(double) will 
-    // either end in .0 (non internationalized) which we don't want but is 
-    // easy, or, for large numbers, it will be E-notation, which is annoying.
-    int digitLen = intPart.length();
-    
-    if (intPart.charAt(digitLen - 2) == '.') {
-      return intPart.substring(0, digitLen - 2);
-    } 
-
-    // if we have E notation, (1) the exponent will be positive (else 
-    // intValue is 0, which doesn't need E notation), and (2) there will
-    // be a radix dot (String.valueOf() isn't interationalized)
-    int radix = intPart.indexOf('.');
-    int exp = intPart.indexOf('E');
-    int digits = 0;
-    for (int i = exp + 1; i < intPart.length(); i++) {
-      digits = digits * 10 + (intPart.charAt(i) - '0');
-    }
-    digits++;  // exp of zero is one int digit...
-    StringBuffer newIntPart = new StringBuffer();
-    newIntPart.append(intPart.substring(0, radix));
-    newIntPart.append(intPart.substring(radix + 1, exp));
-    while (newIntPart.length() < digits) {
-      newIntPart.append('0');
-    }
-    newIntPart.setLength(digits);
-    return newIntPart.toString();
   }
-  
+
+  /**
+   * Replace locale-independent digits with locale-specific ones.
+   *  
+   * @param digits StringBuilder containing formatted number
+   * @param zero locale-specific zero character -- the rest of the digits must
+   *     be consecutive
+   */
+  private void localizeDigits(StringBuilder digits, char zero) {
+    // don't use digitsLength since we may have added an exponent
+    int n = digits.length();
+    for (int i = 0; i < n; ++i) {
+      char ch = digits.charAt(i);
+      if (ch >= '0' && ch <= '9') {
+        digits.setCharAt(i, (char) (ch - '0' + zero));
+      }
+    }
+  }
+
   /**
    * This method parses affix part of pattern.
    * 
@@ -1301,141 +1653,87 @@
 
     return pos - start;
   }
-  
+
   /**
-   * This method formats a <code>double</code> in exponential format.
+   * Remove excess leading zeros or add some if we don't have enough.
    * 
-   * @param number value need to be formated
-   * @param result where the formatted string goes
+   * @param digits
    */
-  private void subformatExponential(double number, StringBuffer result) {
-    if (number == 0.0) {
-      subformatFixed(number, result, minimumIntegerDigits);
-      addExponentPart(0, result);
-      return;
+  private void processLeadingZeros(StringBuilder digits) {
+    // make sure we have enough trailing zeros
+    if (decimalPosition > digitsLength) {
+      while (digitsLength < decimalPosition) {
+        digits.append('0');
+        ++digitsLength;
+      }
     }
 
-    int exponent = (int) Math.floor(Math.log(number) / Math.log(10));
-    number /= Math.pow(10, exponent);
-
-    int minIntDigits = minimumIntegerDigits;
-    if (maximumIntegerDigits > 1 && maximumIntegerDigits > minimumIntegerDigits) {
-      // A repeating range is defined; adjust to it as follows.
-      // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3;
-      // -3,-4,-5=>-6, etc. This takes into account that the
-      // exponent we have here is off by one from what we expect;
-      // it is for the format 0.MMMMMx10^n.
-      while ((exponent % maximumIntegerDigits) != 0) {
-        number *= 10;
-        exponent--;
-      }
-      minIntDigits = 1;
-    } else {
-      // No repeating range is defined; use minimum integer digits.
-      if (minimumIntegerDigits < 1) {
-        exponent++;
-        number /= 10;
-      } else {
-        for (int i = 1; i < minimumIntegerDigits; i++) {
-          exponent--;
-          number *= 10;
+    if (!useExponentialNotation) {
+      // make sure we have the right number of leading zeros
+      if (decimalPosition < minimumIntegerDigits) {
+        // add leading zeros
+        StringBuilder prefix = new StringBuilder();
+        while (decimalPosition < minimumIntegerDigits) {
+          prefix.append('0');
+          ++decimalPosition;
+          ++digitsLength;
+        }
+        digits.insert(0, prefix);
+      } else if (decimalPosition > minimumIntegerDigits) {
+        // trim excess leading zeros
+        int strip = decimalPosition - minimumIntegerDigits;
+        for (int i = 0; i < strip; ++i) {
+          if (digits.charAt(i) != '0') {
+            strip = i;
+            break;
+          }
+        }
+        if (strip > 0) {
+          digits.delete(0, strip);
+          digitsLength -= strip;
+          decimalPosition -= strip;
         }
       }
     }
-
-    subformatFixed(number, result, minIntDigits);
-    addExponentPart(exponent, result);
   }
 
   /**
-   * This method formats a <code>double</code> into a fractional
-   * representation.
+   * Propagate a carry from incrementing the {@code i+1}'th digit.
    * 
-   * @param number value need to be formated
-   * @param result result will be written here
-   * @param minIntDigits minimum integer digits
+   * @param digits
+   * @param i digit to start incrementing
    */
-  private void subformatFixed(double number, StringBuffer result,
-      int minIntDigits) {
-    double power = Math.pow(10, maximumFractionDigits);
-    // Use 3 extra digits to allow us to do our own rounding since
-    // Java rounds up on .5 whereas some browsers might use 'round to even'
-    // or other rules.
-    
-    // There are cases where more digits would be required to get
-    // guaranteed results, but this at least makes such cases rarer.
-    String fixedString = toFixed(number, maximumFractionDigits + 3);
-
-    double intValue = 0, fracValue = 0;
-    int exponentIndex = fixedString.indexOf('e');
-    if (exponentIndex != -1) {
-      // Large numbers may be returned in exponential notation: such numbers
-      // are integers anyway
-      intValue = Math.floor(number);
-    } else {
-      int decimalIndex = fixedString.indexOf('.');
-      int len = fixedString.length();
-      if (decimalIndex == -1) {
-        decimalIndex = len;
-      }
-      if (decimalIndex > 0) {
-        intValue = Double.parseDouble(fixedString.substring(0, decimalIndex));
-      }
-      if (decimalIndex < len - 1) {
-        fracValue = Double.parseDouble(fixedString.substring(decimalIndex + 1));
-        fracValue = (((int) fracValue) + 500) / 1000;
-        if (fracValue >= power) {
-          fracValue -= power;
-          intValue++;
-        }
+  private void propagateCarry(StringBuilder digits, int i) {
+    boolean carry = true;
+    while (carry && i >= 0) {
+      char digit = digits.charAt(i);
+      if (digit == '9') {
+        // set this to zero and keep going
+        digits.setCharAt(i--, '0');
+      } else {
+        digits.setCharAt(i, (char) (digit + 1));
+        carry = false;
       }
     }
-
-    boolean fractionPresent = (minimumFractionDigits > 0) || (fracValue > 0);
-
-    String intPart = makeIntString(intValue);
-    String grouping = isCurrencyFormat
-        ? numberConstants.monetaryGroupingSeparator()
-        : numberConstants.groupingSeparator();
-    String decimal = isCurrencyFormat ? numberConstants.monetarySeparator()
-        : numberConstants.decimalSeparator();
-
-    int zeroDelta = numberConstants.zeroDigit().charAt(0) - '0';
-    int digitLen = intPart.length();
-    
-    if (intValue > 0 || minIntDigits > 0) {
-      for (int i = digitLen; i < minIntDigits; i++) {
-        result.append(numberConstants.zeroDigit());
-      }
-
-      for (int i = 0; i < digitLen; i++) {
-        result.append((char) (intPart.charAt(i) + zeroDelta));
-
-        if (digitLen - i > 1 && groupingSize > 0
-            && ((digitLen - i) % groupingSize == 1)) {
-          result.append(grouping);
-        }
-      }
-    } else if (!fractionPresent) {
-      // If there is no fraction present, and we haven't printed any
-      // integer digits, then print a zero.
-      result.append(numberConstants.zeroDigit());
+    if (carry) {
+      // ran off the front, prepend a 1
+      digits.insert(0, '1');
+      ++decimalPosition;
+      ++digitsLength;
     }
+  }
 
-    // Output the decimal separator if we always do so.
-    if (decimalSeparatorAlwaysShown || fractionPresent) {
-      result.append(decimal);
-    }
-
-    // To make sure it lead zero will be kept.
-    String fracPart = makeIntString(Math.floor(fracValue + power + 0.5d));
-    int fracLen = fracPart.length();
-    while (fracPart.charAt(fracLen - 1) == '0' && fracLen > minimumFractionDigits + 1) {
-      fracLen--;
-    }
-
-    for (int i = 1; i < fracLen; i++) {
-      result.append((char) (fracPart.charAt(i) + zeroDelta));
+  /**
+   * Round the value at the requested place, propagating any carry backward.
+   * 
+   * @param digits
+   */
+  private void roundValue(StringBuilder digits) {
+    // TODO(jat): other rounding modes?    
+    if (digitsLength > decimalPosition + maximumFractionDigits
+        && digits.charAt(decimalPosition + maximumFractionDigits) >= '5') {
+      int i = decimalPosition + maximumFractionDigits - 1;
+      propagateCarry(digits, i);
     }
   }
 }
diff --git a/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java b/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java
index a360356..4513ab0 100644
--- a/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java
@@ -83,9 +83,21 @@
     public String format(StringGenerator out, String subformat, String argName,
         JType argType) {
       JPrimitiveType argPrimType = argType.isPrimitive();
-      if (argPrimType == null || argPrimType == JPrimitiveType.BOOLEAN
-          || argPrimType == JPrimitiveType.VOID) {
-        return "Illegal argument type for number format";
+      if (argPrimType != null) {
+        if (argPrimType == JPrimitiveType.BOOLEAN
+            || argPrimType == JPrimitiveType.VOID) {
+          return "Illegal argument type for number format";
+        }
+      } else {
+        JClassType classType = argType.isClass();
+        if (classType == null) {
+          return "Unexpected argument type for number format";
+        }
+        TypeOracle oracle = classType.getOracle();
+        JClassType numberType = oracle.findType("java.lang.Number");
+        if (!classType.isAssignableTo(numberType)) {
+          return "Only Number subclasses may be formatted as a number";
+        }
       }
       if (subformat == null) {
         out.appendExpression(numFormatClassName + ".getDecimalFormat().format("
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/math/BigDecimal_CustomFieldSerializer.java b/user/src/com/google/gwt/user/client/rpc/core/java/math/BigDecimal_CustomFieldSerializer.java
new file mode 100644
index 0000000..8bd01ee
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/rpc/core/java/math/BigDecimal_CustomFieldSerializer.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+/*
+ * author Richard Zschech
+ */
+package com.google.gwt.user.client.rpc.core.java.math;
+
+import com.google.gwt.user.client.rpc.SerializationException;
+import com.google.gwt.user.client.rpc.SerializationStreamReader;
+import com.google.gwt.user.client.rpc.SerializationStreamWriter;
+
+import java.math.BigDecimal;
+
+/**
+ * Custom field serializer for BigDecimal.
+ */
+public class BigDecimal_CustomFieldSerializer {
+
+  public static void deserialize(SerializationStreamReader streamReader,
+      BigDecimal instance) {
+  }
+
+  public static BigDecimal instantiate(SerializationStreamReader streamReader)
+      throws SerializationException {
+    return new BigDecimal(streamReader.readString());
+  }
+
+  public static void serialize(SerializationStreamWriter streamWriter,
+      BigDecimal instance) throws SerializationException {
+    streamWriter.writeString(instance.toString());
+  }
+}
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/math/BigInteger_CustomFieldSerializer.java b/user/src/com/google/gwt/user/client/rpc/core/java/math/BigInteger_CustomFieldSerializer.java
new file mode 100644
index 0000000..57ed4ba
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/rpc/core/java/math/BigInteger_CustomFieldSerializer.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+/*
+ * author Richard Zschech
+ */
+package com.google.gwt.user.client.rpc.core.java.math;
+
+import com.google.gwt.user.client.rpc.SerializationException;
+import com.google.gwt.user.client.rpc.SerializationStreamReader;
+import com.google.gwt.user.client.rpc.SerializationStreamWriter;
+
+import java.math.BigInteger;
+
+/**
+ * Custom field serializer for BigInteger.
+ */
+public class BigInteger_CustomFieldSerializer {
+
+  public static void deserialize(SerializationStreamReader streamReader,
+      BigInteger instance) {
+  }
+
+  public static BigInteger instantiate(SerializationStreamReader streamReader)
+      throws SerializationException {
+    return new BigInteger(streamReader.readString());
+  }
+
+  public static void serialize(SerializationStreamWriter streamWriter,
+      BigInteger instance) throws SerializationException {
+    streamWriter.writeString(instance.toString());
+  }
+}
diff --git a/user/src/com/google/gwt/user/client/rpc/core/java/math/MathContext_CustomFieldSerializer.java b/user/src/com/google/gwt/user/client/rpc/core/java/math/MathContext_CustomFieldSerializer.java
new file mode 100644
index 0000000..a9b3277
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/rpc/core/java/math/MathContext_CustomFieldSerializer.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+/*
+ * author Richard Zschech
+ */
+package com.google.gwt.user.client.rpc.core.java.math;
+
+import com.google.gwt.user.client.rpc.SerializationException;
+import com.google.gwt.user.client.rpc.SerializationStreamReader;
+import com.google.gwt.user.client.rpc.SerializationStreamWriter;
+
+import java.math.MathContext;
+import java.math.RoundingMode;
+
+/**
+ * Custom field serializer for MathContext.
+ */
+public class MathContext_CustomFieldSerializer {
+
+  public static void deserialize(SerializationStreamReader streamReader,
+      MathContext instance) {
+  }
+
+  public static MathContext instantiate(SerializationStreamReader streamReader)
+      throws SerializationException {
+    return new MathContext(streamReader.readInt(),
+        RoundingMode.values()[streamReader.readInt()]);
+  }
+
+  public static void serialize(SerializationStreamWriter streamWriter,
+      MathContext instance) throws SerializationException {
+    streamWriter.writeInt(instance.getPrecision());
+    streamWriter.writeInt(instance.getRoundingMode().ordinal());
+  }
+}
diff --git a/user/super/com/google/gwt/emul/java/lang/ArithmeticException.java b/user/super/com/google/gwt/emul/java/lang/ArithmeticException.java
index faf821e..235bc2c 100644
--- a/user/super/com/google/gwt/emul/java/lang/ArithmeticException.java
+++ b/user/super/com/google/gwt/emul/java/lang/ArithmeticException.java
@@ -16,10 +16,11 @@
 package java.lang;
 
 /**
- * NOTE: in GWT this is only thrown for division by zero on longs.
- * 
+ * NOTE: in GWT this is only thrown for division by zero on longs and
+ * BigInteger/BigDecimal.
+ * <p>
  * See <a
- * href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/ArrayIndexOutOfBoundsException.html">the
+ * href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/ArithmeticException.html">the
  * official Java API doc</a> for details.
  */
 public class ArithmeticException extends RuntimeException {
diff --git a/user/super/com/google/gwt/emul/java/lang/Float.java b/user/super/com/google/gwt/emul/java/lang/Float.java
index 8d9e849..b3c9576 100644
--- a/user/super/com/google/gwt/emul/java/lang/Float.java
+++ b/user/super/com/google/gwt/emul/java/lang/Float.java
@@ -16,7 +16,7 @@
 package java.lang;
 
 /**
- * Wraps a primitve <code>float</code> as an object.
+ * Wraps a primitive <code>float</code> as an object.
  */
 public final class Float extends Number implements Comparable<Float> {
   public static final float MAX_VALUE = 3.4028235e+38f;
@@ -40,7 +40,9 @@
   }
 
   /**
-   * @skip Here for shared implementation with Arrays.hashCode
+   * @skip Here for shared implementation with Arrays.hashCode.
+   * @param f 
+   * @return hash value of float (currently just truncated to int)
    */
   public static int hashCode(float f) {
     return (int) f;
@@ -55,7 +57,13 @@
   }-*/;
 
   public static float parseFloat(String s) throws NumberFormatException {
-    return (float) __parseAndValidateDouble(s);
+    double doubleValue = __parseAndValidateDouble(s);
+    if (doubleValue > Float.MAX_VALUE) {
+      return Float.POSITIVE_INFINITY;
+    } else if (doubleValue < -Float.MAX_VALUE) {
+      return Float.NEGATIVE_INFINITY;
+    }
+    return (float) doubleValue;
   }
 
   public static String toString(float b) {
diff --git a/user/super/com/google/gwt/emul/java/math/BigDecimal.java b/user/super/com/google/gwt/emul/java/math/BigDecimal.java
new file mode 100644
index 0000000..569918e
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/math/BigDecimal.java
@@ -0,0 +1,2979 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE.
+ */
+package java.math;
+
+import com.google.gwt.core.client.JavaScriptObject;
+
+import java.io.Serializable;
+
+/**
+ * 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}).
+ */
+public class BigDecimal extends Number implements Comparable<BigDecimal>,
+    Serializable {
+
+  /**
+   * The constant one as a {@code BigDecimal}.
+   */
+  public static final BigDecimal ONE = new BigDecimal(1, 0);
+
+  /**
+   * 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 static final int ROUND_CEILING = 2;
+
+  /**
+   * Rounding mode where the values are rounded towards zero.
+   * 
+   * @see RoundingMode#DOWN
+   */
+  public static final int ROUND_DOWN = 1;
+
+  /**
+   * 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 static final int ROUND_FLOOR = 3;
+
+  /**
+   * Rounding mode where values are rounded towards the nearest neighbor. Ties
+   * are broken by rounding down.
+   * 
+   * @see RoundingMode#HALF_DOWN
+   */
+  public static final 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 static final int ROUND_HALF_EVEN = 6;
+
+  /**
+   * Rounding mode where values are rounded towards the nearest neighbor. Ties
+   * are broken by rounding up.
+   * 
+   * @see RoundingMode#HALF_UP
+   */
+  public static final int ROUND_HALF_UP = 4;
+
+  /**
+   * 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 static final int ROUND_UNNECESSARY = 7;
+
+  /**
+   * Rounding mode where positive values are rounded towards positive infinity
+   * and negative values towards negative infinity.
+   * 
+   * @see RoundingMode#UP
+   */
+  public static final int ROUND_UP = 0;
+
+  /**
+   * The constant ten as a {@code BigDecimal}.
+   */
+  public static final BigDecimal TEN = new BigDecimal(10, 0);
+
+  /**
+   * The constant zero as a {@code BigDecimal}.
+   */
+  public static final BigDecimal ZERO = new BigDecimal(0, 0);
+
+  protected static JavaScriptObject unscaledRegex;
+
+  private static final 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 final BigDecimal BI_SCALED_BY_ZERO[] = new BigDecimal[BI_SCALED_BY_ZERO_LENGTH];
+
+  /**
+   * An array filled with characters <code>'0'</code>.
+   */
+  private static final char[] CH_ZEROS = new char[100];
+
+  private static final double[] DOUBLE_FIVE_POW = new double[] {
+      1D, 5D, 25D, 125D, 625D, 3125D, 15625D, 78125D, 390625D, 1953125D,
+      9765625D, 48828125D, 244140625D, 1220703125D, 6103515625D, 30517578125D,
+      152587890625D, 762939453125D, 3814697265625D, 19073486328125D,
+      95367431640625D, 476837158203125D, 2384185791015625D,};
+
+  private static final int[] DOUBLE_FIVE_POW_BIT_LENGTH = new int[DOUBLE_FIVE_POW.length];
+
+  /**
+   * An array with powers of ten that fit in the type <code>double</code> (
+   * <code>10^0,10^1,...,10^18</code>).
+   */
+  private static final double[] DOUBLE_TEN_POW = new double[] {
+      1D, 10D, 100D, 1000D, 10000D, 100000D, 1000000D, 10000000D, 100000000D,
+      1000000000D, 10000000000D, 100000000000D, 1000000000000D,
+      10000000000000D, 100000000000000D,};
+
+  private static final int[] DOUBLE_TEN_POW_BIT_LENGTH = new int[DOUBLE_TEN_POW.length];
+
+  /**
+   * An array with powers of five that fit in the type <code>double</code> (
+   * <code>5^0,5^1,...,5^27</code>).
+   */
+  private static final BigInteger FIVE_POW[];
+  /**
+   * The double closer to <code>Log10(2)</code>.
+   */
+  private static final double LOG10_2 = 0.3010299956639812;
+
+  /**
+   * This is the serialVersionUID used by the sun implementation.
+   */
+  private static final long serialVersionUID = 6108874887143696463L;
+
+  /**
+   * An array with powers of ten that fit in the type <code>double</code> (
+   * <code>10^0,10^1,...,10^18</code>).
+   */
+  private static final BigInteger TEN_POW[];
+
+  /**
+   * 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 final BigDecimal ZERO_SCALED_BY[] = new BigDecimal[11];
+
+  static {
+    // 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 < DOUBLE_FIVE_POW_BIT_LENGTH.length; j++) {
+      DOUBLE_FIVE_POW_BIT_LENGTH[j] = bitLength(DOUBLE_FIVE_POW[j]);
+    }
+    for (int j = 0; j < DOUBLE_TEN_POW_BIT_LENGTH.length; j++) {
+      DOUBLE_TEN_POW_BIT_LENGTH[j] = bitLength(DOUBLE_TEN_POW[j]);
+    }
+
+    // Taking the references of useful powers.
+    TEN_POW = Multiplication.bigTenPows;
+    FIVE_POW = Multiplication.bigFivePows;
+  }
+
+  /**
+   * 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 (Double.isInfinite(val) || Double.isNaN(val)) {
+      // math.03=Infinity or NaN
+      throw new NumberFormatException("Infinite or NaN"); //$NON-NLS-1$
+    }
+    return new BigDecimal(Double.toString(val));
+  }
+
+  /**
+   * 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
+   * 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);
+  }
+
+  private static BigDecimal addAndMult10(BigDecimal thisValue,
+      BigDecimal augend, double diffScale) {
+    if (diffScale < DOUBLE_TEN_POW.length
+        && Math.max(thisValue.bitLength, augend.bitLength
+            + DOUBLE_TEN_POW_BIT_LENGTH[(int) diffScale]) + 1 < 54) {
+      return valueOf(thisValue.smallValue + augend.smallValue
+          * DOUBLE_TEN_POW[(int) diffScale], thisValue.scale);
+    }
+    return new BigDecimal(thisValue.getUnscaledValue().add(
+        Multiplication.multiplyByTenPow(augend.getUnscaledValue(),
+            (int) diffScale)), thisValue.scale);
+  }
+
+  private static int bitLength(double sv) {
+    long smallValue = (long) sv;
+    if (smallValue < 0) {
+      smallValue = ~smallValue;
+    }
+    return 64 - Long.numberOfLeadingZeros(smallValue);
+  }
+
+  private static int bitLength(long smallValue) {
+    if (smallValue < 0) {
+      smallValue = ~smallValue;
+    }
+    return 64 - Long.numberOfLeadingZeros(smallValue);
+  }
+
+  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() < 54) {
+      long rem = remainder.longValue();
+      long divisor = scaledDivisor.longValue();
+      compRem = longCompareTo(Math.abs(rem) << 1, 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());
+      compRem = roundingBehavior(quotient.testBit(0) ? 1 : 0, sign
+          * (5 + compRem), roundingMode);
+    }
+    if (compRem != 0) {
+      if (quotient.bitLength() < 54) {
+        return valueOf(quotient.longValue() + compRem, scale);
+      }
+      quotient = quotient.add(BigInteger.valueOf(compRem));
+      return new BigDecimal(quotient, scale);
+    }
+    // Constructing the result with the appropriate unscaled value
+    return new BigDecimal(quotient, scale);
+  }
+
+  // TODO convert to double math dont use longs
+  private static BigDecimal dividePrimitiveLongs(long scaledDividend,
+      long scaledDivisor, int scale, RoundingMode roundingMode) {
+    long quotient = scaledDividend / scaledDivisor;
+    long remainder = scaledDividend % scaledDivisor;
+    int sign = Long.signum(scaledDividend) * Long.signum(scaledDivisor);
+    if (remainder != 0) {
+      // Checking if: remainder * 2 >= scaledDivisor
+      int compRem; // 'compare to remainder'
+      compRem = longCompareTo(Math.abs(remainder) << 1, Math.abs(scaledDivisor));
+      // To look if there is a carry
+      quotient += roundingBehavior(((int) quotient) & 1, sign * (5 + compRem),
+          roundingMode);
+    }
+    // Constructing the result with the appropriate unscaled value
+    return valueOf(quotient, scale);
+  }
+
+  private static int longCompareTo(long value1, long value2) {
+    return value1 > value2 ? 1 : (value1 < value2 ? -1 : 0);
+  }
+
+  private static native double parseUnscaled(String str) /*-{
+      var unscaledRegex = @java.math.BigDecimal::unscaledRegex;
+      if (!unscaledRegex) {
+        unscaledRegex = @java.math.BigDecimal::unscaledRegex = /^[+-]?\d*$/i;
+      }
+      if (unscaledRegex.test(str)) {
+        return parseInt(str, 10);
+      } else {
+        return Number.NaN;
+      }
+  }-*/;
+
+  /**
+   * Return an increment that can be -1,0 or 1, depending of {@code
+   * roundingMode}.
+   * 
+   * @param parityBit can be 0 or 1, it's only used in the case {@code
+   *          HALF_EVEN}
+   * @param fraction the mantisa to be analyzed
+   * @param roundingMode the type of rounding
+   * @return the carry propagated after rounding
+   */
+  private static int roundingBehavior(int parityBit, int fraction,
+      RoundingMode roundingMode) {
+    int increment = 0; // the carry after rounding
+
+    switch (roundingMode) {
+      case UNNECESSARY:
+        if (fraction != 0) {
+          // math.08=Rounding necessary
+          throw new ArithmeticException("Rounding necessary"); //$NON-NLS-1$
+        }
+        break;
+      case UP:
+        increment = Integer.signum(fraction);
+        break;
+      case DOWN:
+        break;
+      case CEILING:
+        increment = Math.max(Integer.signum(fraction), 0);
+        break;
+      case FLOOR:
+        increment = Math.min(Integer.signum(fraction), 0);
+        break;
+      case HALF_UP:
+        if (Math.abs(fraction) >= 5) {
+          increment = Integer.signum(fraction);
+        }
+        break;
+      case HALF_DOWN:
+        if (Math.abs(fraction) > 5) {
+          increment = Integer.signum(fraction);
+        }
+        break;
+      case HALF_EVEN:
+        if (Math.abs(fraction) + parityBit > 5) {
+          increment = Integer.signum(fraction);
+        }
+        break;
+    }
+    return increment;
+  }
+
+  /**
+   * It tests if a scale of type {@code long} fits in 32 bits. It returns the
+   * same scale being casted to {@code int} type when is possible, otherwise
+   * throws an exception.
+   * 
+   * @param doubleScale a double bit scale
+   * @return a 32 bit scale when is possible
+   * @throws ArithmeticException when {@code scale} doesn't fit in {@code int}
+   *           type
+   * @see #scale
+   */
+  private static int toIntScale(double doubleScale) {
+    if (doubleScale < Integer.MIN_VALUE) {
+      // math.09=Overflow
+      throw new ArithmeticException("Overflow"); //$NON-NLS-1$
+    } else if (doubleScale > Integer.MAX_VALUE) {
+      // math.0A=Underflow
+      throw new ArithmeticException("Underflow"); //$NON-NLS-1$
+    } else {
+      return (int) doubleScale;
+    }
+  }
+
+  /**
+   * Convert a double to a string with {@code digits} precision.  The resulting
+   * string may still be in exponential notation.
+   * 
+   * @param d double value
+   * @param digits number of digits of precision to include
+   * @return non-localized string representation of {@code d}
+   */
+  private static native String toPrecision(double d, int digits) /*-{
+    return d.toPrecision(digits);
+  }-*/;
+
+  private static BigDecimal valueOf(double smallValue, double scale) {
+    return new BigDecimal(smallValue, scale);
+  }
+
+  /**
+   * It returns the value 0 with the most approximated scale of type {@code int}
+   * . if {@code longScale > Integer.MAX_VALUE} the scale will be {@code
+   * Integer.MAX_VALUE}; if {@code longScale < Integer.MIN_VALUE} the scale will
+   * be {@code Integer.MIN_VALUE}; otherwise {@code longScale} is casted to the
+   * type {@code int}.
+   * 
+   * @param doubleScale the scale to which the value 0 will be scaled.
+   * @return the value 0 scaled by the closer scale of type {@code int}.
+   * @see #scale
+   */
+  private static BigDecimal zeroScaledBy(double doubleScale) {
+    if (doubleScale == (int) doubleScale) {
+      return valueOf(0, (int) doubleScale);
+    }
+    if (doubleScale >= 0) {
+      return new BigDecimal(0, Integer.MAX_VALUE);
+    }
+    return new BigDecimal(0, Integer.MIN_VALUE);
+  }
+
+  private transient int bitLength;
+
+  /**
+   * Cache for the hash code.
+   */
+  private transient int hashCode;
+
+  /**
+   * The arbitrary precision integer (unscaled value) in the internal
+   * representation of {@code BigDecimal}.
+   */
+  private BigInteger intVal;
+
+  /**
+   * 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 (Double.isInfinite(val) || Double.isNaN(val)) {
+  // // math.03=Infinity or NaN
+  //            throw new NumberFormatException("Infinite or NaN"); //$NON-NLS-1$
+  // }
+  // long bits = Double.doubleToLongBits(val); // IEEE-754
+  // long mantisa;
+  // int trailingZeros;
+  // // Extracting the exponent, note that the bias is 1023
+  // scale = 1075 - (int)((bits >> 52) & 0x7FFL);
+  // // Extracting the 52 bits of the mantisa.
+  // mantisa = (scale == 1075) ? (bits & 0xFFFFFFFFFFFFFL) << 1
+  // : (bits & 0xFFFFFFFFFFFFFL) | 0x10000000000000L;
+  // if (mantisa == 0) {
+  // scale = 0;
+  // precision = 1;
+  // }
+  // // To simplify all factors '2' in the mantisa
+  // if (scale > 0) {
+  // trailingZeros = Math.min(scale, Long.numberOfTrailingZeros(mantisa));
+  // mantisa >>>= trailingZeros;
+  // scale -= trailingZeros;
+  // }
+  // // Calculating the new unscaled value and the new scale
+  // if((bits >> 63) != 0) {
+  // mantisa = -mantisa;
+  // }
+  // int mantisaBits = bitLength(mantisa);
+  // if (scale < 0) {
+  // bitLength = mantisaBits == 0 ? 0 : mantisaBits - scale;
+  // if(bitLength < 64) {
+  // smallValue = mantisa << (-scale);
+  // } else {
+  // intVal = BigInteger.valueOf(mantisa).shiftLeft(-scale);
+  // }
+  // scale = 0;
+  // } else if (scale > 0) {
+  // // m * 2^e = (m * 5^(-e)) * 10^e
+  // if(scale < LONG_FIVE_POW.length
+  // && mantisaBits+LONG_FIVE_POW_BIT_LENGTH[scale] < 64) {
+  // smallValue = mantisa * LONG_FIVE_POW[scale];
+  // bitLength = bitLength(smallValue);
+  // } else {
+  // setUnscaledValue(Multiplication.multiplyByFivePow(BigInteger.valueOf(mantisa),
+  // scale));
+  // }
+  // } else { // scale == 0
+  // smallValue = mantisa;
+  // bitLength = 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);
+  // }
+  /**
+   * 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)
+   */
+  private transient int precision;
+
+  private double scale;
+
+  private transient double smallValue;
+
+  /**
+   * The <code>String</code> representation is cached.
+   */
+  private transient String toStringImage;
+
+  /**
+   * 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 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 NullPointerException();
+    }
+    this.scale = 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 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 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[] in) {
+    this(in, 0, in.length);
+  }
+
+  /**
+   * 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[] in, int offset, int len) {
+    try {
+      initFrom(new String(in, offset, len));
+    } catch (StringIndexOutOfBoundsException e) {
+      throw new NumberFormatException(e.getMessage());
+    }
+  }
+
+  /**
+   * 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[] in, int offset, int len, MathContext mc) {
+    this(in, offset, len);
+    inplaceRound(mc);
+  }
+
+  /**
+   * 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[] in, MathContext mc) {
+    this(in, 0, in.length);
+    inplaceRound(mc);
+  }
+
+  /**
+   * Constructs a new {@code BigDecimal} instance from the given double {@code
+   * val}. The scale of the result is 0.
+   * 
+   * @param val double value to be converted to a {@code BigDecimal} instance.
+   * @throws NumberFormatException if {@code val} is infinite or a NaN
+   */
+  public BigDecimal(double val) {
+    if (Double.isInfinite(val) || Double.isNaN(val)) {
+      // math.03=Infinity or NaN
+      throw new NumberFormatException("Infinite or NaN"); //$NON-NLS-1$
+    }
+    initFrom(toPrecision(val, 20));
+  }
+
+  /**
+   * Constructs a new {@code BigDecimal} instance from the given double {@code
+   * val}. The scale of the result is 0. The result is rounded according to the
+   * specified math context.
+   * 
+   * @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 infinite or a NaN
+   * @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) {
+    if (Double.isInfinite(val) || Double.isNaN(val)) {
+      // math.03=Infinity or NaN
+      throw new NumberFormatException("Infinite or NaN"); //$NON-NLS-1$
+    }
+    initFrom(toPrecision(val, 20));
+    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);
+  }
+
+  /**
+   * 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) {
+    initFrom(val);
+  }
+
+  /**
+   * 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);
+  }
+
+  private BigDecimal(BigInteger unscaledVal, double scale) {
+    if (unscaledVal == null) {
+      throw new NullPointerException();
+    }
+    this.scale = scale;
+    setUnscaledValue(unscaledVal);
+  }
+
+  private BigDecimal(double smallValue, double scale) {
+    this.smallValue = smallValue;
+    this.scale = scale;
+    this.bitLength = bitLength(smallValue);
+  }
+
+  private BigDecimal(long smallValue, int scale) {
+    this.scale = scale;
+    this.bitLength = bitLength(smallValue);
+    if (bitLength < 54) {
+      this.smallValue = smallValue;
+    } else {
+      this.intVal = BigInteger.valueOf(smallValue);
+    }
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} whose value is the absolute value of
+   * {@code this}. The scale of the result is the same as the scale of this.
+   * 
+   * @return {@code abs(this)}
+   */
+  public BigDecimal abs() {
+    return ((signum() < 0) ? negate() : this);
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} whose value is the absolute value of
+   * {@code this}. The result is rounded according to the passed context {@code
+   * mc}.
+   * 
+   * @param mc rounding mode and precision for the result of this operation.
+   * @return {@code abs(this)}
+   */
+  public BigDecimal abs(MathContext mc) {
+    return round(mc).abs();
+  }
+
+  /**
+   * 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) {
+    double diffScale = this.scale - augend.scale;
+    // 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 (Math.max(this.bitLength, augend.bitLength) + 1 < 54) {
+        return valueOf(this.smallValue + augend.smallValue, this.scale);
+      }
+      return new BigDecimal(this.getUnscaledValue().add(
+          augend.getUnscaledValue()), this.scale);
+    } 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);
+    }
+  }
+
+  /**
+   * 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;
+    double diffScale = 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.approxPrecision() < diffScale - 1) {
+      larger = augend;
+      smaller = this;
+    } else if (augend.approxPrecision() < -diffScale - 1) {
+      larger = this;
+      smaller = augend;
+    } else {
+      // No optimization is done
+      return add(augend).round(mc);
+    }
+    if (mc.getPrecision() >= larger.approxPrecision()) {
+      // 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);
+  }
+
+  /**
+   * Returns this {@code BigDecimal} as a byte value if it has no fractional
+   * part and if its value fits to the byte range ([-128..127]). If these
+   * conditions are not met, an {@code ArithmeticException} is thrown.
+   * 
+   * @return this {@code BigDecimal} as a byte value.
+   * @throws ArithmeticException if rounding is necessary or the number doesn't
+   *           fit in a byte.
+   */
+  public byte byteValueExact() {
+    return (byte) valueExact(8);
+  }
+
+  /**
+   * Compares this {@code BigDecimal} with {@code val}. Returns one of the three
+   * values {@code 1}, {@code 0}, or {@code -1}. The method behaves as if
+   * {@code this.subtract(val)} is computed. If this difference is > 0 then 1 is
+   * returned, if the difference is < 0 then -1 is returned, and if the
+   * difference is 0 then 0 is returned. This means, that if two decimal
+   * instances are compared which are equal in value but differ in scale, then
+   * these two instances are considered as equal.
+   * 
+   * @param val value to be compared with {@code this}.
+   * @return {@code 1} if {@code this > val}, {@code -1} if {@code this < val},
+   *         {@code 0} if {@code this == val}.
+   * @throws NullPointerException if {@code val == null}.
+   */
+  public int compareTo(BigDecimal val) {
+    int thisSign = signum();
+    int valueSign = val.signum();
+
+    if (thisSign == valueSign) {
+      if (this.scale == val.scale && this.bitLength < 54 && val.bitLength < 54) {
+        return (smallValue < val.smallValue) ? -1
+            : (smallValue > val.smallValue) ? 1 : 0;
+      }
+      double diffScale = this.scale - val.scale;
+      double diffPrecision = this.approxPrecision() - val.approxPrecision();
+      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;
+    }
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} whose value is {@code this / divisor}. The
+   * scale of the result is the difference of the scales of {@code this} and
+   * {@code divisor}. If the exact result requires more digits, then the scale
+   * is adjusted accordingly. For example, {@code 1/128 = 0.0078125} which has a
+   * scale of {@code 7} and precision {@code 5}.
+   * 
+   * @param divisor value by which {@code this} is divided.
+   * @return {@code this / divisor}.
+   * @throws NullPointerException if {@code divisor == null}.
+   * @throws ArithmeticException if {@code divisor == 0}.
+   * @throws ArithmeticException if the result cannot be represented exactly.
+   */
+  public BigDecimal divide(BigDecimal divisor) {
+    BigInteger p = this.getUnscaledValue();
+    BigInteger q = divisor.getUnscaledValue();
+    BigInteger gcd; // greatest common divisor between 'p' and 'q'
+    BigInteger quotAndRem[];
+    double diffScale = scale - divisor.scale;
+    int newScale; // the new scale for final quotient
+    int k; // number of factors "2" in 'q'
+    int l = 0; // number of factors "5" in 'q'
+    int i = 1;
+    int lastPow = FIVE_POW.length - 1;
+
+    if (divisor.isZero()) {
+      // math.04=Division by zero
+      throw new ArithmeticException("Division by zero"); //$NON-NLS-1$
+    }
+    if (p.signum() == 0) {
+      return zeroScaledBy(diffScale);
+    }
+    // To divide both by the GCD
+    gcd = p.gcd(q);
+    p = p.divide(gcd);
+    q = q.divide(gcd);
+    // To simplify all "2" factors of q, dividing by 2^k
+    k = q.getLowestSetBit();
+    q = q.shiftRight(k);
+    // To simplify all "5" factors of q, dividing by 5^l
+    do {
+      quotAndRem = q.divideAndRemainder(FIVE_POW[i]);
+      if (quotAndRem[1].signum() == 0) {
+        l += i;
+        if (i < lastPow) {
+          i++;
+        }
+        q = quotAndRem[0];
+      } else {
+        if (i == 1) {
+          break;
+        }
+        i = 1;
+      }
+    } while (true);
+    // If abs(q) != 1 then the quotient is periodic
+    if (!q.abs().equals(BigInteger.ONE)) {
+      // math.05=Non-terminating decimal expansion; no exact representable
+      // decimal result.
+      throw new ArithmeticException(
+          "Non-terminating decimal expansion; no exact representable decimal result"); //$NON-NLS-1$
+    }
+    // The sign of the is fixed and the quotient will be saved in 'p'
+    if (q.signum() < 0) {
+      p = p.negate();
+    }
+    // Checking if the new scale is out of range
+    newScale = toIntScale(diffScale + Math.max(k, l));
+    // k >= 0 and l >= 0 implies that k - l is in the 32-bit range
+    i = k - l;
+
+    p = (i > 0) ? Multiplication.multiplyByFivePow(p, i) : p.shiftLeft(-i);
+    return new BigDecimal(p, newScale);
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} whose value is {@code this / divisor}. The
+   * scale of the result is the scale of {@code this}. 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 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 scale of this.
+   */
+  public BigDecimal divide(BigDecimal divisor, int roundingMode) {
+    return divide(divisor, (int) 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}.
+   * @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 NullPointerException();
+    }
+    if (divisor.isZero()) {
+      // math.04=Division by zero
+      throw new ArithmeticException("Division by zero"); //$NON-NLS-1$
+    }
+
+    double diffScale = this.scale - divisor.scale - scale;
+    if (this.bitLength < 54 && divisor.bitLength < 54) {
+      if (diffScale == 0) {
+        return dividePrimitiveLongs((long) this.smallValue,
+            (long) divisor.smallValue, scale, roundingMode);
+      } else if (diffScale > 0) {
+        if (diffScale < DOUBLE_TEN_POW.length
+            && divisor.bitLength + DOUBLE_TEN_POW_BIT_LENGTH[(int) diffScale] < 54) {
+          return dividePrimitiveLongs((long) this.smallValue,
+              (long) (divisor.smallValue * DOUBLE_TEN_POW[(int) diffScale]),
+              scale, roundingMode);
+        }
+      } else { // diffScale < 0
+        if (-diffScale < DOUBLE_TEN_POW.length
+            && this.bitLength + DOUBLE_TEN_POW_BIT_LENGTH[(int) -diffScale] < 54) {
+          return dividePrimitiveLongs(
+              (long) (this.smallValue * DOUBLE_TEN_POW[(int) -diffScale]),
+              (long) 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);
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} whose value is {@code this / divisor}. The
+   * result is rounded according to the passed context {@code mc}. If the passed
+   * math context specifies precision {@code 0}, then this call is equivalent to
+   * {@code this.divide(divisor)}.
+   * 
+   * @param divisor value by which {@code this} is divided.
+   * @param mc rounding mode and precision for the result of this operation.
+   * @return {@code this / divisor}.
+   * @throws NullPointerException if {@code divisor == null} or {@code mc ==
+   *           null}.
+   * @throws ArithmeticException if {@code divisor == 0}.
+   * @throws ArithmeticException if {@code mc.getRoundingMode() == UNNECESSARY}
+   *           and rounding is necessary according {@code mc.getPrecision()}.
+   */
+  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
+     */
+    double traillingZeros = mc.getPrecision() + 2L + divisor.approxPrecision()
+        - approxPrecision();
+    double diffScale = scale - divisor.scale;
+    double 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);
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} whose value is {@code this / divisor}. The
+   * scale of the result is the scale of {@code this}. 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 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.UNNECESSARY} and rounding is necessary according to
+   *           the scale of this.
+   */
+  public BigDecimal divide(BigDecimal divisor, RoundingMode roundingMode) {
+    return divide(divisor, (int) scale, roundingMode);
+  }
+
+  /**
+   * Returns a {@code BigDecimal} array which contains the integral part of
+   * {@code this / divisor} at index 0 and the remainder {@code this % divisor}
+   * at index 1. The quotient is rounded down towards zero to the next integer.
+   * 
+   * @param divisor value by which {@code this} is divided.
+   * @return {@code [this.divideToIntegralValue(divisor),
+   *         this.remainder(divisor)]}.
+   * @throws NullPointerException if {@code divisor == null}.
+   * @throws ArithmeticException if {@code divisor == 0}.
+   * @see #divideToIntegralValue
+   * @see #remainder
+   */
+  public BigDecimal[] divideAndRemainder(BigDecimal divisor) {
+    BigDecimal quotAndRem[] = new BigDecimal[2];
+
+    quotAndRem[0] = this.divideToIntegralValue(divisor);
+    quotAndRem[1] = this.subtract(quotAndRem[0].multiply(divisor));
+    return quotAndRem;
+  }
+
+  /**
+   * Returns a {@code BigDecimal} array which contains the integral part of
+   * {@code this / divisor} at index 0 and the remainder {@code this % divisor}
+   * at index 1. The quotient is rounded down towards zero to the next integer.
+   * The rounding mode passed with the parameter {@code mc} is not considered.
+   * But if the precision of {@code mc > 0} and the integral part requires more
+   * digits, then an {@code ArithmeticException} is thrown.
+   * 
+   * @param divisor value by which {@code this} is divided.
+   * @param mc math context which determines the maximal precision of the
+   *          result.
+   * @return {@code [this.divideToIntegralValue(divisor),
+   *         this.remainder(divisor)]}.
+   * @throws NullPointerException if {@code divisor == null}.
+   * @throws ArithmeticException if {@code divisor == 0}.
+   * @see #divideToIntegralValue
+   * @see #remainder
+   */
+  public BigDecimal[] divideAndRemainder(BigDecimal divisor, MathContext mc) {
+    BigDecimal quotAndRem[] = new BigDecimal[2];
+
+    quotAndRem[0] = this.divideToIntegralValue(divisor, mc);
+    quotAndRem[1] = this.subtract(quotAndRem[0].multiply(divisor));
+    return quotAndRem;
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} whose value is the integral part of
+   * {@code this / divisor}. The quotient is rounded down towards zero to the
+   * next integer. For example, {@code 0.5/0.2 = 2}.
+   * 
+   * @param divisor value by which {@code this} is divided.
+   * @return integral part of {@code this / divisor}.
+   * @throws NullPointerException if {@code divisor == null}.
+   * @throws ArithmeticException if {@code divisor == 0}.
+   */
+  public BigDecimal divideToIntegralValue(BigDecimal divisor) {
+    BigInteger integralValue; // the integer of result
+    BigInteger powerOfTen; // some power of ten
+    BigInteger quotAndRem[] = {getUnscaledValue()};
+    double newScale = this.scale - divisor.scale;
+    double tempScale = 0;
+    int i = 1;
+    int lastPow = TEN_POW.length - 1;
+
+    if (divisor.isZero()) {
+      // math.04=Division by zero
+      throw new ArithmeticException("Division by zero"); //$NON-NLS-1$
+    }
+    if ((divisor.approxPrecision() + newScale > this.approxPrecision() + 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)));
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} whose value is the integral part of
+   * {@code this / divisor}. The quotient is rounded down towards zero to the
+   * next integer. The rounding mode passed with the parameter {@code mc} is not
+   * considered. But if the precision of {@code mc > 0} and the integral part
+   * requires more digits, then an {@code ArithmeticException} is thrown.
+   * 
+   * @param divisor value by which {@code this} is divided.
+   * @param mc math context which determines the maximal precision of the
+   *          result.
+   * @return integral part of {@code this / divisor}.
+   * @throws NullPointerException if {@code divisor == null} or {@code mc ==
+   *           null}.
+   * @throws ArithmeticException if {@code divisor == 0}.
+   * @throws ArithmeticException if {@code mc.getPrecision() > 0} and the result
+   *           requires more digits to be represented.
+   */
+  public BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc) {
+    int mcPrecision = mc.getPrecision();
+    int diffPrecision = this.precision() - divisor.precision();
+    int lastPow = TEN_POW.length - 1;
+    double diffScale = this.scale - divisor.scale;
+    double newScale = diffScale;
+    double quotPrecision = diffPrecision - diffScale + 1;
+    BigInteger quotAndRem[] = new BigInteger[2];
+    // In special cases it call the dual method
+    if ((mcPrecision == 0) || (this.isZero()) || (divisor.isZero())) {
+      return this.divideToIntegralValue(divisor);
+    }
+    // Let be: this = [u1,s1] and divisor = [u2,s2]
+    if (quotPrecision <= 0) {
+      quotAndRem[0] = BigInteger.ZERO;
+    } else if (diffScale == 0) {
+      // CASE s1 == s2: to calculate u1 / u2
+      quotAndRem[0] = this.getUnscaledValue().divide(divisor.getUnscaledValue());
+    } else if (diffScale > 0) {
+      // CASE s1 >= s2: to calculate u1 / (u2 * 10^(s1-s2)
+      quotAndRem[0] = this.getUnscaledValue().divide(
+          divisor.getUnscaledValue().multiply(
+              Multiplication.powerOf10(diffScale)));
+      // To chose 10^newScale to get a quotient with at least 'mc.precision()'
+      // digits
+      newScale = Math.min(diffScale, Math.max(mcPrecision - quotPrecision + 1,
+          0));
+      // To calculate: (u1 / (u2 * 10^(s1-s2)) * 10^newScale
+      quotAndRem[0] = quotAndRem[0].multiply(Multiplication.powerOf10(newScale));
+    } else {
+      // CASE s2 > s1:
+      /*
+       * To calculate the minimum power of ten, such that the quotient (u1 *
+       * 10^exp) / u2 has at least 'mc.precision()' digits.
+       */
+      double exp = Math.min(-diffScale, Math.max((double) mcPrecision
+          - diffPrecision, 0));
+      double compRemDiv;
+      // Let be: (u1 * 10^exp) / u2 = [q,r]
+      quotAndRem = this.getUnscaledValue().multiply(
+          Multiplication.powerOf10(exp)).divideAndRemainder(
+          divisor.getUnscaledValue());
+      newScale += exp; // To fix the scale
+      exp = -newScale; // The remaining power of ten
+      // If after division there is a remainder...
+      if ((quotAndRem[1].signum() != 0) && (exp > 0)) {
+        // Log10(r) + ((s2 - s1) - exp) > mc.precision ?
+        compRemDiv = (new BigDecimal(quotAndRem[1])).precision() + exp
+            - divisor.precision();
+        if (compRemDiv == 0) {
+          // To calculate: (r * 10^exp2) / u2
+          quotAndRem[1] = quotAndRem[1].multiply(Multiplication.powerOf10(exp)).divide(
+              divisor.getUnscaledValue());
+          compRemDiv = Math.abs(quotAndRem[1].signum());
+        }
+        if (compRemDiv > 0) {
+          // The quotient won't fit in 'mc.precision()' digits
+          // math.06=Division impossible
+          throw new ArithmeticException("Division impossible"); //$NON-NLS-1$
+        }
+      }
+    }
+    // Fast return if the quotient is zero
+    if (quotAndRem[0].signum() == 0) {
+      return zeroScaledBy(diffScale);
+    }
+    BigInteger strippedBI = quotAndRem[0];
+    BigDecimal integralValue = new BigDecimal(quotAndRem[0]);
+    int resultPrecision = integralValue.precision();
+    int i = 1;
+    // To strip trailing zeros until the specified precision is reached
+    while (!strippedBI.testBit(0)) {
+      quotAndRem = strippedBI.divideAndRemainder(TEN_POW[i]);
+      if ((quotAndRem[1].signum() == 0)
+          && ((resultPrecision - i >= mcPrecision) || (newScale - i >= diffScale))) {
+        resultPrecision -= i;
+        newScale -= i;
+        if (i < lastPow) {
+          i++;
+        }
+        strippedBI = quotAndRem[0];
+      } else {
+        if (i == 1) {
+          break;
+        }
+        i = 1;
+      }
+    }
+    // To check if the result fit in 'mc.precision()' digits
+    if (resultPrecision > mcPrecision) {
+      // math.06=Division impossible
+      throw new ArithmeticException("Division impossible"); //$NON-NLS-1$
+    }
+    integralValue.scale = toIntScale(newScale);
+    integralValue.setUnscaledValue(strippedBI);
+    return integralValue;
+  }
+
+  /**
+   * Returns this {@code BigDecimal} as a double value. If {@code this} is too
+   * big to be represented as an float, then {@code Double.POSITIVE_INFINITY} or
+   * {@code Double.NEGATIVE_INFINITY} is returned.
+   * <p>
+   * Note, that if the unscaled value has more than 53 significant digits, then
+   * this decimal cannot be represented exactly in a double variable. In this
+   * case the result is rounded.
+   * <p>
+   * For example, if the instance {@code x1 = new BigDecimal("0.1")} cannot be
+   * represented exactly as a double, and thus {@code x1.equals(new
+   * BigDecimal(x1.doubleValue())} returns {@code false} for this case.
+   * <p>
+   * Similarly, if the instance {@code new BigDecimal(9007199254740993L)} is
+   * converted to a double, the result is {@code 9.007199254740992E15}.
+   * <p>
+   * 
+   * @return this {@code BigDecimal} as a double value.
+   */
+  @Override
+  public double doubleValue() {
+    return Double.parseDouble(this.toString());
+  }
+
+  /**
+   * Returns {@code true} if {@code x} is a {@code BigDecimal} instance and if
+   * this instance is equal to this big decimal. Two big decimals are equal if
+   * their unscaled value and their scale is equal. For example, 1.0
+   * (10*10^(-1)) is not equal to 1.00 (100*10^(-2)). Similarly, zero instances
+   * are not equal if their scale differs.
+   * 
+   * @param x object to be compared with {@code this}.
+   * @return true if {@code x} is a {@code BigDecimal} and {@code this == x}.
+   */
+  @Override
+  public boolean equals(Object x) {
+    if (this == x) {
+      return true;
+    }
+    if (x instanceof BigDecimal) {
+      BigDecimal x1 = (BigDecimal) x;
+      return x1.scale == scale
+          && (bitLength < 54 ? (x1.smallValue == smallValue)
+              : intVal.equals(x1.intVal));
+    }
+    return false;
+  }
+
+  // @Override
+  // public double doubleValue() {
+  // int sign = signum();
+  // int exponent = 1076; // bias + 53
+  // int lowestSetBit;
+  // int discardedSize;
+  // long powerOfTwo = this.bitLength - (long)(scale / LOG10_2);
+  // long bits; // IEEE-754 Standard
+  // long tempBits; // for temporal calculations
+  // BigInteger mantisa;
+  //
+  // if ((powerOfTwo < -1074) || (sign == 0)) {
+  // // Cases which 'this' is very small
+  // return (sign * 0.0d);
+  // } else if (powerOfTwo > 1025) {
+  // // Cases which 'this' is very large
+  // return (sign * Double.POSITIVE_INFINITY);
+  // }
+  // mantisa = getUnscaledValue().abs();
+  // // Let be: this = [u,s], with s > 0
+  // if (scale <= 0) {
+  // // mantisa = abs(u) * 10^s
+  // mantisa = mantisa.multiply(Multiplication.powerOf10(-scale));
+  // } else {// (scale > 0)
+  // BigInteger quotAndRem[];
+  // BigInteger powerOfTen = Multiplication.powerOf10(scale);
+  // int k = 100 - (int)powerOfTwo;
+  // int compRem;
+  //
+  // if (k > 0) {
+  // /* Computing (mantisa * 2^k) , where 'k' is a enough big
+  // * power of '2' to can divide by 10^s */
+  // mantisa = mantisa.shiftLeft(k);
+  // exponent -= k;
+  // }
+  // // Computing (mantisa * 2^k) / 10^s
+  // quotAndRem = mantisa.divideAndRemainder(powerOfTen);
+  // // To check if the fractional part >= 0.5
+  // compRem = quotAndRem[1].shiftLeftOneBit().compareTo(powerOfTen);
+  // // To add two rounded bits at end of mantisa
+  // mantisa = quotAndRem[0].shiftLeft(2).add(
+  // BigInteger.valueOf((compRem * (compRem + 3)) / 2 + 1));
+  // exponent -= 2;
+  // }
+  // lowestSetBit = mantisa.getLowestSetBit();
+  // discardedSize = mantisa.bitLength() - 54;
+  // if (discardedSize > 0) {// (n > 54)
+  // // mantisa = (abs(u) * 10^s) >> (n - 54)
+  // bits = mantisa.shiftRight(discardedSize).longValue();
+  // tempBits = bits;
+  // // #bits = 54, to check if the discarded fraction produces a carry
+  // if ((((bits & 1) == 1) && (lowestSetBit < discardedSize))
+  // || ((bits & 3) == 3)) {
+  // bits += 2;
+  // }
+  // } else {// (n <= 54)
+  // // mantisa = (abs(u) * 10^s) << (54 - n)
+  // bits = mantisa.longValue() << -discardedSize;
+  // tempBits = bits;
+  // // #bits = 54, to check if the discarded fraction produces a carry:
+  // if ((bits & 3) == 3) {
+  // bits += 2;
+  // }
+  // }
+  // // Testing bit 54 to check if the carry creates a new binary digit
+  // if ((bits & 0x40000000000000L) == 0) {
+  // // To drop the last bit of mantisa (first discarded)
+  // bits >>= 1;
+  // // exponent = 2^(s-n+53+bias)
+  // exponent += discardedSize;
+  // } else {// #bits = 54
+  // bits >>= 2;
+  // exponent += discardedSize + 1;
+  // }
+  // // To test if the 53-bits number fits in 'double'
+  // if (exponent > 2046) {// (exponent - bias > 1023)
+  // return (sign * Double.POSITIVE_INFINITY);
+  // } else if (exponent <= 0) {// (exponent - bias <= -1023)
+  // // Denormalized numbers (having exponent == 0)
+  // if (exponent < -53) {// exponent - bias < -1076
+  // return (sign * 0.0d);
+  // }
+  // // -1076 <= exponent - bias <= -1023
+  // // To discard '- exponent + 1' bits
+  // bits = tempBits >> 1;
+  // tempBits = bits & (-1L >>> (63 + exponent));
+  // bits >>= (-exponent );
+  // // To test if after discard bits, a new carry is generated
+  // if (((bits & 3) == 3) || (((bits & 1) == 1) && (tempBits != 0)
+  // && (lowestSetBit < discardedSize))) {
+  // bits += 1;
+  // }
+  // exponent = 0;
+  // bits >>= 1;
+  // }
+  // // Construct the 64 double bits: [sign(1), exponent(11), mantisa(52)]
+  // bits = (sign & 0x8000000000000000L) | ((long)exponent << 52)
+  // | (bits & 0xFFFFFFFFFFFFFL);
+  // return Double.longBitsToDouble(bits);
+  // }
+
+  /**
+   * Returns this {@code BigDecimal} as a float value. If {@code this} is too
+   * big to be represented as an float, then {@code Float.POSITIVE_INFINITY} or
+   * {@code Float.NEGATIVE_INFINITY} is returned.
+   * <p>
+   * Note, that if the unscaled value has more than 24 significant digits, then
+   * this decimal cannot be represented exactly in a float variable. In this
+   * case the result is rounded.
+   * <p>
+   * For example, if the instance {@code x1 = new BigDecimal("0.1")} cannot be
+   * represented exactly as a float, and thus {@code x1.equals(new
+   * BigDecimal(x1.folatValue())} returns {@code false} for this case.
+   * <p>
+   * Similarly, if the instance {@code new BigDecimal(16777217)} is converted to
+   * a float, the result is {@code 1.6777216E}7.
+   * 
+   * @return this {@code BigDecimal} as a float value.
+   */
+  @Override
+  public float floatValue() {
+    /*
+     * A similar code like in doubleValue() could be repeated here, but this
+     * simple implementation is quite efficient.
+     */
+    float floatResult = signum();
+    double powerOfTwo = this.bitLength - (scale / LOG10_2);
+    if ((powerOfTwo < -149) || (floatResult == 0.0f)) {
+      // Cases which 'this' is very small
+      floatResult *= 0.0f;
+    } else if (powerOfTwo > 129) {
+      // Cases which 'this' is very large
+      floatResult *= Float.POSITIVE_INFINITY;
+    } else {
+      floatResult = (float) doubleValue();
+    }
+    return floatResult;
+  }
+
+  /**
+   * Returns a hash code for this {@code BigDecimal}.
+   * 
+   * @return hash code for {@code this}.
+   */
+  @Override
+  public int hashCode() {
+    if (hashCode != 0) {
+      return hashCode;
+    }
+    if (bitLength < 54) {
+      long longValue = (long) smallValue;
+      hashCode = (int) (longValue & 0xffffffff);
+      hashCode = 33 * hashCode + (int) ((longValue >> 32) & 0xffffffff);
+      hashCode = 17 * hashCode + (int) scale;
+      return hashCode;
+    }
+    hashCode = 17 * intVal.hashCode() + (int) scale;
+    return hashCode;
+  }
+
+  /**
+   * Returns this {@code BigDecimal} as an int value. Any fractional part is
+   * discarded. If the integral part of {@code this} is too big to be
+   * represented as an int, then {@code this} % 2^32 is returned.
+   * 
+   * @return this {@code BigDecimal} as a int value.
+   */
+  @Override
+  public int intValue() {
+    /*
+     * If scale <= -32 there are at least 32 trailing bits zero in 10^(-scale).
+     * If the scale is positive and very large the long value could be zero.
+     */
+    return ((scale <= -32) || (scale > approxPrecision()) ? 0
+        : toBigInteger().intValue());
+  }
+
+  /**
+   * Returns this {@code BigDecimal} as a int value if it has no fractional part
+   * and if its value fits to the int range ([-2^{31}..2^{31}-1]). If these
+   * conditions are not met, an {@code ArithmeticException} is thrown.
+   * 
+   * @return this {@code BigDecimal} as a int value.
+   * @throws ArithmeticException if rounding is necessary or the number doesn't
+   *           fit in a int.
+   */
+  public int intValueExact() {
+    return (int) valueExact(32);
+  }
+
+  /**
+   * Returns this {@code BigDecimal} as an long value. Any fractional part is
+   * discarded. If the integral part of {@code this} is too big to be
+   * represented as an long, then {@code this} % 2^64 is returned.
+   * 
+   * @return this {@code BigDecimal} as a long value.
+   */
+  @Override
+  public long longValue() {
+    /*
+     * If scale <= -64 there are at least 64 trailing bits zero in 10^(-scale).
+     * If the scale is positive and very large the long value could be zero.
+     */
+    return ((scale <= -64) || (scale > approxPrecision()) ? 0L
+        : toBigInteger().longValue());
+  }
+
+  /**
+   * Returns this {@code BigDecimal} as a long value if it has no fractional
+   * part and if its value fits to the int range ([-2^{63}..2^{63}-1]). If these
+   * conditions are not met, an {@code ArithmeticException} is thrown.
+   * 
+   * @return this {@code BigDecimal} as a long value.
+   * @throws ArithmeticException if rounding is necessary or the number doesn't
+   *           fit in a long.
+   */
+  public long longValueExact() {
+    return valueExact(64);
+  }
+
+  /**
+   * Returns the maximum of this {@code BigDecimal} and {@code val}.
+   * 
+   * @param val value to be used to compute the maximum with this.
+   * @return {@code max(this, val}.
+   * @throws NullPointerException if {@code val == null}.
+   */
+  public BigDecimal max(BigDecimal val) {
+    return ((compareTo(val) >= 0) ? this : val);
+  }
+
+  /**
+   * Returns the minimum of this {@code BigDecimal} and {@code val}.
+   * 
+   * @param val value to be used to compute the minimum with this.
+   * @return {@code min(this, val}.
+   * @throws NullPointerException if {@code val == null}.
+   */
+  public BigDecimal min(BigDecimal val) {
+    return ((compareTo(val) <= 0) ? this : val);
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} instance where the decimal point has been
+   * moved {@code n} places to the left. If {@code n < 0} then the decimal point
+   * is moved {@code -n} places to the right.
+   * <p>
+   * The result is obtained by changing its scale. If the scale of the result
+   * becomes negative, then its precision is increased such that the scale is
+   * zero.
+   * <p>
+   * Note, that {@code movePointLeft(0)} returns a result which is
+   * mathematically equivalent, but which has {@code scale >= 0}.
+   * 
+   * @param n number of placed the decimal point has to be moved.
+   * @return {@code this * 10^(-n}).
+   */
+  public BigDecimal movePointLeft(int n) {
+    return movePoint(scale + n);
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} instance where the decimal point has been
+   * moved {@code n} places to the right. If {@code n < 0} then the decimal
+   * point is moved {@code -n} places to the left.
+   * <p>
+   * The result is obtained by changing its scale. If the scale of the result
+   * becomes negative, then its precision is increased such that the scale is
+   * zero.
+   * <p>
+   * Note, that {@code movePointRight(0)} returns a result which is
+   * mathematically equivalent, but which has scale >= 0.
+   * 
+   * @param n number of placed the decimal point has to be moved.
+   * @return {@code this * 10^n}.
+   */
+  public BigDecimal movePointRight(int n) {
+    return movePoint(scale - n);
+  }
+
+  /**
+   * 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) {
+    double newScale = this.scale + multiplicand.scale;
+
+    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.bitLength + multiplicand.bitLength < 54) {
+      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 the {@code -this}. The
+   * scale of the result is the same as the scale of this.
+   * 
+   * @return {@code -this}
+   */
+  public BigDecimal negate() {
+    if (bitLength < 54) {
+      return valueOf(-smallValue, scale);
+    }
+    return new BigDecimal(getUnscaledValue().negate(), scale);
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} whose value is the {@code -this}. The
+   * result is rounded according to the passed context {@code mc}.
+   * 
+   * @param mc rounding mode and precision for the result of this operation.
+   * @return {@code -this}
+   */
+  public BigDecimal negate(MathContext mc) {
+    return round(mc).negate();
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} whose value is {@code +this}. The scale of
+   * the result is the same as the scale of this.
+   * 
+   * @return {@code this}
+   */
+  public BigDecimal plus() {
+    return this;
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} whose value is {@code +this}. The result
+   * is rounded according to the passed context {@code mc}.
+   * 
+   * @param mc rounding mode and precision for the result of this operation.
+   * @return {@code this}, rounded
+   */
+  public BigDecimal plus(MathContext mc) {
+    return round(mc);
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} whose value is {@code this ^ n}. The scale
+   * of the result is {@code n} times the scales of {@code this}.
+   * <p>
+   * {@code x.pow(0)} returns {@code 1}, even if {@code x == 0}.
+   * <p>
+   * Implementation Note: The implementation is based on the ANSI standard
+   * X3.274-1996 algorithm.
+   * 
+   * @param n exponent to which {@code this} is raised.
+   * @return {@code this ^ n}.
+   * @throws ArithmeticException if {@code n < 0} or {@code n > 999999999}.
+   */
+  public BigDecimal pow(int n) {
+    if (n == 0) {
+      return ONE;
+    }
+    if ((n < 0) || (n > 999999999)) {
+      // math.07=Invalid Operation
+      throw new ArithmeticException("Invalid Operation"); //$NON-NLS-1$
+    }
+    double newScale = scale * n;
+    // Let be: this = [u,s] so: this^n = [u^n, s*n]
+    return ((isZero()) ? zeroScaledBy(newScale) : new BigDecimal(
+        getUnscaledValue().pow(n), toIntScale(newScale)));
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} whose value is {@code this ^ n}. The
+   * result is rounded according to the passed context {@code mc}.
+   * <p>
+   * Implementation Note: The implementation is based on the ANSI standard
+   * X3.274-1996 algorithm.
+   * 
+   * @param n exponent to which {@code this} is raised.
+   * @param mc rounding mode and precision for the result of this operation.
+   * @return {@code this ^ n}.
+   * @throws ArithmeticException if {@code n < 0} or {@code n > 999999999}.
+   */
+  public BigDecimal pow(int n, MathContext mc) {
+    // The ANSI standard X3.274-1996 algorithm
+    int m = Math.abs(n);
+    int mcPrecision = mc.getPrecision();
+    int elength = (int) Math.log10(m) + 1; // decimal digits in 'n'
+    int oneBitMask; // mask of bits
+    BigDecimal accum; // the single accumulator
+    MathContext newPrecision = mc; // MathContext by default
+
+    // In particular cases, it reduces the problem to call the other 'pow()'
+    if ((n == 0) || ((isZero()) && (n > 0))) {
+      return pow(n);
+    }
+    if ((m > 999999999) || ((mcPrecision == 0) && (n < 0))
+        || ((mcPrecision > 0) && (elength > mcPrecision))) {
+      // math.07=Invalid Operation
+      throw new ArithmeticException("Invalid Operation"); //$NON-NLS-1$
+    }
+    if (mcPrecision > 0) {
+      newPrecision = new MathContext(mcPrecision + elength + 1,
+          mc.getRoundingMode());
+    }
+    // The result is calculated as if 'n' were positive
+    accum = round(newPrecision);
+    oneBitMask = Integer.highestOneBit(m) >> 1;
+
+    while (oneBitMask > 0) {
+      accum = accum.multiply(accum, newPrecision);
+      if ((m & oneBitMask) == oneBitMask) {
+        accum = accum.multiply(this, newPrecision);
+      }
+      oneBitMask >>= 1;
+    }
+    // If 'n' is negative, the value is divided into 'ONE'
+    if (n < 0) {
+      accum = ONE.divide(accum, newPrecision);
+    }
+    // The final value is rounded to the destination precision
+    accum.inplaceRound(mc);
+    return accum;
+  }
+
+  /**
+   * Returns the precision of this {@code BigDecimal}. The precision is the
+   * number of decimal digits used to represent this decimal. It is equivalent
+   * to the number of digits of the unscaled value. The precision of {@code 0}
+   * is {@code 1} (independent of the scale).
+   * 
+   * @return the precision of this {@code BigDecimal}.
+   */
+  public int precision() {
+    // Checking if the precision already was calculated
+    if (precision > 0) {
+      return precision;
+    }
+    int decimalDigits = 1; // the precision to be calculated
+    double doubleUnsc = 1; // intVal in 'double'
+
+    if (bitLength < 1024) {
+      // To calculate the precision for small numbers
+      if (bitLength >= 54) {
+        doubleUnsc = getUnscaledValue().doubleValue();
+      } else if (bitLength >= 1) {
+        doubleUnsc = smallValue;
+      }
+      decimalDigits += (int) Math.log10(Math.abs(doubleUnsc));
+    } else {
+      // (bitLength >= 1024)
+      /*
+       * To calculate the precision for large numbers Note that: 2 ^(bitlength()
+       * - 1) <= intVal < 10 ^(precision())
+       */
+      decimalDigits += (bitLength - 1) * LOG10_2;
+      // If after division the number isn't zero, exists an aditional digit
+      if (getUnscaledValue().divide(Multiplication.powerOf10(decimalDigits)).signum() != 0) {
+        decimalDigits++;
+      }
+    }
+    precision = decimalDigits;
+    return precision;
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} whose value is {@code this % divisor}.
+   * <p>
+   * The remainder is defined as {@code this -
+   * this.divideToIntegralValue(divisor) * divisor}.
+   * 
+   * @param divisor value by which {@code this} is divided.
+   * @return {@code this % divisor}.
+   * @throws NullPointerException if {@code divisor == null}.
+   * @throws ArithmeticException if {@code divisor == 0}.
+   */
+  public BigDecimal remainder(BigDecimal divisor) {
+    return divideAndRemainder(divisor)[1];
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} whose value is {@code this % divisor}.
+   * <p>
+   * The remainder is defined as {@code this -
+   * this.divideToIntegralValue(divisor) * divisor}.
+   * <p>
+   * The specified rounding mode {@code mc} is used for the division only.
+   * 
+   * @param divisor value by which {@code this} is divided.
+   * @param mc rounding mode and precision to be used.
+   * @return {@code this % divisor}.
+   * @throws NullPointerException if {@code divisor == null}.
+   * @throws ArithmeticException if {@code divisor == 0}.
+   * @throws ArithmeticException if {@code mc.getPrecision() > 0} and the result
+   *           of {@code this.divideToIntegralValue(divisor, mc)} requires more
+   *           digits to be represented.
+   */
+  public BigDecimal remainder(BigDecimal divisor, MathContext mc) {
+    return divideAndRemainder(divisor, mc)[1];
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} whose value is {@code this}, rounded
+   * according to the passed context {@code mc}.
+   * <p>
+   * If {@code mc.precision = 0}, then no rounding is performed.
+   * <p>
+   * If {@code mc.precision > 0} and {@code mc.roundingMode == UNNECESSARY},
+   * then an {@code ArithmeticException} is thrown if the result cannot be
+   * represented exactly within the given precision.
+   * 
+   * @param mc rounding mode and precision for the result of this operation.
+   * @return {@code this} rounded according to the passed context.
+   * @throws ArithmeticException if {@code mc.precision > 0} and {@code
+   *           mc.roundingMode == UNNECESSARY} and this cannot be represented
+   *           within the given precision.
+   */
+  public BigDecimal round(MathContext mc) {
+    BigDecimal thisBD = new BigDecimal(getUnscaledValue(), scale);
+
+    thisBD.inplaceRound(mc);
+    return thisBD;
+  }
+
+  /**
+   * Returns the scale of this {@code BigDecimal}. The scale is the number of
+   * digits behind the decimal point. The value of this {@code BigDecimal} is
+   * the unsignedValue * 10^(-scale). If the scale is negative, then this
+   * {@code BigDecimal} represents a big integer.
+   * 
+   * @return the scale of this {@code BigDecimal}.
+   */
+  public int scale() {
+    return (int) scale;
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} whose value is {@code this} 10^{@code n}.
+   * The scale of the result is {@code this.scale()} - {@code n}. The precision
+   * of the result is the precision of {@code this}.
+   * <p>
+   * This method has the same effect as {@link #movePointRight}, except that the
+   * precision is not changed.
+   * 
+   * @param n number of places the decimal point has to be moved.
+   * @return {@code this * 10^n}
+   */
+  public BigDecimal scaleByPowerOfTen(int n) {
+    double newScale = scale - n;
+    if (bitLength < 54) {
+      // Taking care when a 0 is to be scaled
+      if (smallValue == 0) {
+        return zeroScaledBy(newScale);
+      }
+      return valueOf(smallValue, toIntScale(newScale));
+    }
+    return new BigDecimal(getUnscaledValue(), toIntScale(newScale));
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} instance with the specified scale. If the
+   * new scale is greater than the old scale, then additional zeros are added to
+   * the unscaled value. If the new scale is smaller than the old scale, then
+   * trailing zeros are removed. If the trailing digits are not zeros then an
+   * ArithmeticException is thrown.
+   * <p>
+   * If no exception is thrown, then the following equation holds: {@code
+   * x.setScale(s).compareTo(x) == 0}.
+   * 
+   * @param newScale scale of the result returned.
+   * @return a new {@code BigDecimal} instance with the specified scale.
+   * @throws ArithmeticException if rounding would be necessary.
+   */
+  public BigDecimal setScale(int newScale) {
+    return setScale(newScale, RoundingMode.UNNECESSARY);
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} instance with the specified scale.
+   * <p>
+   * If the new scale is greater than the old scale, then additional zeros are
+   * added to the unscaled value. In this case no rounding is necessary.
+   * <p>
+   * If the new scale is smaller than the old scale, then trailing digits are
+   * removed. If these trailing digits are not zero, then the remaining unscaled
+   * value has to be rounded. For this rounding operation the specified rounding
+   * mode is used.
+   * 
+   * @param newScale scale of the result returned.
+   * @param roundingMode rounding mode to be used to round the result.
+   * @return a new {@code BigDecimal} instance with the specified scale.
+   * @throws IllegalArgumentException if {@code roundingMode} is not a valid
+   *           rounding mode.
+   * @throws ArithmeticException if {@code roundingMode == ROUND_UNNECESSARY}
+   *           and rounding is necessary according to the given scale.
+   */
+  public BigDecimal setScale(int newScale, int roundingMode) {
+    return setScale(newScale, RoundingMode.valueOf(roundingMode));
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} instance with the specified scale.
+   * <p>
+   * If the new scale is greater than the old scale, then additional zeros are
+   * added to the unscaled value. In this case no rounding is necessary.
+   * <p>
+   * If the new scale is smaller than the old scale, then trailing digits are
+   * removed. If these trailing digits are not zero, then the remaining unscaled
+   * value has to be rounded. For this rounding operation the specified rounding
+   * mode is used.
+   * 
+   * @param newScale scale of the result returned.
+   * @param roundingMode rounding mode to be used to round the result.
+   * @return a new {@code BigDecimal} instance with the specified scale.
+   * @throws NullPointerException if {@code roundingMode == null}.
+   * @throws ArithmeticException if {@code roundingMode == ROUND_UNNECESSARY}
+   *           and rounding is necessary according to the given scale.
+   */
+  public BigDecimal setScale(int newScale, RoundingMode roundingMode) {
+    if (roundingMode == null) {
+      throw new NullPointerException();
+    }
+    double diffScale = newScale - scale;
+    // Let be: 'this' = [u,s]
+    if (diffScale == 0) {
+      return this;
+    }
+    if (diffScale > 0) {
+      // return [u * 10^(s2 - s), newScale]
+      if (diffScale < DOUBLE_TEN_POW.length
+          && (this.bitLength + DOUBLE_TEN_POW_BIT_LENGTH[(int) diffScale]) < 54) {
+        return valueOf(this.smallValue * DOUBLE_TEN_POW[(int) diffScale],
+            newScale);
+      }
+      return new BigDecimal(Multiplication.multiplyByTenPow(getUnscaledValue(),
+          (int) diffScale), newScale);
+    }
+    // diffScale < 0
+    // return [u,s] / [1,newScale] with the appropriate scale and rounding
+    if (this.bitLength < 54 && -diffScale < DOUBLE_TEN_POW.length) {
+      return dividePrimitiveLongs((long) this.smallValue,
+          (long) DOUBLE_TEN_POW[(int) -diffScale], newScale, roundingMode);
+    }
+    return divideBigIntegers(this.getUnscaledValue(),
+        Multiplication.powerOf10(-diffScale), newScale, roundingMode);
+  }
+
+  /**
+   * Returns this {@code BigDecimal} as a short value if it has no fractional
+   * part and if its value fits to the short range ([-2^{15}..2^{15}-1]). If
+   * these conditions are not met, an {@code ArithmeticException} is thrown.
+   * 
+   * @return this {@code BigDecimal} as a short value.
+   * @throws ArithmeticException if rounding is necessary of the number doesn't
+   *           fit in a short.
+   */
+  public short shortValueExact() {
+    return (short) valueExact(16);
+  }
+
+  /**
+   * Returns the sign of this {@code BigDecimal}.
+   * 
+   * @return {@code -1} if {@code this < 0}, {@code 0} if {@code this == 0},
+   *         {@code 1} if {@code this > 0}.
+   */
+  public int signum() {
+    if (bitLength < 54) {
+      return this.smallValue < 0 ? -1 : this.smallValue > 0 ? 1 : 0;
+    }
+    return getUnscaledValue().signum();
+  }
+
+  /**
+   * Returns a new {@code BigDecimal} instance with the same value as {@code
+   * this} but with a unscaled value where the trailing zeros have been removed.
+   * If the unscaled value of {@code this} has n trailing zeros, then the scale
+   * and the precision of the result has been reduced by n.
+   * 
+   * @return a new {@code BigDecimal} instance equivalent to this where the
+   *         trailing zeros of the unscaled value have been removed.
+   */
+  public BigDecimal stripTrailingZeros() {
+    int i = 1; // 1 <= i <= 18
+    int lastPow = TEN_POW.length - 1;
+    double newScale = scale;
+
+    if (isZero()) {
+      return new BigDecimal("0");
+    }
+    BigInteger strippedBI = getUnscaledValue();
+    BigInteger[] quotAndRem;
+
+    // while the number is even...
+    while (!strippedBI.testBit(0)) {
+      // To divide by 10^i
+      quotAndRem = strippedBI.divideAndRemainder(TEN_POW[i]);
+      // To look the remainder
+      if (quotAndRem[1].signum() == 0) {
+        // To adjust the scale
+        newScale -= i;
+        if (i < lastPow) {
+          // To set to the next power
+          i++;
+        }
+        strippedBI = quotAndRem[0];
+      } else {
+        if (i == 1) {
+          // 'this' has no more trailing zeros
+          break;
+        }
+        // To set to the smallest power of ten
+        i = 1;
+      }
+    }
+    return new BigDecimal(strippedBI, toIntScale(newScale));
+  }
+
+  /**
+   * 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) {
+    double diffScale = this.scale - subtrahend.scale;
+    // 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 (Math.max(this.bitLength, subtrahend.bitLength) + 1 < 54) {
+        return valueOf(this.smallValue - subtrahend.smallValue, this.scale);
+      }
+      return new BigDecimal(this.getUnscaledValue().subtract(
+          subtrahend.getUnscaledValue()), this.scale);
+    } else if (diffScale > 0) {
+      // case s1 > s2 : [ u1 - u2 * 10 ^ (s1 - s2) , s1 ]
+      if (diffScale < DOUBLE_TEN_POW.length
+          && Math.max(this.bitLength, subtrahend.bitLength
+              + DOUBLE_TEN_POW_BIT_LENGTH[(int) diffScale]) + 1 < 54) {
+        return valueOf(this.smallValue - subtrahend.smallValue
+            * DOUBLE_TEN_POW[(int) diffScale], this.scale);
+      }
+      return new BigDecimal(this.getUnscaledValue().subtract(
+          Multiplication.multiplyByTenPow(subtrahend.getUnscaledValue(),
+              (int) diffScale)), this.scale);
+    } else {
+      // case s2 > s1 : [ u1 * 10 ^ (s2 - s1) - u2 , s2 ]
+      diffScale = -diffScale;
+      if (diffScale < DOUBLE_TEN_POW.length
+          && Math.max(this.bitLength
+              + DOUBLE_TEN_POW_BIT_LENGTH[(int) diffScale],
+              subtrahend.bitLength) + 1 < 54) {
+        return valueOf(this.smallValue * DOUBLE_TEN_POW[(int) diffScale]
+            - subtrahend.smallValue, subtrahend.scale);
+      }
+      return new BigDecimal(Multiplication.multiplyByTenPow(
+          this.getUnscaledValue(), (int) diffScale).subtract(
+          subtrahend.getUnscaledValue()), subtrahend.scale);
+    }
+  }
+
+  /**
+   * 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) {
+    double diffScale = subtrahend.scale - 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.approxPrecision() < diffScale - 1) {
+      // Cases where it is unnecessary to subtract two numbers with very
+      // different scales
+      if (mc.getPrecision() < this.approxPrecision()) {
+        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);
+  }
+
+  /**
+   * Returns this {@code BigDecimal} as a big integer instance. A fractional
+   * part is discarded.
+   * 
+   * @return this {@code BigDecimal} as a big integer instance.
+   */
+  public BigInteger toBigInteger() {
+    if ((scale == 0) || (isZero())) {
+      return getUnscaledValue();
+    } else if (scale < 0) {
+      return getUnscaledValue().multiply(Multiplication.powerOf10(-scale));
+    } else {
+      // (scale > 0)
+      return getUnscaledValue().divide(Multiplication.powerOf10(scale));
+    }
+  }
+
+  /**
+   * Returns this {@code BigDecimal} as a big integer instance if it has no
+   * fractional part. If this {@code BigDecimal} has a fractional part, i.e. if
+   * rounding would be necessary, an {@code ArithmeticException} is thrown.
+   * 
+   * @return this {@code BigDecimal} as a big integer value.
+   * @throws ArithmeticException if rounding is necessary.
+   */
+  public BigInteger toBigIntegerExact() {
+    if ((scale == 0) || (isZero())) {
+      return getUnscaledValue();
+    } else if (scale < 0) {
+      return getUnscaledValue().multiply(Multiplication.powerOf10(-scale));
+    } else {
+      // (scale > 0)
+      BigInteger[] integerAndFraction;
+      // An optimization before do a heavy division
+      if ((scale > approxPrecision())
+          || (scale > getUnscaledValue().getLowestSetBit())) {
+        // math.08=Rounding necessary
+        throw new ArithmeticException("Rounding necessary"); //$NON-NLS-1$
+      }
+      integerAndFraction = getUnscaledValue().divideAndRemainder(
+          Multiplication.powerOf10(scale));
+      if (integerAndFraction[1].signum() != 0) {
+        // It exists a non-zero fractional part
+        // math.08=Rounding necessary
+        throw new ArithmeticException("Rounding necessary"); //$NON-NLS-1$
+      }
+      return integerAndFraction[0];
+    }
+  }
+
+  /**
+   * Returns a string representation of this {@code BigDecimal}. This
+   * representation always prints all significant digits of this value.
+   * <p>
+   * If the scale is negative or if {@code scale - precision >= 6} then
+   * engineering notation is used. Engineering notation is similar to the
+   * scientific notation except that the exponent is made to be a multiple of 3
+   * such that the integer part is >= 1 and < 1000.
+   * 
+   * @return a string representation of {@code this} in engineering notation if
+   *         necessary.
+   */
+  public String toEngineeringString() {
+    String intString = getUnscaledValue().toString();
+    if (scale == 0) {
+      return intString;
+    }
+    int begin = (getUnscaledValue().signum() < 0) ? 2 : 1;
+    int end = intString.length();
+    double exponent = -scale + end - begin;
+    StringBuilder result = new StringBuilder(intString);
+
+    if ((scale > 0) && (exponent >= -6)) {
+      if (exponent >= 0) {
+        result.insert(end - (int) scale, '.');
+      } else {
+        result.insert(begin - 1, "0."); //$NON-NLS-1$
+        result.insert(begin + 1, CH_ZEROS, 0, -(int) exponent - 1);
+      }
+    } else {
+      int delta = end - begin;
+      int rem = (int) (exponent % 3);
+
+      if (rem != 0) {
+        // adjust exponent so it is a multiple of three
+        if (getUnscaledValue().signum() == 0) {
+          // zero value
+          rem = (rem < 0) ? -rem : 3 - rem;
+          exponent += rem;
+        } else {
+          // nonzero value
+          rem = (rem < 0) ? rem + 3 : rem;
+          exponent -= rem;
+          begin += rem;
+        }
+        if (delta < 3) {
+          for (int i = rem - delta; i > 0; i--) {
+            result.insert(end++, '0');
+          }
+        }
+      }
+      if (end - begin >= 1) {
+        result.insert(begin, '.');
+        end++;
+      }
+      if (exponent != 0) {
+        result.insert(end, 'E');
+        if (exponent > 0) {
+          result.insert(++end, '+');
+        }
+        result.insert(++end, Long.toString((long) exponent));
+      }
+    }
+    return result.toString();
+  }
+
+  /* Private Methods */
+
+  /**
+   * Returns a string representation of this {@code BigDecimal}. No scientific
+   * notation is used. This methods adds zeros where necessary.
+   * <p>
+   * If this string representation is used to create a new instance, this
+   * instance is generally not identical to {@code this} as the precision
+   * changes.
+   * <p>
+   * {@code x.equals(new BigDecimal(x.toPlainString())} usually returns {@code
+   * false}.
+   * <p>
+   * {@code x.compareTo(new BigDecimal(x.toPlainString())} returns {@code 0}.
+   * 
+   * @return a string representation of {@code this} without exponent part.
+   */
+  public String toPlainString() {
+    String intStr = getUnscaledValue().toString();
+    if ((scale == 0) || ((isZero()) && (scale < 0))) {
+      return intStr;
+    }
+    int begin = (signum() < 0) ? 1 : 0;
+    double delta = scale;
+    // We take space for all digits, plus a possible decimal point, plus 'scale'
+    StringBuilder result = new StringBuilder(intStr.length() + 1
+        + Math.abs((int) scale));
+
+    if (begin == 1) {
+      // If the number is negative, we insert a '-' character at front
+      result.append('-');
+    }
+    if (scale > 0) {
+      delta -= (intStr.length() - begin);
+      if (delta >= 0) {
+        result.append("0."); //$NON-NLS-1$
+        // To append zeros after the decimal point
+        for (; delta > CH_ZEROS.length; delta -= CH_ZEROS.length) {
+          result.append(CH_ZEROS);
+        }
+        result.append(CH_ZEROS, 0, (int) delta);
+        result.append(intStr.substring(begin));
+      } else {
+        delta = begin - delta;
+        result.append(intStr.substring(begin, (int) delta));
+        result.append('.');
+        result.append(intStr.substring((int) delta));
+      }
+    } else {
+      // (scale <= 0)
+      result.append(intStr.substring(begin));
+      // To append trailing zeros
+      for (; delta < -CH_ZEROS.length; delta += CH_ZEROS.length) {
+        result.append(CH_ZEROS);
+      }
+      result.append(CH_ZEROS, 0, (int) -delta);
+    }
+    return result.toString();
+  }
+
+  /**
+   * Returns a canonical string representation of this {@code BigDecimal}. If
+   * necessary, scientific notation is used. This representation always prints
+   * all significant digits of this value.
+   * <p>
+   * If the scale is negative or if {@code scale - precision >= 6} then
+   * scientific notation is used.
+   * 
+   * @return a string representation of {@code this} in scientific notation if
+   *         necessary.
+   */
+  @Override
+  public String toString() {
+    if (toStringImage != null) {
+      return toStringImage;
+    }
+    if (bitLength < 32) {
+      // TODO convert to double math dont cast to long :-(
+      toStringImage = Conversion.toDecimalScaledString((long) smallValue,
+          (int) scale);
+      return toStringImage;
+    }
+    String intString = getUnscaledValue().toString();
+    if (scale == 0) {
+      return intString;
+    }
+    int begin = (getUnscaledValue().signum() < 0) ? 2 : 1;
+    int end = intString.length();
+    double exponent = -scale + end - begin;
+    StringBuilder result = new StringBuilder();
+
+    result.append(intString);
+    if ((scale > 0) && (exponent >= -6)) {
+      if (exponent >= 0) {
+        result.insert(end - (int) scale, '.');
+      } else {
+        result.insert(begin - 1, "0."); //$NON-NLS-1$
+        result.insert(begin + 1, CH_ZEROS, 0, -(int) exponent - 1);
+      }
+    } else {
+      if (end - begin >= 1) {
+        result.insert(begin, '.');
+        end++;
+      }
+      result.insert(end, 'E');
+      if (exponent > 0) {
+        result.insert(++end, '+');
+      }
+      result.insert(++end, Long.toString((long) exponent));
+    }
+    toStringImage = result.toString();
+    return toStringImage;
+  }
+
+  /**
+   * Returns the unit in the last place (ULP) of this {@code BigDecimal}
+   * instance. An ULP is the distance to the nearest big decimal with the same
+   * precision.
+   * <p>
+   * The amount of a rounding error in the evaluation of a floating-point
+   * operation is often expressed in ULPs. An error of 1 ULP is often seen as a
+   * tolerable error.
+   * <p>
+   * For class {@code BigDecimal}, the ULP of a number is simply 10^(-scale).
+   * <p>
+   * For example, {@code new BigDecimal(0.1).ulp()} returns {@code 1E-55}.
+   * 
+   * @return unit in the last place (ULP) of this {@code BigDecimal} instance.
+   */
+  public BigDecimal ulp() {
+    return valueOf(1, scale);
+  }
+
+  /**
+   * Returns the unscaled value (mantissa) of this {@code BigDecimal} instance
+   * as a {@code BigInteger}. The unscaled value can be computed as {@code this}
+   * 10^(scale).
+   * 
+   * @return unscaled value (this * 10^(scale)).
+   */
+  public BigInteger unscaledValue() {
+    return getUnscaledValue();
+  }
+
+  /**
+   * If the precision already was calculated it returns that value, otherwise it
+   * calculates a very good approximation efficiently . Note that this value
+   * will be {@code precision()} or {@code precision()-1} in the worst case.
+   * 
+   * @return an approximation of {@code precision()} value
+   */
+  private double approxPrecision() {
+    return (precision > 0) ? precision
+        : Math.floor((this.bitLength - 1) * LOG10_2) + 1;
+  }
+
+  private BigInteger getUnscaledValue() {
+    if (intVal == null) {
+      intVal = BigInteger.valueOf((long) smallValue);
+    }
+    return intVal;
+  }
+
+  private void initFrom(String val) {
+    int begin = 0; // first index to be copied
+    int offset = 0;
+    int last = val.length() - 1; // last index to be copied
+    String scaleString = null; // buffer for scale
+    StringBuilder unscaledBuffer; // buffer for unscaled value
+
+    if (val == null) {
+      throw new NullPointerException();
+    }
+    unscaledBuffer = new StringBuilder(val.length());
+    // To skip a possible '+' symbol
+    if ((offset <= last) && (val.charAt(offset) == '+')) {
+      offset++;
+      begin++;
+    }
+    int counter = 0;
+    boolean wasNonZero = false;
+    // Accumulating all digits until a possible decimal point
+    for (; (offset <= last) && (val.charAt(offset) != '.')
+        && (val.charAt(offset) != 'e') && (val.charAt(offset) != 'E'); offset++) {
+      if (!wasNonZero) {
+        if (val.charAt(offset) == '0') {
+          counter++;
+        } else {
+          wasNonZero = true;
+        }
+      }
+    }
+    unscaledBuffer.append(val, begin, offset);
+    // A decimal point was found
+    if ((offset <= last) && (val.charAt(offset) == '.')) {
+      offset++;
+      // Accumulating all digits until a possible exponent
+      begin = offset;
+      for (; (offset <= last) && (val.charAt(offset) != 'e')
+          && (val.charAt(offset) != 'E'); offset++) {
+        if (!wasNonZero) {
+          if (val.charAt(offset) == '0') {
+            counter++;
+          } else {
+            wasNonZero = true;
+          }
+        }
+      }
+      scale = offset - begin;
+      unscaledBuffer.append(val, begin, offset);
+    } else {
+      scale = 0;
+    }
+    // An exponent was found
+    if ((offset <= last)
+        && ((val.charAt(offset) == 'e') || (val.charAt(offset) == 'E'))) {
+      offset++;
+      // Checking for a possible sign of scale
+      begin = offset;
+      if ((offset <= last) && (val.charAt(offset) == '+')) {
+        offset++;
+        if ((offset <= last) && (val.charAt(offset) != '-')) {
+          begin++;
+        }
+      }
+      // Accumulating all remaining digits
+      scaleString = val.substring(begin, last + 1);
+      // Checking if the scale is defined
+      scale = scale - Integer.parseInt(scaleString);
+      if (scale != (int) scale) {
+        // math.02=Scale out of range.
+        throw new NumberFormatException("Scale out of range."); //$NON-NLS-1$
+      }
+    }
+    // Parsing the unscaled value
+    String unscaled = unscaledBuffer.toString();
+    if (unscaled.length() < 16) {
+      smallValue = parseUnscaled(unscaled);
+      if (Double.isNaN(smallValue)) {
+        throw new NumberFormatException("For input string: \"" + val + "\"");
+      }
+      bitLength = bitLength(smallValue);
+    } else {
+      setUnscaledValue(new BigInteger(unscaled));
+    }
+    precision = unscaledBuffer.length() - counter;
+    if (unscaledBuffer.charAt(0) == '-') {
+      precision--;
+    }
+  }
+
+  /**
+   * It does all rounding work of the public method {@code round(MathContext)},
+   * performing an inplace rounding without creating a new object.
+   * 
+   * @param mc the {@code MathContext} for perform the rounding.
+   * @see #round(MathContext)
+   */
+  private void inplaceRound(MathContext mc) {
+    int mcPrecision = mc.getPrecision();
+    if (approxPrecision() - mcPrecision <= 0 || mcPrecision == 0) {
+      return;
+    }
+    int discardedPrecision = precision() - mcPrecision;
+    // If no rounding is necessary it returns immediately
+    if ((discardedPrecision <= 0)) {
+      return;
+    }
+    // When the number is small perform an efficient rounding
+    if (this.bitLength < 54) {
+      smallRound(mc, discardedPrecision);
+      return;
+    }
+    // Getting the integer part and the discarded fraction
+    BigInteger sizeOfFraction = Multiplication.powerOf10(discardedPrecision);
+    BigInteger[] integerAndFraction = getUnscaledValue().divideAndRemainder(
+        sizeOfFraction);
+    double newScale = scale - discardedPrecision;
+    int compRem;
+    BigDecimal tempBD;
+    // If the discarded fraction is non-zero, perform rounding
+    if (integerAndFraction[1].signum() != 0) {
+      // To check if the discarded fraction >= 0.5
+      compRem = (integerAndFraction[1].abs().shiftLeftOneBit().compareTo(sizeOfFraction));
+      // To look if there is a carry
+      compRem = roundingBehavior(integerAndFraction[0].testBit(0) ? 1 : 0,
+          integerAndFraction[1].signum() * (5 + compRem), mc.getRoundingMode());
+      if (compRem != 0) {
+        integerAndFraction[0] = integerAndFraction[0].add(BigInteger.valueOf(compRem));
+      }
+      tempBD = new BigDecimal(integerAndFraction[0]);
+      // If after to add the increment the precision changed, we normalize the
+      // size
+      if (tempBD.precision() > mcPrecision) {
+        integerAndFraction[0] = integerAndFraction[0].divide(BigInteger.TEN);
+        newScale--;
+      }
+    }
+    // To update all internal fields
+    scale = toIntScale(newScale);
+    precision = mcPrecision;
+    setUnscaledValue(integerAndFraction[0]);
+  }
+
+  private boolean isZero() {
+    return bitLength == 0 && this.smallValue != -1;
+  }
+
+  private BigDecimal movePoint(double newScale) {
+    if (isZero()) {
+      return zeroScaledBy(Math.max(newScale, 0));
+    }
+    /*
+     * When: 'n'== Integer.MIN_VALUE isn't possible to call to
+     * movePointRight(-n) since -Integer.MIN_VALUE == Integer.MIN_VALUE
+     */
+    if (newScale >= 0) {
+      if (bitLength < 54) {
+        return valueOf(smallValue, toIntScale(newScale));
+      }
+      return new BigDecimal(getUnscaledValue(), toIntScale(newScale));
+    }
+    if (-newScale < DOUBLE_TEN_POW.length
+        && bitLength + DOUBLE_TEN_POW_BIT_LENGTH[(int) -newScale] < 54) {
+      return valueOf(smallValue * DOUBLE_TEN_POW[(int) -newScale], 0);
+    }
+    return new BigDecimal(Multiplication.multiplyByTenPow(getUnscaledValue(),
+        (int) -newScale), 0);
+  }
+
+  private void setUnscaledValue(BigInteger unscaledValue) {
+    this.intVal = unscaledValue;
+    this.bitLength = unscaledValue.bitLength();
+    if (this.bitLength < 54) {
+      this.smallValue = unscaledValue.longValue();
+    }
+  }
+
+  /**
+   * This method implements an efficient rounding for numbers which unscaled
+   * value fits in the type {@code long}.
+   * 
+   * @param mc the context to use
+   * @param discardedPrecision the number of decimal digits that are discarded
+   * @see #round(MathContext)
+   */
+  private void smallRound(MathContext mc, int discardedPrecision) {
+    long sizeOfFraction = (long) DOUBLE_TEN_POW[discardedPrecision];
+    long newScale = (long) scale - discardedPrecision;
+    long unscaledVal = (long) smallValue; // TODO convert to double math dont
+                                          // use longs
+    // Getting the integer part and the discarded fraction
+    long integer = unscaledVal / sizeOfFraction;
+    long fraction = unscaledVal % sizeOfFraction;
+    int compRem;
+    // If the discarded fraction is non-zero perform rounding
+    if (fraction != 0) {
+      // To check if the discarded fraction >= 0.5
+      compRem = longCompareTo(Math.abs(fraction) << 1, sizeOfFraction);
+      // To look if there is a carry
+      integer += roundingBehavior(((int) integer) & 1, Long.signum(fraction)
+          * (5 + compRem), mc.getRoundingMode());
+      // If after to add the increment the precision changed, we normalize the
+      // size
+      if (Math.log10(Math.abs(integer)) >= mc.getPrecision()) {
+        integer /= 10;
+        newScale--;
+      }
+    }
+    // To update all internal fields
+    scale = toIntScale(newScale);
+    precision = mc.getPrecision();
+    smallValue = integer;
+    bitLength = bitLength(integer);
+    intVal = null;
+  }
+
+  /**
+   * If {@code intVal} has a fractional part throws an exception, otherwise it
+   * counts the number of bits of value and checks if it's out of the range of
+   * the primitive type. If the number fits in the primitive type returns this
+   * number as {@code long}, otherwise throws an exception.
+   * 
+   * @param bitLengthOfType number of bits of the type whose value will be
+   *          calculated exactly
+   * @return the exact value of the integer part of {@code BigDecimal} when is
+   *         possible
+   * @throws ArithmeticException when rounding is necessary or the number don't
+   *           fit in the primitive type
+   */
+  private long valueExact(int bitLengthOfType) {
+    BigInteger bigInteger = toBigIntegerExact();
+
+    if (bigInteger.bitLength() < bitLengthOfType) {
+      // It fits in the primitive type
+      return bigInteger.longValue();
+    }
+    // math.08=Rounding necessary
+    throw new ArithmeticException("Rounding necessary"); //$NON-NLS-1$
+  }
+}
diff --git a/user/super/com/google/gwt/emul/java/math/BigInteger.java b/user/super/com/google/gwt/emul/java/math/BigInteger.java
new file mode 100644
index 0000000..e36c778
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/math/BigInteger.java
@@ -0,0 +1,1497 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE.
+ */
+package java.math;
+
+import java.io.Serializable;
+import java.util.Random;
+
+/**
+ * This class represents immutable integer numbers of arbitrary length. Large
+ * numbers are typically used in security applications and therefore BigIntegers
+ * offer dedicated functionality like the generation of large prime numbers or
+ * the computation of modular inverse.
+ * <p>
+ * Since the class was modeled to offer all the functionality as the
+ * {@link Integer} class does, it provides even methods that operate bitwise on
+ * a two's complement representation of large integers. Note however that the
+ * implementations favors an internal representation where magnitude and sign
+ * are treated separately. Hence such operations are inefficient and should be
+ * discouraged. In simple words: Do NOT implement any bit fields based on
+ * BigInteger.
+ */
+public class BigInteger extends Number implements Comparable<BigInteger>,
+    Serializable {
+
+  /**
+   * The {@code BigInteger} constant 1.
+   */
+  public static final BigInteger ONE = new BigInteger(1, 1);
+
+  /* Fields used for the internal representation. */
+
+  /**
+   * The {@code BigInteger} constant 10.
+   */
+  public static final BigInteger TEN = new BigInteger(1, 10);
+
+  /**
+   * The {@code BigInteger} constant 0.
+   */
+  public static final BigInteger ZERO = new BigInteger(0, 0);
+
+  /**
+   * The {@code BigInteger} constant 0 used for comparison.
+   */
+  static final int EQUALS = 0;
+
+  /**
+   * The {@code BigInteger} constant 1 used for comparison.
+   */
+  static final int GREATER = 1;
+
+  /**
+   * The {@code BigInteger} constant -1 used for comparison.
+   */
+  static final int LESS = -1;
+
+  /**
+   * The {@code BigInteger} constant -1.
+   */
+  static final BigInteger MINUS_ONE = new BigInteger(-1, 1);
+
+  /**
+   * All the {@code BigInteger} numbers in the range [0,10] are cached.
+   */
+  static final BigInteger[] SMALL_VALUES = {
+      ZERO, ONE, new BigInteger(1, 2), new BigInteger(1, 3),
+      new BigInteger(1, 4), new BigInteger(1, 5), new BigInteger(1, 6),
+      new BigInteger(1, 7), new BigInteger(1, 8), new BigInteger(1, 9), TEN};
+
+  static final BigInteger[] TWO_POWS;
+
+  /**
+   * This is the serialVersionUID used by the sun implementation.
+   */
+  private static final long serialVersionUID = -8287574255936472291L;
+
+  static {
+    TWO_POWS = new BigInteger[32];
+    for (int i = 0; i < TWO_POWS.length; i++) {
+      TWO_POWS[i] = BigInteger.valueOf(1L << i);
+    }
+  }
+
+  /**
+   * Returns a random positive {@code BigInteger} instance in the range [0,
+   * 2^(bitLength)-1] which is probably prime. The probability that the returned
+   * {@code BigInteger} is prime is beyond (1-1/2^80).
+   * <p>
+   * <b>Implementation Note:</b> Currently {@code rnd} is ignored.
+   * 
+   * @param bitLength length of the new {@code BigInteger} in bits.
+   * @param rnd random generator used to generate the new {@code BigInteger}.
+   * @return probably prime random {@code BigInteger} instance.
+   * @throws IllegalArgumentException if {@code bitLength < 2}.
+   */
+  public static BigInteger probablePrime(int bitLength, Random rnd) {
+    return new BigInteger(bitLength, 100, rnd);
+  }
+
+  public static BigInteger valueOf(long val) {
+    if (val < 0) {
+      if (val != -1) {
+        return new BigInteger(-1, -val);
+      }
+      return MINUS_ONE;
+    } else if (val <= 10) {
+      return SMALL_VALUES[(int) val];
+    } else {
+      // (val > 10)
+      return new BigInteger(1, val);
+    }
+  }
+
+  static BigInteger getPowerOfTwo(int exp) {
+    if (exp < TWO_POWS.length) {
+      return TWO_POWS[exp];
+    }
+    int intCount = exp >> 5;
+    int bitN = exp & 31;
+    int resDigits[] = new int[intCount + 1];
+    resDigits[intCount] = 1 << bitN;
+    return new BigInteger(1, intCount + 1, resDigits);
+  }
+
+  /**
+   * @see BigInteger#BigInteger(String, int)
+   */
+  private static void setFromString(BigInteger bi, String val, int radix) {
+    int sign;
+    int[] digits;
+    int numberLength;
+    int stringLength = val.length();
+    int startChar;
+    int endChar = stringLength;
+
+    if (val.charAt(0) == '-') {
+      sign = -1;
+      startChar = 1;
+      stringLength--;
+    } else {
+      sign = 1;
+      startChar = 0;
+    }
+    /*
+     * We use the following algorithm: split a string into portions of n
+     * characters and convert each portion to an integer according to the radix.
+     * Then convert an exp(radix, n) based number to binary using the
+     * multiplication method. See D. Knuth, The Art of Computer Programming,
+     * vol. 2.
+     */
+
+    int charsPerInt = Conversion.digitFitInInt[radix];
+    int bigRadixDigitsLength = stringLength / charsPerInt;
+    int topChars = stringLength % charsPerInt;
+
+    if (topChars != 0) {
+      bigRadixDigitsLength++;
+    }
+    digits = new int[bigRadixDigitsLength];
+    // Get the maximal power of radix that fits in int
+    int bigRadix = Conversion.bigRadices[radix - 2];
+    // Parse an input string and accumulate the BigInteger's magnitude
+    int digitIndex = 0; // index of digits array
+    int substrEnd = startChar + ((topChars == 0) ? charsPerInt : topChars);
+    int newDigit;
+
+    for (int substrStart = startChar; substrStart < endChar; substrStart = substrEnd, substrEnd = substrStart
+        + charsPerInt) {
+      int bigRadixDigit = Integer.parseInt(
+          val.substring(substrStart, substrEnd), radix);
+      newDigit = Multiplication.multiplyByInt(digits, digitIndex, bigRadix);
+      newDigit += Elementary.inplaceAdd(digits, digitIndex, bigRadixDigit);
+      digits[digitIndex++] = newDigit;
+    }
+    numberLength = digitIndex;
+    bi.sign = sign;
+    bi.numberLength = numberLength;
+    bi.digits = digits;
+    bi.cutOffLeadingZeroes();
+  }
+
+  /**
+   * The magnitude of this big integer. This array holds unsigned little endian
+   * digits. For example: {@code 13} is represented as [ 13 ] {@code -13} is
+   * represented as [ 13 ] {@code 2^32 + 13} is represented as [ 13, 1 ] {@code
+   * 2^64 + 13} is represented as [ 13, 0, 1 ] {@code 2^31} is represented as [
+   * Integer.MIN_VALUE ] The magnitude array may be longer than strictly
+   * necessary, which results in additional trailing zeros.
+   */
+  transient int digits[];
+
+  /**
+   * The length of this in measured in ints. Can be less than digits.length().
+   */
+  transient int numberLength;
+
+  /**
+   * The sign of this.
+   */
+  transient int sign;
+
+  private transient int firstNonzeroDigit = -2;
+
+  /**
+   * Cache for the hash code.
+   */
+  private transient int hashCode = 0;
+
+  /**
+   * Constructs a new {@code BigInteger} from the given two's complement
+   * representation. The most significant byte is the entry at index 0. The most
+   * significant bit of this entry determines the sign of the new {@code
+   * BigInteger} instance. The given array must not be empty.
+   * 
+   * @param val two's complement representation of the new {@code BigInteger}.
+   * @throws NullPointerException if {@code val == null}.
+   * @throws NumberFormatException if the length of {@code val} is zero.
+   */
+  public BigInteger(byte[] val) {
+    if (val.length == 0) {
+      // math.12=Zero length BigInteger
+      throw new NumberFormatException("Zero length BigInteger"); //$NON-NLS-1$
+    }
+    if (val[0] < 0) {
+      sign = -1;
+      putBytesNegativeToIntegers(val);
+    } else {
+      sign = 1;
+      putBytesPositiveToIntegers(val);
+    }
+    cutOffLeadingZeroes();
+  }
+
+  /**
+   * Constructs a new {@code BigInteger} instance with the given sign and the
+   * given magnitude. The sign is given as an integer (-1 for negative, 0 for
+   * zero, 1 for positive). The magnitude is specified as a byte array. The most
+   * significant byte is the entry at index 0.
+   * 
+   * @param signum sign of the new {@code BigInteger} (-1 for negative, 0 for
+   *          zero, 1 for positive).
+   * @param magnitude magnitude of the new {@code BigInteger} with the most
+   *          significant byte first.
+   * @throws NullPointerException if {@code magnitude == null}.
+   * @throws NumberFormatException if the sign is not one of -1, 0, 1 or if the
+   *           sign is zero and the magnitude contains non-zero entries.
+   */
+  public BigInteger(int signum, byte[] magnitude) {
+    if (magnitude == null) {
+      throw new NullPointerException();
+    }
+    if ((signum < -1) || (signum > 1)) {
+      // math.13=Invalid signum value
+      throw new NumberFormatException("Invalid signum value"); //$NON-NLS-1$
+    }
+    if (signum == 0) {
+      for (byte element : magnitude) {
+        if (element != 0) {
+          // math.14=signum-magnitude mismatch
+          throw new NumberFormatException("signum-magnitude mismatch"); //$NON-NLS-1$
+        }
+      }
+    }
+    if (magnitude.length == 0) {
+      sign = 0;
+      numberLength = 1;
+      digits = new int[] {0};
+    } else {
+      sign = signum;
+      putBytesPositiveToIntegers(magnitude);
+      cutOffLeadingZeroes();
+    }
+  }
+
+  /**
+   * Constructs a random {@code BigInteger} instance in the range [0,
+   * 2^(bitLength)-1] which is probably prime. The probability that the returned
+   * {@code BigInteger} is prime is beyond (1-1/2^certainty).
+   * 
+   * @param bitLength length of the new {@code BigInteger} in bits.
+   * @param certainty tolerated primality uncertainty.
+   * @param rnd is an optional random generator to be used.
+   * @throws ArithmeticException if {@code bitLength} < 2.
+   */
+  public BigInteger(int bitLength, int certainty, Random rnd) {
+    if (bitLength < 2) {
+      // math.1C=bitLength < 2
+      throw new ArithmeticException("bitLength < 2"); //$NON-NLS-1$
+    }
+    BigInteger me = Primality.consBigInteger(bitLength, certainty, rnd);
+    sign = me.sign;
+    numberLength = me.numberLength;
+    digits = me.digits;
+  }
+
+  /**
+   * Constructs a random non-negative {@code BigInteger} instance in the range
+   * [0, 2^(numBits)-1].
+   * 
+   * @param numBits maximum length of the new {@code BigInteger} in bits.
+   * @param rnd is an optional random generator to be used.
+   * @throws IllegalArgumentException if {@code numBits} < 0.
+   */
+  public BigInteger(int numBits, Random rnd) {
+    if (numBits < 0) {
+      // math.1B=numBits must be non-negative
+      throw new IllegalArgumentException("numBits must be non-negative"); //$NON-NLS-1$
+    }
+    if (numBits == 0) {
+      sign = 0;
+      numberLength = 1;
+      digits = new int[] {0};
+    } else {
+      sign = 1;
+      numberLength = (numBits + 31) >> 5;
+      digits = new int[numberLength];
+      for (int i = 0; i < numberLength; i++) {
+        digits[i] = rnd.nextInt();
+      }
+      // Using only the necessary bits
+      digits[numberLength - 1] >>>= (-numBits) & 31;
+      cutOffLeadingZeroes();
+    }
+  }
+
+  /**
+   * Constructs a new {@code BigInteger} instance from the string
+   * representation. The string representation consists of an optional minus
+   * sign followed by a non-empty sequence of decimal digits.
+   * 
+   * @param val string representation of the new {@code BigInteger}.
+   * @throws NullPointerException if {@code val == null}.
+   * @throws NumberFormatException if {@code val} is not a valid representation
+   *           of a {@code BigInteger}.
+   */
+  public BigInteger(String val) {
+    this(val, 10);
+  }
+
+  /**
+   * Constructs a new {@code BigInteger} instance from the string
+   * representation. The string representation consists of an optional minus
+   * sign followed by a non-empty sequence of digits in the specified radix. For
+   * the conversion the method {@code Character.digit(char, radix)} is used.
+   * 
+   * @param val string representation of the new {@code BigInteger}.
+   * @param radix the base to be used for the conversion.
+   * @throws NullPointerException if {@code val == null}.
+   * @throws NumberFormatException if {@code val} is not a valid representation
+   *           of a {@code BigInteger} or if {@code radix < Character.MIN_RADIX}
+   *           or {@code radix > Character.MAX_RADIX}.
+   */
+  public BigInteger(String val, int radix) {
+    if (val == null) {
+      throw new NullPointerException();
+    }
+    if ((radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX)) {
+      // math.11=Radix out of range
+      throw new NumberFormatException("Radix out of range"); //$NON-NLS-1$
+    }
+    if (val.length() == 0) {
+      // math.12=Zero length BigInteger
+      throw new NumberFormatException("Zero length BigInteger"); //$NON-NLS-1$
+    }
+    setFromString(this, val, radix);
+  }
+
+  /**
+   * Constructs a number which array is of size 1.
+   * 
+   * @param sign the sign of the number
+   * @param value the only one digit of array
+   */
+  BigInteger(int sign, int value) {
+    this.sign = sign;
+    numberLength = 1;
+    digits = new int[] {value};
+  }
+
+  /**
+   * Creates a new {@code BigInteger} with the given sign and magnitude. This
+   * constructor does not create a copy, so any changes to the reference will
+   * affect the new number.
+   * 
+   * @param signum The sign of the number represented by {@code digits}
+   * @param digits The magnitude of the number
+   */
+  BigInteger(int signum, int digits[]) {
+    if (digits.length == 0) {
+      sign = 0;
+      numberLength = 1;
+      this.digits = new int[] {0};
+    } else {
+      sign = signum;
+      numberLength = digits.length;
+      this.digits = digits;
+      cutOffLeadingZeroes();
+    }
+  }
+
+  /**
+   * Constructs a number without to create new space. This construct should be
+   * used only if the three fields of representation are known.
+   * 
+   * @param sign the sign of the number
+   * @param numberLength the length of the internal array
+   * @param digits a reference of some array created before
+   */
+  BigInteger(int sign, int numberLength, int[] digits) {
+    this.sign = sign;
+    this.numberLength = numberLength;
+    this.digits = digits;
+  }
+
+  /**
+   * Creates a new {@code BigInteger} whose value is equal to the specified
+   * {@code long}.
+   * 
+   * @param sign the sign of the number
+   * @param val the value of the new {@code BigInteger}.
+   */
+  BigInteger(int sign, long val) {
+    // PRE: (val >= 0) && (sign >= -1) && (sign <= 1)
+    this.sign = sign;
+    if ((val & 0xFFFFFFFF00000000L) == 0) {
+      // It fits in one 'int'
+      numberLength = 1;
+      digits = new int[] {(int) val};
+    } else {
+      numberLength = 2;
+      digits = new int[] {(int) val, (int) (val >> 32)};
+    }
+  }
+
+  /**
+   * Returns a (new) {@code BigInteger} whose value is the absolute value of
+   * {@code this}.
+   * 
+   * @return {@code abs(this)}.
+   */
+  public BigInteger abs() {
+    return ((sign < 0) ? new BigInteger(1, numberLength, digits) : this);
+  }
+
+  /**
+   * Returns a new {@code BigInteger} whose value is {@code this + val}.
+   * 
+   * @param val value to be added to {@code this}.
+   * @return {@code this + val}.
+   * @throws NullPointerException if {@code val == null}.
+   */
+  public BigInteger add(BigInteger val) {
+    return Elementary.add(this, val);
+  }
+
+  /**
+   * Returns a new {@code BigInteger} whose value is {@code this & val}.
+   * <p>
+   * <b>Implementation Note:</b> Usage of this method is not recommended as the
+   * current implementation is not efficient.
+   * 
+   * @param val value to be and'ed with {@code this}.
+   * @return {@code this & val}.
+   * @throws NullPointerException if {@code val == null}.
+   */
+  public BigInteger and(BigInteger val) {
+    return Logical.and(this, val);
+  }
+
+  /**
+   * Returns a new {@code BigInteger} whose value is {@code this & ~val}.
+   * Evaluating {@code x.andNot(val)} returns the same result as {@code
+   * x.and(val.not())}.
+   * <p>
+   * <b>Implementation Note:</b> Usage of this method is not recommended as the
+   * current implementation is not efficient.
+   * 
+   * @param val value to be not'ed and then and'ed with {@code this}.
+   * @return {@code this & ~val}.
+   * @throws NullPointerException if {@code val == null}.
+   */
+  public BigInteger andNot(BigInteger val) {
+    return Logical.andNot(this, val);
+  }
+
+  /**
+   * Use {@code bitLength(0)} if you want to know the length of the binary value
+   * in bits.
+   * <p>
+   * Returns the number of bits in the binary representation of {@code this}
+   * which differ from the sign bit. If {@code this} is positive the result is
+   * equivalent to the number of bits set in the binary representation of
+   * {@code this}. If {@code this} is negative the result is equivalent to the
+   * number of bits set in the binary representation of {@code -this-1}.
+   * <p>
+   * <b>Implementation Note:</b> Usage of this method is not recommended as the
+   * current implementation is not efficient.
+   * 
+   * @return number of bits in the binary representation of {@code this} which
+   *         differ from the sign bit
+   */
+  public int bitCount() {
+    return BitLevel.bitCount(this);
+  }
+
+  /**
+   * Returns the length of the value's two's complement representation without
+   * leading zeros for positive numbers / without leading ones for negative
+   * values.
+   * <p>
+   * The two's complement representation of {@code this} will be at least
+   * {@code bitLength() + 1} bits long.
+   * <p>
+   * The value will fit into an {@code int} if {@code bitLength() < 32} or into
+   * a {@code long} if {@code bitLength() < 64}.
+   * 
+   * @return the length of the minimal two's complement representation for
+   *         {@code this} without the sign bit.
+   */
+  public int bitLength() {
+    return BitLevel.bitLength(this);
+  }
+
+  /**
+   * Returns a new {@code BigInteger} which has the same binary representation
+   * as {@code this} but with the bit at position n cleared. The result is
+   * equivalent to {@code this & ~(2^n)}.
+   * <p>
+   * <b>Implementation Note:</b> Usage of this method is not recommended as the
+   * current implementation is not efficient.
+   * 
+   * @param n position where the bit in {@code this} has to be cleared.
+   * @return {@code this & ~(2^n)}.
+   * @throws ArithmeticException if {@code n < 0}.
+   */
+  public BigInteger clearBit(int n) {
+    if (testBit(n)) {
+      return BitLevel.flipBit(this, n);
+    }
+    return this;
+  }
+
+  /**
+   * Compares this {@code BigInteger} with {@code val}. Returns one of the three
+   * values 1, 0, or -1.
+   * 
+   * @param val value to be compared with {@code this}.
+   * @return {@code 1} if {@code this > val}, {@code -1} if {@code this < val} ,
+   *         {@code 0} if {@code this == val}.
+   * @throws NullPointerException if {@code val == null}.
+   */
+  public int compareTo(BigInteger val) {
+    if (sign > val.sign) {
+      return GREATER;
+    }
+    if (sign < val.sign) {
+      return LESS;
+    }
+    if (numberLength > val.numberLength) {
+      return sign;
+    }
+    if (numberLength < val.numberLength) {
+      return -val.sign;
+    }
+    // Equal sign and equal numberLength
+    return (sign * Elementary.compareArrays(digits, val.digits, numberLength));
+  }
+
+  /**
+   * Returns a new {@code BigInteger} whose value is {@code this / divisor}.
+   * 
+   * @param divisor value by which {@code this} is divided.
+   * @return {@code this / divisor}.
+   * @throws NullPointerException if {@code divisor == null}.
+   * @throws ArithmeticException if {@code divisor == 0}.
+   */
+  public BigInteger divide(BigInteger divisor) {
+    if (divisor.sign == 0) {
+      // math.17=BigInteger divide by zero
+      throw new ArithmeticException("BigInteger divide by zero"); //$NON-NLS-1$
+    }
+    int divisorSign = divisor.sign;
+    if (divisor.isOne()) {
+      return ((divisor.sign > 0) ? this : this.negate());
+    }
+    int thisSign = sign;
+    int thisLen = numberLength;
+    int divisorLen = divisor.numberLength;
+    if (thisLen + divisorLen == 2) {
+      long val = (digits[0] & 0xFFFFFFFFL) / (divisor.digits[0] & 0xFFFFFFFFL);
+      if (thisSign != divisorSign) {
+        val = -val;
+      }
+      return valueOf(val);
+    }
+    int cmp = ((thisLen != divisorLen) ? ((thisLen > divisorLen) ? 1 : -1)
+        : Elementary.compareArrays(digits, divisor.digits, thisLen));
+    if (cmp == EQUALS) {
+      return ((thisSign == divisorSign) ? ONE : MINUS_ONE);
+    }
+    if (cmp == LESS) {
+      return ZERO;
+    }
+    int resLength = thisLen - divisorLen + 1;
+    int resDigits[] = new int[resLength];
+    int resSign = ((thisSign == divisorSign) ? 1 : -1);
+    if (divisorLen == 1) {
+      Division.divideArrayByInt(resDigits, digits, thisLen, divisor.digits[0]);
+    } else {
+      Division.divide(resDigits, resLength, digits, thisLen, divisor.digits,
+          divisorLen);
+    }
+    BigInteger result = new BigInteger(resSign, resLength, resDigits);
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  /**
+   * Returns a {@code BigInteger} array which contains {@code this / divisor} at
+   * index 0 and {@code this % divisor} at index 1.
+   * 
+   * @param divisor value by which {@code this} is divided.
+   * @return {@code [this / divisor, this % divisor]}.
+   * @throws NullPointerException if {@code divisor == null}.
+   * @throws ArithmeticException if {@code divisor == 0}.
+   * @see #divide
+   * @see #remainder
+   */
+  public BigInteger[] divideAndRemainder(BigInteger divisor) {
+    int divisorSign = divisor.sign;
+    if (divisorSign == 0) {
+      // math.17=BigInteger divide by zero
+      throw new ArithmeticException("BigInteger divide by zero"); //$NON-NLS-1$
+    }
+    int divisorLen = divisor.numberLength;
+    int[] divisorDigits = divisor.digits;
+    if (divisorLen == 1) {
+      return Division.divideAndRemainderByInteger(this, divisorDigits[0],
+          divisorSign);
+    }
+    // res[0] is a quotient and res[1] is a remainder:
+    int[] thisDigits = digits;
+    int thisLen = numberLength;
+    int cmp = (thisLen != divisorLen) ? ((thisLen > divisorLen) ? 1 : -1)
+        : Elementary.compareArrays(thisDigits, divisorDigits, thisLen);
+    if (cmp < 0) {
+      return new BigInteger[] {ZERO, this};
+    }
+    int thisSign = sign;
+    int quotientLength = thisLen - divisorLen + 1;
+    int remainderLength = divisorLen;
+    int quotientSign = ((thisSign == divisorSign) ? 1 : -1);
+    int quotientDigits[] = new int[quotientLength];
+    int remainderDigits[] = Division.divide(quotientDigits, quotientLength,
+        thisDigits, thisLen, divisorDigits, divisorLen);
+    BigInteger result0 = new BigInteger(quotientSign, quotientLength,
+        quotientDigits);
+    BigInteger result1 = new BigInteger(thisSign, remainderLength,
+        remainderDigits);
+    result0.cutOffLeadingZeroes();
+    result1.cutOffLeadingZeroes();
+    return new BigInteger[] {result0, result1};
+  }
+
+  /**
+   * Returns this {@code BigInteger} as an double value. If {@code this} is too
+   * big to be represented as an double, then {@code Double.POSITIVE_INFINITY}
+   * or {@code Double.NEGATIVE_INFINITY} is returned. Note, that not all
+   * integers x in the range [-Double.MAX_VALUE, Double.MAX_VALUE] can be
+   * represented as a double. The double representation has a mantissa of length
+   * 53. For example, 2^53+1 = 9007199254740993 is returned as double
+   * 9007199254740992.0.
+   * 
+   * @return this {@code BigInteger} as a double value
+   */
+  @Override
+  public double doubleValue() {
+    return Double.parseDouble(this.toString());
+  }
+
+  /**
+   * Returns {@code true} if {@code x} is a BigInteger instance and if this
+   * instance is equal to this {@code BigInteger}.
+   * 
+   * @param x object to be compared with {@code this}.
+   * @return true if {@code x} is a BigInteger and {@code this == x}, {@code
+   *         false} otherwise.
+   */
+  @Override
+  public boolean equals(Object x) {
+    if (this == x) {
+      return true;
+    }
+    if (x instanceof BigInteger) {
+      BigInteger x1 = (BigInteger) x;
+      return sign == x1.sign && numberLength == x1.numberLength
+          && equalsArrays(x1.digits);
+    }
+    return false;
+  }
+
+  /**
+   * Returns a new {@code BigInteger} which has the same binary representation
+   * as {@code this} but with the bit at position n flipped. The result is
+   * equivalent to {@code this ^ 2^n}.
+   * <p>
+   * <b>Implementation Note:</b> Usage of this method is not recommended as the
+   * current implementation is not efficient.
+   * 
+   * @param n position where the bit in {@code this} has to be flipped.
+   * @return {@code this ^ 2^n}.
+   * @throws ArithmeticException if {@code n < 0}.
+   */
+  public BigInteger flipBit(int n) {
+    if (n < 0) {
+      // math.15=Negative bit address
+      throw new ArithmeticException("Negative bit address"); //$NON-NLS-1$
+    }
+    return BitLevel.flipBit(this, n);
+  }
+
+  /**
+   * Returns this {@code BigInteger} as an float value. If {@code this} is too
+   * big to be represented as an float, then {@code Float.POSITIVE_INFINITY} or
+   * {@code Float.NEGATIVE_INFINITY} is returned. Note, that not all integers x
+   * in the range [-Float.MAX_VALUE, Float.MAX_VALUE] can be represented as a
+   * float. The float representation has a mantissa of length 24. For example,
+   * 2^24+1 = 16777217 is returned as float 16777216.0.
+   * 
+   * @return this {@code BigInteger} as a float value.
+   */
+  @Override
+  public float floatValue() {
+    return Float.parseFloat(this.toString());
+  }
+
+  /**
+   * Returns a new {@code BigInteger} whose value is greatest common divisor of
+   * {@code this} and {@code val}. If {@code this==0} and {@code val==0} then
+   * zero is returned, otherwise the result is positive.
+   * 
+   * @param val value with which the greatest common divisor is computed.
+   * @return {@code gcd(this, val)}.
+   * @throws NullPointerException if {@code val == null}.
+   */
+  public BigInteger gcd(BigInteger val) {
+    BigInteger val1 = this.abs();
+    BigInteger val2 = val.abs();
+    // To avoid a possible division by zero
+    if (val1.signum() == 0) {
+      return val2;
+    } else if (val2.signum() == 0) {
+      return val1;
+    }
+
+    // Optimization for small operands
+    // (op2.bitLength() < 64) and (op1.bitLength() < 64)
+    if (((val1.numberLength == 1) || ((val1.numberLength == 2) && (val1.digits[1] > 0)))
+        && (val2.numberLength == 1 || (val2.numberLength == 2 && val2.digits[1] > 0))) {
+      return BigInteger.valueOf(Division.gcdBinary(val1.longValue(),
+          val2.longValue()));
+    }
+
+    return Division.gcdBinary(val1.copy(), val2.copy());
+  }
+
+  /**
+   * Returns the position of the lowest set bit in the two's complement
+   * representation of this {@code BigInteger}. If all bits are zero (this=0)
+   * then -1 is returned as result.
+   * <p>
+   * <b>Implementation Note:</b> Usage of this method is not recommended as the
+   * current implementation is not efficient.
+   * 
+   * @return position of lowest bit if {@code this != 0}, {@code -1} otherwise
+   */
+  public int getLowestSetBit() {
+    if (sign == 0) {
+      return -1;
+    }
+    // (sign != 0) implies that exists some non zero digit
+    int i = getFirstNonzeroDigit();
+    return ((i << 5) + Integer.numberOfTrailingZeros(digits[i]));
+  }
+
+  /**
+   * Returns a hash code for this {@code BigInteger}.
+   * 
+   * @return hash code for {@code this}.
+   */
+  @Override
+  public int hashCode() {
+    if (hashCode != 0) {
+      return hashCode;
+    }
+    for (int i = 0; i < digits.length; i++) {
+      hashCode = (hashCode * 33 + (digits[i] & 0xffffffff));
+    }
+    hashCode = hashCode * sign;
+    return hashCode;
+  }
+
+  /**
+   * Returns this {@code BigInteger} as an int value. If {@code this} is too big
+   * to be represented as an int, then {@code this} % 2^32 is returned.
+   * 
+   * @return this {@code BigInteger} as an int value.
+   */
+  @Override
+  public int intValue() {
+    return (sign * digits[0]);
+  }
+
+  /**
+   * Tests whether this {@code BigInteger} is probably prime. If {@code true} is
+   * returned, then this is prime with a probability beyond (1-1/2^certainty).
+   * If {@code false} is returned, then this is definitely composite. If the
+   * argument {@code certainty} <= 0, then this method returns true.
+   * 
+   * @param certainty tolerated primality uncertainty.
+   * @return {@code true}, if {@code this} is probably prime, {@code false}
+   *         otherwise.
+   */
+  public boolean isProbablePrime(int certainty) {
+    return Primality.isProbablePrime(abs(), certainty);
+  }
+
+  /**
+   * Returns this {@code BigInteger} as an long value. If {@code this} is too
+   * big to be represented as an long, then {@code this} % 2^64 is returned.
+   * 
+   * @return this {@code BigInteger} as a long value.
+   */
+  @Override
+  public long longValue() {
+    long value = (numberLength > 1) ? (((long) digits[1]) << 32)
+        | (digits[0] & 0xFFFFFFFFL) : (digits[0] & 0xFFFFFFFFL);
+    return (sign * value);
+  }
+
+  /**
+   * Returns the maximum of this {@code BigInteger} and {@code val}.
+   * 
+   * @param val value to be used to compute the maximum with {@code this}
+   * @return {@code max(this, val)}
+   * @throws NullPointerException if {@code val == null}
+   */
+  public BigInteger max(BigInteger val) {
+    return ((this.compareTo(val) == GREATER) ? this : val);
+  }
+
+  /**
+   * Returns the minimum of this {@code BigInteger} and {@code val}.
+   * 
+   * @param val value to be used to compute the minimum with {@code this}.
+   * @return {@code min(this, val)}.
+   * @throws NullPointerException if {@code val == null}.
+   */
+  public BigInteger min(BigInteger val) {
+    return ((this.compareTo(val) == LESS) ? this : val);
+  }
+
+  /**
+   * Returns a new {@code BigInteger} whose value is {@code this mod m}. The
+   * modulus {@code m} must be positive. The result is guaranteed to be in the
+   * interval {@code [0, m)} (0 inclusive, m exclusive). The behavior of this
+   * function is not equivalent to the behavior of the % operator defined for
+   * the built-in {@code int}'s.
+   * 
+   * @param m the modulus.
+   * @return {@code this mod m}.
+   * @throws NullPointerException if {@code m == null}.
+   * @throws ArithmeticException if {@code m < 0}.
+   */
+  public BigInteger mod(BigInteger m) {
+    if (m.sign <= 0) {
+      // math.18=BigInteger: modulus not positive
+      throw new ArithmeticException("BigInteger: modulus not positive"); //$NON-NLS-1$
+    }
+    BigInteger rem = remainder(m);
+    return ((rem.sign < 0) ? rem.add(m) : rem);
+  }
+
+  // @Override
+  // public double doubleValue() {
+  // return Conversion.bigInteger2Double(this);
+  // }
+
+  /**
+   * Returns a new {@code BigInteger} whose value is {@code 1/this mod m}. The
+   * modulus {@code m} must be positive. The result is guaranteed to be in the
+   * interval {@code [0, m)} (0 inclusive, m exclusive). If {@code this} is not
+   * relatively prime to m, then an exception is thrown.
+   * 
+   * @param m the modulus.
+   * @return {@code 1/this mod m}.
+   * @throws NullPointerException if {@code m == null}
+   * @throws ArithmeticException if {@code m < 0 or} if {@code this} is not
+   *           relatively prime to {@code m}
+   */
+  public BigInteger modInverse(BigInteger m) {
+    if (m.sign <= 0) {
+      // math.18=BigInteger: modulus not positive
+      throw new ArithmeticException("BigInteger: modulus not positive"); //$NON-NLS-1$
+    }
+    // If both are even, no inverse exists
+    if (!(testBit(0) || m.testBit(0))) {
+      // math.19=BigInteger not invertible.
+      throw new ArithmeticException("BigInteger not invertible."); //$NON-NLS-1$
+    }
+    if (m.isOne()) {
+      return ZERO;
+    }
+
+    // From now on: (m > 1)
+    BigInteger res = Division.modInverseMontgomery(abs().mod(m), m);
+    if (res.sign == 0) {
+      // math.19=BigInteger not invertible.
+      throw new ArithmeticException("BigInteger not invertible."); //$NON-NLS-1$
+    }
+
+    res = ((sign < 0) ? m.subtract(res) : res);
+    return res;
+  }
+
+  /**
+   * Returns a new {@code BigInteger} whose value is {@code this^exponent mod m}
+   * . The modulus {@code m} must be positive. The result is guaranteed to be in
+   * the interval {@code [0, m)} (0 inclusive, m exclusive). If the exponent is
+   * negative, then {@code this.modInverse(m)^(-exponent) mod m)} is computed.
+   * The inverse of this only exists if {@code this} is relatively prime to m,
+   * otherwise an exception is thrown.
+   * 
+   * @param exponent the exponent.
+   * @param m the modulus.
+   * @return {@code this^exponent mod val}.
+   * @throws NullPointerException if {@code m == null} or {@code exponent ==
+   *           null}.
+   * @throws ArithmeticException if {@code m < 0} or if {@code exponent<0} and
+   *           this is not relatively prime to {@code m}.
+   */
+  public BigInteger modPow(BigInteger exponent, BigInteger m) {
+    if (m.sign <= 0) {
+      // math.18=BigInteger: modulus not positive
+      throw new ArithmeticException("BigInteger: modulus not positive"); //$NON-NLS-1$
+    }
+    BigInteger base = this;
+
+    if (m.isOne() | (exponent.sign > 0 & base.sign == 0)) {
+      return BigInteger.ZERO;
+    }
+    if (base.sign == 0 && exponent.sign == 0) {
+      return BigInteger.ONE;
+    }
+    if (exponent.sign < 0) {
+      base = modInverse(m);
+      exponent = exponent.negate();
+    }
+    // From now on: (m > 0) and (exponent >= 0)
+    BigInteger res = (m.testBit(0)) ? Division.oddModPow(base.abs(), exponent,
+        m) : Division.evenModPow(base.abs(), exponent, m);
+    if ((base.sign < 0) && exponent.testBit(0)) {
+      // -b^e mod m == ((-1 mod m) * (b^e mod m)) mod m
+      res = m.subtract(BigInteger.ONE).multiply(res).mod(m);
+    }
+    // else exponent is even, so base^exp is positive
+    return res;
+  }
+
+  /**
+   * Returns a new {@code BigInteger} whose value is {@code this * val}.
+   * 
+   * @param val value to be multiplied with {@code this}.
+   * @return {@code this * val}.
+   * @throws NullPointerException if {@code val == null}.
+   */
+  public BigInteger multiply(BigInteger val) {
+    // This let us to throw NullPointerException when val == null
+    if (val.sign == 0) {
+      return ZERO;
+    }
+    if (sign == 0) {
+      return ZERO;
+    }
+    return Multiplication.multiply(this, val);
+  }
+
+  /**
+   * Returns a new {@code BigInteger} whose value is the {@code -this}.
+   * 
+   * @return {@code -this}.
+   */
+  public BigInteger negate() {
+    return ((sign == 0) ? this : new BigInteger(-sign, numberLength, digits));
+  }
+
+  /**
+   * Returns the smallest integer x > {@code this} which is probably prime as a
+   * {@code BigInteger} instance. The probability that the returned {@code
+   * BigInteger} is prime is beyond (1-1/2^80).
+   * 
+   * @return smallest integer > {@code this} which is robably prime.
+   * @throws ArithmeticException if {@code this < 0}.
+   */
+  public BigInteger nextProbablePrime() {
+    if (sign < 0) {
+      // math.1A=start < 0: {0}
+      throw new ArithmeticException("start < 0: " + this); //$NON-NLS-1$
+    }
+    return Primality.nextProbablePrime(this);
+  }
+
+  /**
+   * Returns a new {@code BigInteger} whose value is {@code ~this}. The result
+   * of this operation is {@code -this-1}.
+   * <p>
+   * <b>Implementation Note:</b> Usage of this method is not recommended as the
+   * current implementation is not efficient.
+   * 
+   * @return {@code ~this}.
+   */
+  public BigInteger not() {
+    return Logical.not(this);
+  }
+
+  /**
+   * Returns a new {@code BigInteger} whose value is {@code this | val}.
+   * <p>
+   * <b>Implementation Note:</b> Usage of this method is not recommended as the
+   * current implementation is not efficient.
+   * 
+   * @param val value to be or'ed with {@code this}.
+   * @return {@code this | val}.
+   * @throws NullPointerException if {@code val == null}.
+   */
+  public BigInteger or(BigInteger val) {
+    return Logical.or(this, val);
+  }
+
+  /**
+   * Returns a new {@code BigInteger} whose value is {@code this ^ exp}.
+   * 
+   * @param exp exponent to which {@code this} is raised.
+   * @return {@code this ^ exp}.
+   * @throws ArithmeticException if {@code exp < 0}.
+   */
+  public BigInteger pow(int exp) {
+    if (exp < 0) {
+      // math.16=Negative exponent
+      throw new ArithmeticException("Negative exponent"); //$NON-NLS-1$
+    }
+    if (exp == 0) {
+      return ONE;
+    } else if (exp == 1 || equals(ONE) || equals(ZERO)) {
+      return this;
+    }
+
+    // if even take out 2^x factor which we can
+    // calculate by shifting.
+    if (!testBit(0)) {
+      int x = 1;
+      while (!testBit(x)) {
+        x++;
+      }
+      return getPowerOfTwo(x * exp).multiply(this.shiftRight(x).pow(exp));
+    }
+    return Multiplication.pow(this, exp);
+  }
+
+  /**
+   * Returns a new {@code BigInteger} whose value is {@code this % divisor}.
+   * Regarding signs this methods has the same behavior as the % operator on
+   * int's, i.e. the sign of the remainder is the same as the sign of this.
+   * 
+   * @param divisor value by which {@code this} is divided.
+   * @return {@code this % divisor}.
+   * @throws NullPointerException if {@code divisor == null}.
+   * @throws ArithmeticException if {@code divisor == 0}.
+   */
+  public BigInteger remainder(BigInteger divisor) {
+    if (divisor.sign == 0) {
+      // math.17=BigInteger divide by zero
+      throw new ArithmeticException("BigInteger divide by zero"); //$NON-NLS-1$
+    }
+    int thisLen = numberLength;
+    int divisorLen = divisor.numberLength;
+    if (((thisLen != divisorLen) ? ((thisLen > divisorLen) ? 1 : -1)
+        : Elementary.compareArrays(digits, divisor.digits, thisLen)) == LESS) {
+      return this;
+    }
+    int resLength = divisorLen;
+    int resDigits[] = new int[resLength];
+    if (resLength == 1) {
+      resDigits[0] = Division.remainderArrayByInt(digits, thisLen,
+          divisor.digits[0]);
+    } else {
+      int qLen = thisLen - divisorLen + 1;
+      resDigits = Division.divide(null, qLen, digits, thisLen, divisor.digits,
+          divisorLen);
+    }
+    BigInteger result = new BigInteger(sign, resLength, resDigits);
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  /**
+   * Returns a new {@code BigInteger} which has the same binary representation
+   * as {@code this} but with the bit at position n set. The result is
+   * equivalent to {@code this | 2^n}.
+   * <p>
+   * <b>Implementation Note:</b> Usage of this method is not recommended as the
+   * current implementation is not efficient.
+   * 
+   * @param n position where the bit in {@code this} has to be set.
+   * @return {@code this | 2^n}.
+   * @throws ArithmeticException if {@code n < 0}.
+   */
+  public BigInteger setBit(int n) {
+    if (!testBit(n)) {
+      return BitLevel.flipBit(this, n);
+    }
+    return this;
+  }
+
+  /**
+   * Returns a new {@code BigInteger} whose value is {@code this << n}. The
+   * result is equivalent to {@code this * 2^n} if n >= 0. The shift distance
+   * may be negative which means that {@code this} is shifted right. The result
+   * then corresponds to {@code floor(this / 2^(-n))}.
+   * <p>
+   * <b>Implementation Note:</b> Usage of this method on negative values is not
+   * recommended as the current implementation is not efficient.
+   * 
+   * @param n shift distance.
+   * @return {@code this << n} if {@code n >= 0}; {@code this >> (-n)}.
+   *         otherwise
+   */
+  public BigInteger shiftLeft(int n) {
+    if ((n == 0) || (sign == 0)) {
+      return this;
+    }
+    return ((n > 0) ? BitLevel.shiftLeft(this, n) : BitLevel.shiftRight(this,
+        -n));
+  }
+
+  /**
+   * Returns a new {@code BigInteger} whose value is {@code this >> n}. For
+   * negative arguments, the result is also negative. The shift distance may be
+   * negative which means that {@code this} is shifted left.
+   * <p>
+   * <b>Implementation Note:</b> Usage of this method on negative values is not
+   * recommended as the current implementation is not efficient.
+   * 
+   * @param n shift distance
+   * @return {@code this >> n} if {@code n >= 0}; {@code this << (-n)} otherwise
+   */
+  public BigInteger shiftRight(int n) {
+    if ((n == 0) || (sign == 0)) {
+      return this;
+    }
+    return ((n > 0) ? BitLevel.shiftRight(this, n) : BitLevel.shiftLeft(this,
+        -n));
+  }
+
+  /**
+   * Returns the sign of this {@code BigInteger}.
+   * 
+   * @return {@code -1} if {@code this < 0}, {@code 0} if {@code this == 0},
+   *         {@code 1} if {@code this > 0}.
+   */
+  public int signum() {
+    return sign;
+  }
+
+  /**
+   * Returns a new {@code BigInteger} whose value is {@code this - val}.
+   * 
+   * @param val value to be subtracted from {@code this}.
+   * @return {@code this - val}.
+   * @throws NullPointerException if {@code val == null}.
+   */
+  public BigInteger subtract(BigInteger val) {
+    return Elementary.subtract(this, val);
+  }
+
+  /**
+   * Tests whether the bit at position n in {@code this} is set. The result is
+   * equivalent to {@code this & (2^n) != 0}.
+   * <p>
+   * <b>Implementation Note:</b> Usage of this method is not recommended as the
+   * current implementation is not efficient.
+   * 
+   * @param n position where the bit in {@code this} has to be inspected.
+   * @return {@code this & (2^n) != 0}.
+   * @throws ArithmeticException if {@code n < 0}.
+   */
+  public boolean testBit(int n) {
+    if (n == 0) {
+      return ((digits[0] & 1) != 0);
+    }
+    if (n < 0) {
+      // math.15=Negative bit address
+      throw new ArithmeticException("Negative bit address"); //$NON-NLS-1$
+    }
+    int intCount = n >> 5;
+    if (intCount >= numberLength) {
+      return (sign < 0);
+    }
+    int digit = digits[intCount];
+    n = (1 << (n & 31)); // int with 1 set to the needed position
+    if (sign < 0) {
+      int firstNonZeroDigit = getFirstNonzeroDigit();
+      if (intCount < firstNonZeroDigit) {
+        return false;
+      } else if (firstNonZeroDigit == intCount) {
+        digit = -digit;
+      } else {
+        digit = ~digit;
+      }
+    }
+    return ((digit & n) != 0);
+  }
+
+  /**
+   * Returns the two's complement representation of this BigInteger in a byte
+   * array.
+   * 
+   * @return two's complement representation of {@code this}.
+   */
+  public byte[] toByteArray() {
+    if (this.sign == 0) {
+      return new byte[] {0};
+    }
+    BigInteger temp = this;
+    int bitLen = bitLength();
+    int iThis = getFirstNonzeroDigit();
+    int bytesLen = (bitLen >> 3) + 1;
+    /*
+     * Puts the little-endian int array representing the magnitude of this
+     * BigInteger into the big-endian byte array.
+     */
+    byte[] bytes = new byte[bytesLen];
+    int firstByteNumber = 0;
+    int highBytes;
+    int digitIndex = 0;
+    int bytesInInteger = 4;
+    int digit;
+    int hB;
+
+    if (bytesLen - (numberLength << 2) == 1) {
+      bytes[0] = (byte) ((sign < 0) ? -1 : 0);
+      highBytes = 4;
+      firstByteNumber++;
+    } else {
+      hB = bytesLen & 3;
+      highBytes = (hB == 0) ? 4 : hB;
+    }
+
+    digitIndex = iThis;
+    bytesLen -= iThis << 2;
+
+    if (sign < 0) {
+      digit = -temp.digits[digitIndex];
+      digitIndex++;
+      if (digitIndex == numberLength) {
+        bytesInInteger = highBytes;
+      }
+      for (int i = 0; i < bytesInInteger; i++, digit >>= 8) {
+        bytes[--bytesLen] = (byte) digit;
+      }
+      while (bytesLen > firstByteNumber) {
+        digit = ~temp.digits[digitIndex];
+        digitIndex++;
+        if (digitIndex == numberLength) {
+          bytesInInteger = highBytes;
+        }
+        for (int i = 0; i < bytesInInteger; i++, digit >>= 8) {
+          bytes[--bytesLen] = (byte) digit;
+        }
+      }
+    } else {
+      while (bytesLen > firstByteNumber) {
+        digit = temp.digits[digitIndex];
+        digitIndex++;
+        if (digitIndex == numberLength) {
+          bytesInInteger = highBytes;
+        }
+        for (int i = 0; i < bytesInInteger; i++, digit >>= 8) {
+          bytes[--bytesLen] = (byte) digit;
+        }
+      }
+    }
+    return bytes;
+  }
+
+  /**
+   * Returns a string representation of this {@code BigInteger} in decimal form.
+   * 
+   * @return a string representation of {@code this} in decimal form.
+   */
+  @Override
+  public String toString() {
+    return Conversion.toDecimalScaledString(this, 0);
+  }
+
+  /**
+   * Returns a string containing a string representation of this {@code
+   * BigInteger} with base radix. If {@code radix} is less than
+   * {@link Character#MIN_RADIX} or greater than {@link Character#MAX_RADIX}
+   * then a decimal representation is returned. The characters of the string
+   * representation are generated with method {@link Character#forDigit}.
+   * 
+   * @param radix base to be used for the string representation.
+   * @return a string representation of this with radix 10.
+   */
+  public String toString(int radix) {
+    return Conversion.bigInteger2String(this, radix);
+  }
+
+  /**
+   * Returns a new {@code BigInteger} whose value is {@code this ^ val}.
+   * <p>
+   * <b>Implementation Note:</b> Usage of this method is not recommended as the
+   * current implementation is not efficient.
+   * 
+   * @param val value to be xor'ed with {@code this}
+   * @return {@code this ^ val}
+   * @throws NullPointerException if {@code val == null}
+   */
+  public BigInteger xor(BigInteger val) {
+    return Logical.xor(this, val);
+  }
+
+  /*
+   * Returns a copy of the current instance to achieve immutability
+   */
+  BigInteger copy() {
+    int[] copyDigits = new int[numberLength];
+    System.arraycopy(digits, 0, copyDigits, 0, numberLength);
+    return new BigInteger(sign, numberLength, copyDigits);
+  }
+
+  /* Private Methods */
+
+  /**
+   * Decreases {@code numberLength} if there are zero high elements.
+   */
+  final void cutOffLeadingZeroes() {
+    while ((numberLength > 0) && (digits[--numberLength] == 0)) {
+      // Empty
+    }
+    if (digits[numberLength++] == 0) {
+      sign = 0;
+    }
+  }
+
+  boolean equalsArrays(final int[] b) {
+    int i;
+    for (i = numberLength - 1; (i >= 0) && (digits[i] == b[i]); i--) {
+      // Empty
+    }
+    return i < 0;
+  }
+
+  int getFirstNonzeroDigit() {
+    if (firstNonzeroDigit == -2) {
+      int i;
+      if (this.sign == 0) {
+        i = -1;
+      } else {
+        for (i = 0; digits[i] == 0; i++) {
+          // Empty
+        }
+      }
+      firstNonzeroDigit = i;
+    }
+    return firstNonzeroDigit;
+  }
+
+  /**
+   * Tests if {@code this.abs()} is equals to {@code ONE}
+   */
+  boolean isOne() {
+    return ((numberLength == 1) && (digits[0] == 1));
+  }
+
+  BigInteger shiftLeftOneBit() {
+    return (sign == 0) ? this : BitLevel.shiftLeftOneBit(this);
+  }
+
+  void unCache() {
+    firstNonzeroDigit = -2;
+  }
+
+  /**
+   * Puts a big-endian byte array into a little-endian applying two complement.
+   */
+  private void putBytesNegativeToIntegers(byte[] byteValues) {
+    int bytesLen = byteValues.length;
+    int highBytes = bytesLen & 3;
+    numberLength = (bytesLen >> 2) + ((highBytes == 0) ? 0 : 1);
+    digits = new int[numberLength];
+    int i = 0;
+    // Setting the sign
+    digits[numberLength - 1] = -1;
+    // Put bytes to the int array starting from the end of the byte array
+    while (bytesLen > highBytes) {
+      digits[i] = (byteValues[--bytesLen] & 0xFF)
+          | (byteValues[--bytesLen] & 0xFF) << 8
+          | (byteValues[--bytesLen] & 0xFF) << 16
+          | (byteValues[--bytesLen] & 0xFF) << 24;
+      if (digits[i] != 0) {
+        digits[i] = -digits[i];
+        firstNonzeroDigit = i;
+        i++;
+        while (bytesLen > highBytes) {
+          digits[i] = (byteValues[--bytesLen] & 0xFF)
+              | (byteValues[--bytesLen] & 0xFF) << 8
+              | (byteValues[--bytesLen] & 0xFF) << 16
+              | (byteValues[--bytesLen] & 0xFF) << 24;
+          digits[i] = ~digits[i];
+          i++;
+        }
+        break;
+      }
+      i++;
+    }
+    if (highBytes != 0) {
+      // Put the first bytes in the highest element of the int array
+      if (firstNonzeroDigit != -2) {
+        for (int j = 0; j < bytesLen; j++) {
+          digits[i] = (digits[i] << 8) | (byteValues[j] & 0xFF);
+        }
+        digits[i] = ~digits[i];
+      } else {
+        for (int j = 0; j < bytesLen; j++) {
+          digits[i] = (digits[i] << 8) | (byteValues[j] & 0xFF);
+        }
+        digits[i] = -digits[i];
+      }
+    }
+  }
+
+  /**
+   * Puts a big-endian byte array into a little-endian int array.
+   */
+  private void putBytesPositiveToIntegers(byte[] byteValues) {
+    int bytesLen = byteValues.length;
+    int highBytes = bytesLen & 3;
+    numberLength = (bytesLen >> 2) + ((highBytes == 0) ? 0 : 1);
+    digits = new int[numberLength];
+    int i = 0;
+    // Put bytes to the int array starting from the end of the byte array
+    while (bytesLen > highBytes) {
+      digits[i++] = (byteValues[--bytesLen] & 0xFF)
+          | (byteValues[--bytesLen] & 0xFF) << 8
+          | (byteValues[--bytesLen] & 0xFF) << 16
+          | (byteValues[--bytesLen] & 0xFF) << 24;
+    }
+    // Put the first bytes in the highest element of the int array
+    for (int j = 0; j < bytesLen; j++) {
+      digits[i] = (digits[i] << 8) | (byteValues[j] & 0xFF);
+    }
+  }
+}
diff --git a/user/super/com/google/gwt/emul/java/math/BitLevel.java b/user/super/com/google/gwt/emul/java/math/BitLevel.java
new file mode 100644
index 0000000..b539637
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/math/BitLevel.java
@@ -0,0 +1,379 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE.
+ */
+package java.math;
+
+/**
+ * Static library that provides all the <b>bit level</b> operations for
+ * {@link BigInteger}. The operations are: <ul type="circle"> <li>Left Shifting</li>
+ * <li>Right Shifting</li> <li>Bit clearing</li> <li>Bit setting</li> <li>Bit
+ * counting</li> <li>Bit testing</li> <li>Getting of the lowest bit set</li>
+ * </ul> All operations are provided in immutable way, and some in both mutable
+ * and immutable.
+ */
+class BitLevel {
+
+  /**
+   * @see BigInteger#bitCount()
+   * @param val
+   * @return
+   */
+  static int bitCount(BigInteger val) {
+    int bCount = 0;
+
+    if (val.sign == 0) {
+      return 0;
+    }
+
+    int i = val.getFirstNonzeroDigit();
+    if (val.sign > 0) {
+      for (; i < val.numberLength; i++) {
+        bCount += Integer.bitCount(val.digits[i]);
+      }
+    } else {
+      // (sign < 0)
+      // this digit absorbs the carry
+      bCount += Integer.bitCount(-val.digits[i]);
+      for (i++; i < val.numberLength; i++) {
+        bCount += Integer.bitCount(~val.digits[i]);
+      }
+      // We take the complement sum:
+      bCount = (val.numberLength << 5) - bCount;
+    }
+    return bCount;
+  }
+
+  /**
+   * @see BigInteger#bitLength()
+   * @param val
+   * @return
+   */
+  static int bitLength(BigInteger val) {
+    if (val.sign == 0) {
+      return 0;
+    }
+    int bLength = (val.numberLength << 5);
+    int highDigit = val.digits[val.numberLength - 1];
+
+    if (val.sign < 0) {
+      int i = val.getFirstNonzeroDigit();
+      // We reduce the problem to the positive case.
+      if (i == val.numberLength - 1) {
+        // ~~ is to handle int overflow
+        highDigit = ~~(highDigit - 1);
+      }
+    }
+    // Subtracting all sign bits
+    bLength -= Integer.numberOfLeadingZeros(highDigit);
+    return bLength;
+  }
+
+  /**
+   * Performs a flipBit on the BigInteger, returning a BigInteger with the the
+   * specified bit flipped.
+   * 
+   * @param val BigInteger to operate on
+   * @param n the bit to flip
+   */
+  static BigInteger flipBit(BigInteger val, int n) {
+    int resSign = (val.sign == 0) ? 1 : val.sign;
+    int intCount = n >> 5;
+    int bitN = n & 31;
+    int resLength = Math.max(intCount + 1, val.numberLength) + 1;
+    int resDigits[] = new int[resLength];
+    int i;
+
+    int bitNumber = 1 << bitN;
+    System.arraycopy(val.digits, 0, resDigits, 0, val.numberLength);
+
+    if (val.sign < 0) {
+      if (intCount >= val.numberLength) {
+        resDigits[intCount] = bitNumber;
+      } else {
+        // val.sign<0 y intCount < val.numberLength
+        int firstNonZeroDigit = val.getFirstNonzeroDigit();
+        if (intCount > firstNonZeroDigit) {
+          resDigits[intCount] ^= bitNumber;
+        } else if (intCount < firstNonZeroDigit) {
+          resDigits[intCount] = -bitNumber;
+          for (i = intCount + 1; i < firstNonZeroDigit; i++) {
+            resDigits[i] = -1;
+          }
+          resDigits[i] = resDigits[i]--;
+        } else {
+          i = intCount;
+          resDigits[i] = -((-resDigits[intCount]) ^ bitNumber);
+          if (resDigits[i] == 0) {
+            for (i++; resDigits[i] == -1; i++) {
+              resDigits[i] = 0;
+            }
+            resDigits[i]++;
+          }
+        }
+      }
+    } else {
+      // case where val is positive
+      resDigits[intCount] ^= bitNumber;
+    }
+    BigInteger result = new BigInteger(resSign, resLength, resDigits);
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  /**
+   * Performs {@code val <<= count}.
+   */
+  // val should have enough place (and one digit more)
+  static void inplaceShiftLeft(BigInteger val, int count) {
+    int intCount = count >> 5; // count of integers
+    val.numberLength += intCount
+        + (Integer.numberOfLeadingZeros(val.digits[val.numberLength - 1])
+            - (count & 31) >= 0 ? 0 : 1);
+    shiftLeft(val.digits, val.digits, intCount, count & 31);
+    val.cutOffLeadingZeroes();
+    val.unCache();
+  }
+
+  /**
+   * Performs {@code val >>= count} where {@code val} is a positive number.
+   */
+  static void inplaceShiftRight(BigInteger val, int count) {
+    int sign = val.signum();
+    if (count == 0 || val.signum() == 0) {
+      return;
+    }
+    int intCount = count >> 5; // count of integers
+    val.numberLength -= intCount;
+    if (!shiftRight(val.digits, val.numberLength, val.digits, intCount,
+        count & 31)
+        && sign < 0) {
+      // remainder not zero: add one to the result
+      int i;
+      for (i = 0; (i < val.numberLength) && (val.digits[i] == -1); i++) {
+        val.digits[i] = 0;
+      }
+      if (i == val.numberLength) {
+        val.numberLength++;
+      }
+      val.digits[i]++;
+    }
+    val.cutOffLeadingZeroes();
+    val.unCache();
+  }
+
+  /**
+   * Check if there are 1s in the lowest bits of this BigInteger.
+   * 
+   * @param numberOfBits the number of the lowest bits to check
+   * @return false if all bits are 0s, true otherwise
+   */
+  static boolean nonZeroDroppedBits(int numberOfBits, int digits[]) {
+    int intCount = numberOfBits >> 5;
+    int bitCount = numberOfBits & 31;
+    int i;
+
+    for (i = 0; (i < intCount) && (digits[i] == 0); i++) {
+    }
+    return ((i != intCount) || (digits[i] << (32 - bitCount) != 0));
+  }
+
+  /**
+   * @see BigInteger#shiftLeft(int)
+   * @param source
+   * @param count
+   * @return
+   */
+  static BigInteger shiftLeft(BigInteger source, int count) {
+    int intCount = count >> 5;
+    count &= 31; // %= 32
+    int resLength = source.numberLength + intCount + ((count == 0) ? 0 : 1);
+    int resDigits[] = new int[resLength];
+
+    shiftLeft(resDigits, source.digits, intCount, count);
+    BigInteger result = new BigInteger(source.sign, resLength, resDigits);
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  /**
+   * Abstractly shifts left an array of integers in little endian (i.e. shift it
+   * right). Total shift distance in bits is intCount * 32 + count
+   * 
+   * @param result the destination array
+   * @param source the source array
+   * @param intCount the shift distance in integers
+   * @param count an additional shift distance in bits
+   */
+  static void shiftLeft(int result[], int source[], int intCount, int count) {
+    if (count == 0) {
+      System.arraycopy(source, 0, result, intCount, result.length - intCount);
+    } else {
+      int rightShiftCount = 32 - count;
+
+      result[result.length - 1] = 0;
+      for (int i = result.length - 1; i > intCount; i--) {
+        result[i] |= source[i - intCount - 1] >>> rightShiftCount;
+        result[i - 1] = source[i - intCount - 1] << count;
+      }
+    }
+
+    for (int i = 0; i < intCount; i++) {
+      result[i] = 0;
+    }
+  }
+
+  static BigInteger shiftLeftOneBit(BigInteger source) {
+    int srcLen = source.numberLength;
+    int resLen = srcLen + 1;
+    int resDigits[] = new int[resLen];
+    shiftLeftOneBit(resDigits, source.digits, srcLen);
+    BigInteger result = new BigInteger(source.sign, resLen, resDigits);
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  /**
+   * Shifts the source digits left one bit, creating a value whose magnitude is
+   * doubled.
+   * 
+   * @param result an array of digits that will hold the computed result when
+   *          this method returns. The size of this array is {@code srcLen + 1},
+   *          and the format is the same as {@link BigInteger#digits}.
+   * @param source the array of digits to shift left, in the same format as
+   *          {@link BigInteger#digits}.
+   * @param srcLen the length of {@code source}; may be less than {@code
+   *          source.length}
+   */
+  static void shiftLeftOneBit(int result[], int source[], int srcLen) {
+    int carry = 0;
+    for (int i = 0; i < srcLen; i++) {
+      int val = source[i];
+      result[i] = (val << 1) | carry;
+      carry = val >>> 31;
+    }
+    if (carry != 0) {
+      result[srcLen] = carry;
+    }
+  }
+
+  /**
+   * @see BigInteger#shiftRight(int)
+   * @param source
+   * @param count
+   * @return
+   */
+  static BigInteger shiftRight(BigInteger source, int count) {
+    int intCount = count >> 5; // count of integers
+    count &= 31; // count of remaining bits
+    if (intCount >= source.numberLength) {
+      return ((source.sign < 0) ? BigInteger.MINUS_ONE : BigInteger.ZERO);
+    }
+    int i;
+    int resLength = source.numberLength - intCount;
+    int resDigits[] = new int[resLength + 1];
+
+    shiftRight(resDigits, resLength, source.digits, intCount, count);
+    if (source.sign < 0) {
+      // Checking if the dropped bits are zeros (the remainder equals to
+      // 0)
+      for (i = 0; (i < intCount) && (source.digits[i] == 0); i++) {
+      }
+      // If the remainder is not zero, add 1 to the result
+      if ((i < intCount)
+          || ((count > 0) && ((source.digits[i] << (32 - count)) != 0))) {
+        for (i = 0; (i < resLength) && (resDigits[i] == -1); i++) {
+          resDigits[i] = 0;
+        }
+        if (i == resLength) {
+          resLength++;
+        }
+        resDigits[i]++;
+      }
+    }
+    BigInteger result = new BigInteger(source.sign, resLength, resDigits);
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  /**
+   * Shifts right an array of integers. Total shift distance in bits is intCount
+   * * 32 + count.
+   * 
+   * @param result the destination array
+   * @param resultLen the destination array's length
+   * @param source the source array
+   * @param intCount the number of elements to be shifted
+   * @param count the number of bits to be shifted
+   * @return dropped bit's are all zero (i.e. remaider is zero)
+   */
+  static boolean shiftRight(int result[], int resultLen, int source[],
+      int intCount, int count) {
+    int i;
+    boolean allZero = true;
+    for (i = 0; i < intCount; i++) {
+      allZero &= source[i] == 0;
+    }
+    if (count == 0) {
+      System.arraycopy(source, intCount, result, 0, resultLen);
+      i = resultLen;
+    } else {
+      int leftShiftCount = 32 - count;
+
+      allZero &= (source[i] << leftShiftCount) == 0;
+      for (i = 0; i < resultLen - 1; i++) {
+        result[i] = (source[i + intCount] >>> count)
+            | (source[i + intCount + 1] << leftShiftCount);
+      }
+      result[i] = (source[i + intCount] >>> count);
+      i++;
+    }
+
+    return allZero;
+  }
+
+  /**
+   * Performs a fast bit testing for positive numbers. The bit to to be tested
+   * must be in the range {@code [0, val.bitLength()-1]}
+   */
+  static boolean testBit(BigInteger val, int n) {
+    // PRE: 0 <= n < val.bitLength()
+    return ((val.digits[n >> 5] & (1 << (n & 31))) != 0);
+  }
+
+  /**
+   * Just to denote that this class can't be instantiated.
+   */
+  private BitLevel() {
+  }
+}
diff --git a/user/super/com/google/gwt/emul/java/math/Conversion.java b/user/super/com/google/gwt/emul/java/math/Conversion.java
new file mode 100644
index 0000000..28b8a95
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/math/Conversion.java
@@ -0,0 +1,488 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE.
+ */
+package java.math;
+
+/**
+ * Static library that provides {@link BigInteger} base conversion from/to any
+ * integer represented in an {@link java.lang.String} Object.
+ */
+class Conversion {
+
+  /**
+   * bigRadices values are precomputed maximal powers of radices (integer
+   * numbers from 2 to 36) that fit into unsigned int (32 bits). bigRadices[0] =
+   * 2 ^ 31, bigRadices[8] = 10 ^ 9, etc.
+   */
+
+  static final int bigRadices[] = {
+      -2147483648, 1162261467, 1073741824, 1220703125, 362797056, 1977326743,
+      1073741824, 387420489, 1000000000, 214358881, 429981696, 815730721,
+      1475789056, 170859375, 268435456, 410338673, 612220032, 893871739,
+      1280000000, 1801088541, 113379904, 148035889, 191102976, 244140625,
+      308915776, 387420489, 481890304, 594823321, 729000000, 887503681,
+      1073741824, 1291467969, 1544804416, 1838265625, 60466176};
+
+  /**
+   * Holds the maximal exponent for each radix, so that
+   * radix<sup>digitFitInInt[radix]</sup> fit in an {@code int} (32 bits).
+   */
+  static final int[] digitFitInInt = {
+      -1, -1, 31, 19, 15, 13, 11, 11, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7,
+      7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5};
+
+  /**
+   * @see BigInteger#toString(int)
+   * @param val
+   * @param radix
+   * @return
+   */
+  static String bigInteger2String(BigInteger val, int radix) {
+    int sign = val.sign;
+    int numberLength = val.numberLength;
+    int digits[] = val.digits;
+
+    if (sign == 0) {
+      return "0"; //$NON-NLS-1$
+    }
+    if (numberLength == 1) {
+      int highDigit = digits[numberLength - 1];
+      long v = highDigit & 0xFFFFFFFFL;
+      if (sign < 0) {
+        v = -v;
+      }
+      return Long.toString(v, radix);
+    }
+    if ((radix == 10) || (radix < Character.MIN_RADIX)
+        || (radix > Character.MAX_RADIX)) {
+      return val.toString();
+    }
+    double bitsForRadixDigit;
+    bitsForRadixDigit = Math.log(radix) / Math.log(2);
+    int resLengthInChars = (int) (val.abs().bitLength() / bitsForRadixDigit + ((sign < 0)
+        ? 1 : 0)) + 1;
+
+    char result[] = new char[resLengthInChars];
+    int currentChar = resLengthInChars;
+    int resDigit;
+    if (radix != 16) {
+      int temp[] = new int[numberLength];
+      System.arraycopy(digits, 0, temp, 0, numberLength);
+      int tempLen = numberLength;
+      int charsPerInt = digitFitInInt[radix];
+      int i;
+      // get the maximal power of radix that fits in int
+      int bigRadix = bigRadices[radix - 2];
+      while (true) {
+        // divide the array of digits by bigRadix and convert remainders
+        // to characters collecting them in the char array
+        resDigit = Division.divideArrayByInt(temp, temp, tempLen, bigRadix);
+        int previous = currentChar;
+        do {
+          result[--currentChar] = Character.forDigit(resDigit % radix, radix);
+        } while (((resDigit /= radix) != 0) && (currentChar != 0));
+        int delta = charsPerInt - previous + currentChar;
+        for (i = 0; i < delta && currentChar > 0; i++) {
+          result[--currentChar] = '0';
+        }
+        for (i = tempLen - 1; (i > 0) && (temp[i] == 0); i--) {
+          // empty
+        }
+        tempLen = i + 1;
+        if ((tempLen == 1) && (temp[0] == 0)) { // the quotient is 0
+          break;
+        }
+      }
+    } else {
+      // radix == 16
+      for (int i = 0; i < numberLength; i++) {
+        for (int j = 0; (j < 8) && (currentChar > 0); j++) {
+          resDigit = digits[i] >> (j << 2) & 0xf;
+          result[--currentChar] = Character.forDigit(resDigit, 16);
+        }
+      }
+    }
+    while (result[currentChar] == '0') {
+      currentChar++;
+    }
+    if (sign == -1) {
+      result[--currentChar] = '-';
+    }
+    return new String(result, currentChar, resLengthInChars - currentChar);
+  }
+
+  static long divideLongByBillion(long a) {
+    long quot;
+    long rem;
+
+    if (a >= 0) {
+      long bLong = 1000000000L;
+      quot = (a / bLong);
+      rem = (a % bLong);
+    } else {
+      /*
+       * Make the dividend positive shifting it right by 1 bit then get the
+       * quotient an remainder and correct them properly
+       */
+      long aPos = a >>> 1;
+      long bPos = 1000000000L >>> 1;
+      quot = aPos / bPos;
+      rem = aPos % bPos;
+      // double the remainder and add 1 if 'a' is odd
+      rem = (rem << 1) + (a & 1);
+    }
+    return ((rem << 32) | (quot & 0xFFFFFFFFL));
+  }
+
+  /**
+   * Builds the correspondent {@code String} representation of {@code val} being
+   * scaled by {@code scale}.
+   * 
+   * @see BigInteger#toString()
+   * @see BigDecimal#toString()
+   */
+  static String toDecimalScaledString(BigInteger val, int scale) {
+    int sign = val.sign;
+    int numberLength = val.numberLength;
+    int digits[] = val.digits;
+    int resLengthInChars;
+    int currentChar;
+    char result[];
+
+    if (sign == 0) {
+      switch (scale) {
+        case 0:
+          return "0"; //$NON-NLS-1$
+        case 1:
+          return "0.0"; //$NON-NLS-1$
+        case 2:
+          return "0.00"; //$NON-NLS-1$
+        case 3:
+          return "0.000"; //$NON-NLS-1$
+        case 4:
+          return "0.0000"; //$NON-NLS-1$
+        case 5:
+          return "0.00000"; //$NON-NLS-1$
+        case 6:
+          return "0.000000"; //$NON-NLS-1$
+        default:
+          StringBuilder result1 = new StringBuilder();
+          if (scale < 0) {
+            result1.append("0E+"); //$NON-NLS-1$
+          } else {
+            result1.append("0E"); //$NON-NLS-1$
+          }
+          result1.append(-scale);
+          return result1.toString();
+      }
+    }
+    // one 32-bit unsigned value may contains 10 decimal digits
+    resLengthInChars = numberLength * 10 + 1 + 7;
+    // Explanation why +1+7:
+    // +1 - one char for sign if needed.
+    // +7 - For "special case 2" (see below) we have 7 free chars for
+    // inserting necessary scaled digits.
+    result = new char[resLengthInChars + 1];
+    // allocated [resLengthInChars+1] characters.
+    // a free latest character may be used for "special case 1" (see
+    // below)
+    currentChar = resLengthInChars;
+    if (numberLength == 1) {
+      int highDigit = digits[0];
+      if (highDigit < 0) {
+        long v = highDigit & 0xFFFFFFFFL;
+        do {
+          long prev = v;
+          v /= 10;
+          result[--currentChar] = (char) (0x0030 + ((int) (prev - v * 10)));
+        } while (v != 0);
+      } else {
+        int v = highDigit;
+        do {
+          int prev = v;
+          v /= 10;
+          result[--currentChar] = (char) (0x0030 + (prev - v * 10));
+        } while (v != 0);
+      }
+    } else {
+      int temp[] = new int[numberLength];
+      int tempLen = numberLength;
+      System.arraycopy(digits, 0, temp, 0, tempLen);
+      BIG_LOOP : while (true) {
+        // divide the array of digits by bigRadix and convert
+        // remainders
+        // to characters collecting them in the char array
+        long result11 = 0;
+        for (int i1 = tempLen - 1; i1 >= 0; i1--) {
+          long temp1 = (result11 << 32) + (temp[i1] & 0xFFFFFFFFL);
+          long res = divideLongByBillion(temp1);
+          temp[i1] = (int) res;
+          result11 = (int) (res >> 32);
+        }
+        int resDigit = (int) result11;
+        int previous = currentChar;
+        do {
+          result[--currentChar] = (char) (0x0030 + (resDigit % 10));
+        } while (((resDigit /= 10) != 0) && (currentChar != 0));
+        int delta = 9 - previous + currentChar;
+        for (int i = 0; (i < delta) && (currentChar > 0); i++) {
+          result[--currentChar] = '0';
+        }
+        int j = tempLen - 1;
+        for (; temp[j] == 0; j--) {
+          if (j == 0) { // means temp[0] == 0
+            break BIG_LOOP;
+          }
+        }
+        tempLen = j + 1;
+      }
+      while (result[currentChar] == '0') {
+        currentChar++;
+      }
+    }
+    boolean negNumber = (sign < 0);
+    int exponent = resLengthInChars - currentChar - scale - 1;
+    if (scale == 0) {
+      if (negNumber) {
+        result[--currentChar] = '-';
+      }
+      return new String(result, currentChar, resLengthInChars - currentChar);
+    }
+    if ((scale > 0) && (exponent >= -6)) {
+      if (exponent >= 0) {
+        // special case 1
+        int insertPoint = currentChar + exponent;
+        for (int j = resLengthInChars - 1; j >= insertPoint; j--) {
+          result[j + 1] = result[j];
+        }
+        result[++insertPoint] = '.';
+        if (negNumber) {
+          result[--currentChar] = '-';
+        }
+        return new String(result, currentChar, resLengthInChars - currentChar
+            + 1);
+      }
+      // special case 2
+      for (int j = 2; j < -exponent + 1; j++) {
+        result[--currentChar] = '0';
+      }
+      result[--currentChar] = '.';
+      result[--currentChar] = '0';
+      if (negNumber) {
+        result[--currentChar] = '-';
+      }
+      return new String(result, currentChar, resLengthInChars - currentChar);
+    }
+    int startPoint = currentChar + 1;
+    int endPoint = resLengthInChars;
+    StringBuilder result1 = new StringBuilder(16 + endPoint - startPoint);
+    if (negNumber) {
+      result1.append('-');
+    }
+    if (endPoint - startPoint >= 1) {
+      result1.append(result[currentChar]);
+      result1.append('.');
+      result1.append(result, currentChar + 1, resLengthInChars - currentChar
+          - 1);
+    } else {
+      result1.append(result, currentChar, resLengthInChars - currentChar);
+    }
+    result1.append('E');
+    if (exponent > 0) {
+      result1.append('+');
+    }
+    result1.append(Integer.toString(exponent));
+    return result1.toString();
+  }
+
+  /* can process only 32-bit numbers */
+  static String toDecimalScaledString(long value, int scale) {
+    int resLengthInChars;
+    int currentChar;
+    char result[];
+    boolean negNumber = value < 0;
+    if (negNumber) {
+      value = -value;
+    }
+    if (value == 0) {
+      switch (scale) {
+        case 0:
+          return "0"; //$NON-NLS-1$
+        case 1:
+          return "0.0"; //$NON-NLS-1$
+        case 2:
+          return "0.00"; //$NON-NLS-1$
+        case 3:
+          return "0.000"; //$NON-NLS-1$
+        case 4:
+          return "0.0000"; //$NON-NLS-1$
+        case 5:
+          return "0.00000"; //$NON-NLS-1$
+        case 6:
+          return "0.000000"; //$NON-NLS-1$
+        default:
+          StringBuilder result1 = new StringBuilder();
+          if (scale < 0) {
+            result1.append("0E+"); //$NON-NLS-1$
+          } else {
+            result1.append("0E"); //$NON-NLS-1$
+          }
+          result1.append((scale == Integer.MIN_VALUE)
+              ? "2147483648" : Integer.toString(-scale)); //$NON-NLS-1$
+          return result1.toString();
+      }
+    }
+    // one 32-bit unsigned value may contains 10 decimal digits
+    resLengthInChars = 18;
+    // Explanation why +1+7:
+    // +1 - one char for sign if needed.
+    // +7 - For "special case 2" (see below) we have 7 free chars for
+    // inserting necessary scaled digits.
+    result = new char[resLengthInChars + 1];
+    // Allocated [resLengthInChars+1] characters.
+    // a free latest character may be used for "special case 1" (see below)
+    currentChar = resLengthInChars;
+    long v = value;
+    do {
+      long prev = v;
+      v /= 10;
+      result[--currentChar] = (char) (0x0030 + (prev - v * 10));
+    } while (v != 0);
+
+    long exponent = (long) resLengthInChars - (long) currentChar - scale - 1L;
+    if (scale == 0) {
+      if (negNumber) {
+        result[--currentChar] = '-';
+      }
+      return new String(result, currentChar, resLengthInChars - currentChar);
+    }
+    if (scale > 0 && exponent >= -6) {
+      if (exponent >= 0) {
+        // special case 1
+        int insertPoint = currentChar + (int) exponent;
+        for (int j = resLengthInChars - 1; j >= insertPoint; j--) {
+          result[j + 1] = result[j];
+        }
+        result[++insertPoint] = '.';
+        if (negNumber) {
+          result[--currentChar] = '-';
+        }
+        return new String(result, currentChar, resLengthInChars - currentChar
+            + 1);
+      }
+      // special case 2
+      for (int j = 2; j < -exponent + 1; j++) {
+        result[--currentChar] = '0';
+      }
+      result[--currentChar] = '.';
+      result[--currentChar] = '0';
+      if (negNumber) {
+        result[--currentChar] = '-';
+      }
+      return new String(result, currentChar, resLengthInChars - currentChar);
+    }
+    int startPoint = currentChar + 1;
+    int endPoint = resLengthInChars;
+    StringBuilder result1 = new StringBuilder(16 + endPoint - startPoint);
+    if (negNumber) {
+      result1.append('-');
+    }
+    if (endPoint - startPoint >= 1) {
+      result1.append(result[currentChar]);
+      result1.append('.');
+      result1.append(result, currentChar + 1, resLengthInChars - currentChar
+          - 1);
+    } else {
+      result1.append(result, currentChar, resLengthInChars - currentChar);
+    }
+    result1.append('E');
+    if (exponent > 0) {
+      result1.append('+');
+    }
+    result1.append(Long.toString(exponent));
+    return result1.toString();
+  }
+
+  /**
+   * Just to denote that this class can't be instantiated.
+   */
+  private Conversion() {
+  }
+
+//   /**
+//    * @see BigInteger#doubleValue()
+//    */
+  // static double bigInteger2Double(BigInteger val) {
+  // // val.bitLength() < 64
+  // if ((val.numberLength < 2)
+  // || ((val.numberLength == 2) && (val.digits[1] > 0))) {
+  // return val.longValue();
+  // }
+  // // val.bitLength() >= 33 * 32 > 1024
+  // if (val.numberLength > 32) {
+  // return ((val.sign > 0) ? Double.POSITIVE_INFINITY
+  // : Double.NEGATIVE_INFINITY);
+  // }
+  // int bitLen = val.abs().bitLength();
+  // long exponent = bitLen - 1;
+  // int delta = bitLen - 54;
+  // // We need 54 top bits from this, the 53th bit is always 1 in lVal.
+  // long lVal = val.abs().shiftRight(delta).longValue();
+  // /*
+  // * Take 53 bits from lVal to mantissa. The least significant bit is
+  // * needed for rounding.
+  // */
+  // long mantissa = lVal & 0x1FFFFFFFFFFFFFL;
+  // if (exponent == 1023) {
+  // if (mantissa == 0X1FFFFFFFFFFFFFL) {
+  // return ((val.sign > 0) ? Double.POSITIVE_INFINITY
+  // : Double.NEGATIVE_INFINITY);
+  // }
+  // if (mantissa == 0x1FFFFFFFFFFFFEL) {
+  // return ((val.sign > 0) ? Double.MAX_VALUE : -Double.MAX_VALUE);
+  // }
+  // }
+  // // Round the mantissa
+  // if (((mantissa & 1) == 1)
+  // && (((mantissa & 2) == 2) || BitLevel.nonZeroDroppedBits(delta,
+  // val.digits))) {
+  // mantissa += 2;
+  // }
+  // mantissa >>= 1; // drop the rounding bit
+  // long resSign = (val.sign < 0) ? 0x8000000000000000L : 0;
+  // exponent = ((1023 + exponent) << 52) & 0x7FF0000000000000L;
+  // long result = resSign | exponent | mantissa;
+  // return Double.longBitsToDouble(result);
+  // }
+}
diff --git a/user/super/com/google/gwt/emul/java/math/Division.java b/user/super/com/google/gwt/emul/java/math/Division.java
new file mode 100644
index 0000000..4179a82
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/math/Division.java
@@ -0,0 +1,1013 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE.
+ */
+package java.math;
+
+/**
+ * Static library that provides all operations related with division and modular
+ * arithmetic to {@link BigInteger}. Some methods are provided in both mutable
+ * and immutable way. There are several variants provided listed below:
+ * 
+ * <ul type="circle"> <li><b>Division</b> <ul type="circle"> <li>
+ * {@link BigInteger} division and remainder by {@link BigInteger}.</li> <li>
+ * {@link BigInteger} division and remainder by {@code int}.</li> <li><i>gcd</i>
+ * between {@link BigInteger} numbers.</li> </ul> </li> <li><b>Modular
+ * arithmetic </b> <ul type="circle"> <li>Modular exponentiation between
+ * {@link BigInteger} numbers.</li> <li>Modular inverse of a {@link BigInteger}
+ * numbers.</li> </ul> </li> </ul>
+ */
+class Division {
+
+  /**
+   * Divides the array 'a' by the array 'b' and gets the quotient and the
+   * remainder. Implements the Knuth's division algorithm. See D. Knuth, The Art
+   * of Computer Programming, vol. 2. Steps D1-D8 correspond the steps in the
+   * algorithm description.
+   * 
+   * @param quot the quotient
+   * @param quotLength the quotient's length
+   * @param a the dividend
+   * @param aLength the dividend's length
+   * @param b the divisor
+   * @param bLength the divisor's length
+   * @return the remainder
+   */
+  static int[] divide(int quot[], int quotLength, int a[], int aLength,
+      int b[], int bLength) {
+
+    int normA[] = new int[aLength + 1]; // the normalized dividend
+    // an extra byte is needed for correct shift
+    int normB[] = new int[bLength + 1]; // the normalized divisor;
+    int normBLength = bLength;
+    /*
+     * Step D1: normalize a and b and put the results to a1 and b1 the
+     * normalized divisor's first digit must be >= 2^31
+     */
+    int divisorShift = Integer.numberOfLeadingZeros(b[bLength - 1]);
+    if (divisorShift != 0) {
+      BitLevel.shiftLeft(normB, b, 0, divisorShift);
+      BitLevel.shiftLeft(normA, a, 0, divisorShift);
+    } else {
+      System.arraycopy(a, 0, normA, 0, aLength);
+      System.arraycopy(b, 0, normB, 0, bLength);
+    }
+    int firstDivisorDigit = normB[normBLength - 1];
+    // Step D2: set the quotient index
+    int i = quotLength - 1;
+    int j = aLength;
+
+    while (i >= 0) {
+      // Step D3: calculate a guess digit guessDigit
+      int guessDigit = 0;
+      if (normA[j] == firstDivisorDigit) {
+        // set guessDigit to the largest unsigned int value
+        guessDigit = -1;
+      } else {
+        long product = (((normA[j] & 0xffffffffL) << 32) + (normA[j - 1] & 0xffffffffL));
+        long res = Division.divideLongByInt(product, firstDivisorDigit);
+        guessDigit = (int) res; // the quotient of divideLongByInt
+        int rem = (int) (res >> 32); // the remainder of
+        // divideLongByInt
+        // decrease guessDigit by 1 while leftHand > rightHand
+        if (guessDigit != 0) {
+          long leftHand = 0;
+          long rightHand = 0;
+          boolean rOverflowed = false;
+          guessDigit++; // to have the proper value in the loop
+          // below
+          do {
+            guessDigit--;
+            if (rOverflowed) {
+              break;
+            }
+            // leftHand always fits in an unsigned long
+            leftHand = (guessDigit & 0xffffffffL)
+                * (normB[normBLength - 2] & 0xffffffffL);
+            /*
+             * rightHand can overflow; in this case the loop condition will be
+             * true in the next step of the loop
+             */
+            rightHand = ((long) rem << 32) + (normA[j - 2] & 0xffffffffL);
+            long longR = (rem & 0xffffffffL)
+                + (firstDivisorDigit & 0xffffffffL);
+            /*
+             * checks that longR does not fit in an unsigned int; this ensures
+             * that rightHand will overflow unsigned long in the next step
+             */
+            if (Integer.numberOfLeadingZeros((int) (longR >>> 32)) < 32) {
+              rOverflowed = true;
+            } else {
+              rem = (int) longR;
+            }
+          } while (((leftHand ^ 0x8000000000000000L) > (rightHand ^ 0x8000000000000000L)));
+        }
+      }
+      // Step D4: multiply normB by guessDigit and subtract the production
+      // from normA.
+      if (guessDigit != 0) {
+        int borrow = Division.multiplyAndSubtract(normA, j - normBLength,
+            normB, normBLength, guessDigit);
+        // Step D5: check the borrow
+        if (borrow != 0) {
+          // Step D6: compensating addition
+          guessDigit--;
+          long carry = 0;
+          for (int k = 0; k < normBLength; k++) {
+            carry += (normA[j - normBLength + k] & 0xffffffffL)
+                + (normB[k] & 0xffffffffL);
+            normA[j - normBLength + k] = (int) carry;
+            carry >>>= 32;
+          }
+        }
+      }
+      if (quot != null) {
+        quot[i] = guessDigit;
+      }
+      // Step D7
+      j--;
+      i--;
+    }
+    /*
+     * Step D8: we got the remainder in normA. Denormalize it id needed
+     */
+    if (divisorShift != 0) {
+      // reuse normB
+      BitLevel.shiftRight(normB, normBLength, normA, 0, divisorShift);
+      return normB;
+    }
+    System.arraycopy(normA, 0, normB, 0, bLength);
+    return normA;
+  }
+
+  /**
+   * Computes the quotient and the remainder after a division by an {@code int}
+   * number.
+   * 
+   * @return an array of the form {@code [quotient, remainder]}.
+   */
+  static BigInteger[] divideAndRemainderByInteger(BigInteger val, int divisor,
+      int divisorSign) {
+    // res[0] is a quotient and res[1] is a remainder:
+    int[] valDigits = val.digits;
+    int valLen = val.numberLength;
+    int valSign = val.sign;
+    if (valLen == 1) {
+      long a = (valDigits[0] & 0xffffffffL);
+      long b = (divisor & 0xffffffffL);
+      long quo = a / b;
+      long rem = a % b;
+      if (valSign != divisorSign) {
+        quo = -quo;
+      }
+      if (valSign < 0) {
+        rem = -rem;
+      }
+      return new BigInteger[] {BigInteger.valueOf(quo), BigInteger.valueOf(rem)};
+    }
+    int quotientLength = valLen;
+    int quotientSign = ((valSign == divisorSign) ? 1 : -1);
+    int quotientDigits[] = new int[quotientLength];
+    int remainderDigits[];
+    remainderDigits = new int[] {Division.divideArrayByInt(quotientDigits,
+        valDigits, valLen, divisor)};
+    BigInteger result0 = new BigInteger(quotientSign, quotientLength,
+        quotientDigits);
+    BigInteger result1 = new BigInteger(valSign, 1, remainderDigits);
+    result0.cutOffLeadingZeroes();
+    result1.cutOffLeadingZeroes();
+    return new BigInteger[] {result0, result1};
+  }
+
+  /**
+   * Divides an array by an integer value. Implements the Knuth's division
+   * algorithm. See D. Knuth, The Art of Computer Programming, vol. 2.
+   * 
+   * @param dest the quotient
+   * @param src the dividend
+   * @param srcLength the length of the dividend
+   * @param divisor the divisor
+   * @return remainder
+   */
+  static int divideArrayByInt(int dest[], int src[], final int srcLength,
+      final int divisor) {
+
+    long rem = 0;
+    long bLong = divisor & 0xffffffffL;
+
+    for (int i = srcLength - 1; i >= 0; i--) {
+      long temp = (rem << 32) | (src[i] & 0xffffffffL);
+      long quot;
+      if (temp >= 0) {
+        quot = (temp / bLong);
+        rem = (temp % bLong);
+      } else {
+        /*
+         * make the dividend positive shifting it right by 1 bit then get the
+         * quotient an remainder and correct them properly
+         */
+        long aPos = temp >>> 1;
+        long bPos = divisor >>> 1;
+        quot = aPos / bPos;
+        rem = aPos % bPos;
+        // double the remainder and add 1 if a is odd
+        rem = (rem << 1) + (temp & 1);
+        if ((divisor & 1) != 0) {
+          // the divisor is odd
+          if (quot <= rem) {
+            rem -= quot;
+          } else {
+            if (quot - rem <= bLong) {
+              rem += bLong - quot;
+              quot -= 1;
+            } else {
+              rem += (bLong << 1) - quot;
+              quot -= 2;
+            }
+          }
+        }
+      }
+      dest[i] = (int) (quot & 0xffffffffL);
+    }
+    return (int) rem;
+  }
+
+  /**
+   * Divides an unsigned long a by an unsigned int b. It is supposed that the
+   * most significant bit of b is set to 1, i.e. b < 0
+   * 
+   * @param a the dividend
+   * @param b the divisor
+   * @return the long value containing the unsigned integer remainder in the
+   *         left half and the unsigned integer quotient in the right half
+   */
+  static long divideLongByInt(long a, int b) {
+    long quot;
+    long rem;
+    long bLong = b & 0xffffffffL;
+
+    if (a >= 0) {
+      quot = (a / bLong);
+      rem = (a % bLong);
+    } else {
+      /*
+       * Make the dividend positive shifting it right by 1 bit then get the
+       * quotient an remainder and correct them properly
+       */
+      long aPos = a >>> 1;
+      long bPos = b >>> 1;
+      quot = aPos / bPos;
+      rem = aPos % bPos;
+      // double the remainder and add 1 if a is odd
+      rem = (rem << 1) + (a & 1);
+      if ((b & 1) != 0) { // the divisor is odd
+        if (quot <= rem) {
+          rem -= quot;
+        } else {
+          if (quot - rem <= bLong) {
+            rem += bLong - quot;
+            quot -= 1;
+          } else {
+            rem += (bLong << 1) - quot;
+            quot -= 2;
+          }
+        }
+      }
+    }
+    return (rem << 32) | (quot & 0xffffffffL);
+  }
+
+  /**
+   * Performs modular exponentiation using the Montgomery Reduction. It requires
+   * that all parameters be positive and the modulus be even. Based <i>The
+   * square and multiply algorithm and the Montgomery Reduction C. K. Koc -
+   * Montgomery Reduction with Even Modulus</i>. The square and multiply
+   * algorithm and the Montgomery Reduction.
+   * 
+   * @ar.org.fitc.ref "C. K. Koc - Montgomery Reduction with Even Modulus"
+   * @see BigInteger#modPow(BigInteger, BigInteger)
+   */
+  static BigInteger evenModPow(BigInteger base, BigInteger exponent,
+      BigInteger modulus) {
+    // PRE: (base > 0), (exponent > 0), (modulus > 0) and (modulus even)
+    // STEP 1: Obtain the factorization 'modulus'= q * 2^j.
+    int j = modulus.getLowestSetBit();
+    BigInteger q = modulus.shiftRight(j);
+
+    // STEP 2: Compute x1 := base^exponent (mod q).
+    BigInteger x1 = oddModPow(base, exponent, q);
+
+    // STEP 3: Compute x2 := base^exponent (mod 2^j).
+    BigInteger x2 = pow2ModPow(base, exponent, j);
+
+    // STEP 4: Compute q^(-1) (mod 2^j) and y := (x2-x1) * q^(-1) (mod 2^j)
+    BigInteger qInv = modPow2Inverse(q, j);
+    BigInteger y = (x2.subtract(x1)).multiply(qInv);
+    inplaceModPow2(y, j);
+    if (y.sign < 0) {
+      y = y.add(BigInteger.getPowerOfTwo(j));
+    }
+    // STEP 5: Compute and return: x1 + q * y
+    return x1.add(q.multiply(y));
+  }
+
+  /**
+   * Performs the final reduction of the Montgomery algorithm.
+   * 
+   * @see #monPro(BigInteger, BigInteger, BigInteger, long)
+   * @see #monSquare(BigInteger, BigInteger, long)
+   */
+  static BigInteger finalSubtraction(int res[], BigInteger modulus) {
+
+    // skipping leading zeros
+    int modulusLen = modulus.numberLength;
+    boolean doSub = res[modulusLen] != 0;
+    if (!doSub) {
+      int modulusDigits[] = modulus.digits;
+      doSub = true;
+      for (int i = modulusLen - 1; i >= 0; i--) {
+        if (res[i] != modulusDigits[i]) {
+          doSub = (res[i] != 0)
+              && ((res[i] & 0xFFFFFFFFL) > (modulusDigits[i] & 0xFFFFFFFFL));
+          break;
+        }
+      }
+    }
+
+    BigInteger result = new BigInteger(1, modulusLen + 1, res);
+
+    // if (res >= modulusDigits) compute (res - modulusDigits)
+    if (doSub) {
+      Elementary.inplaceSubtract(result, modulus);
+    }
+
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  /**
+   * @param m a positive modulus Return the greatest common divisor of op1 and
+   *          op2,
+   * 
+   * @param op1 must be greater than zero
+   * @param op2 must be greater than zero
+   * @see BigInteger#gcd(BigInteger)
+   * @return {@code GCD(op1, op2)}
+   */
+  static BigInteger gcdBinary(BigInteger op1, BigInteger op2) {
+    // PRE: (op1 > 0) and (op2 > 0)
+
+    /*
+     * Divide both number the maximal possible times by 2 without rounding
+     * gcd(2*a, 2*b) = 2 * gcd(a,b)
+     */
+    int lsb1 = op1.getLowestSetBit();
+    int lsb2 = op2.getLowestSetBit();
+    int pow2Count = Math.min(lsb1, lsb2);
+
+    BitLevel.inplaceShiftRight(op1, lsb1);
+    BitLevel.inplaceShiftRight(op2, lsb2);
+
+    BigInteger swap;
+    // I want op2 > op1
+    if (op1.compareTo(op2) == BigInteger.GREATER) {
+      swap = op1;
+      op1 = op2;
+      op2 = swap;
+    }
+
+    do { // INV: op2 >= op1 && both are odd unless op1 = 0
+
+      // Optimization for small operands
+      // (op2.bitLength() < 64) implies by INV (op1.bitLength() < 64)
+      if ((op2.numberLength == 1)
+          || ((op2.numberLength == 2) && (op2.digits[1] > 0))) {
+        op2 = BigInteger.valueOf(Division.gcdBinary(op1.longValue(),
+            op2.longValue()));
+        break;
+      }
+
+      // Implements one step of the Euclidean algorithm
+      // To reduce one operand if it's much smaller than the other one
+      if (op2.numberLength > op1.numberLength * 1.2) {
+        op2 = op2.remainder(op1);
+        if (op2.signum() != 0) {
+          BitLevel.inplaceShiftRight(op2, op2.getLowestSetBit());
+        }
+      } else {
+
+        // Use Knuth's algorithm of successive subtract and shifting
+        do {
+          Elementary.inplaceSubtract(op2, op1); // both are odd
+          BitLevel.inplaceShiftRight(op2, op2.getLowestSetBit()); // op2 is even
+        } while (op2.compareTo(op1) >= BigInteger.EQUALS);
+      }
+      // now op1 >= op2
+      swap = op2;
+      op2 = op1;
+      op1 = swap;
+    } while (op1.sign != 0);
+    return op2.shiftLeft(pow2Count);
+  }
+
+  /**
+   * Performs the same as {@link #gcdBinary(BigInteger, BigInteger)}, but with
+   * numbers of 63 bits, represented in positives values of {@code long} type.
+   * 
+   * @param op1 a positive number
+   * @param op2 a positive number
+   * @see #gcdBinary(BigInteger, BigInteger)
+   * @return <code>GCD(op1, op2)</code>
+   */
+  static long gcdBinary(long op1, long op2) {
+    // PRE: (op1 > 0) and (op2 > 0)
+    int lsb1 = Long.numberOfTrailingZeros(op1);
+    int lsb2 = Long.numberOfTrailingZeros(op2);
+    int pow2Count = Math.min(lsb1, lsb2);
+
+    if (lsb1 != 0) {
+      op1 >>>= lsb1;
+    }
+    if (lsb2 != 0) {
+      op2 >>>= lsb2;
+    }
+    do {
+      if (op1 >= op2) {
+        op1 -= op2;
+        op1 >>>= Long.numberOfTrailingZeros(op1);
+      } else {
+        op2 -= op1;
+        op2 >>>= Long.numberOfTrailingZeros(op2);
+      }
+    } while (op1 != 0);
+    return (op2 << pow2Count);
+  }
+
+  /**
+   * Performs {@code x = x mod (2<sup>n</sup>)}.
+   * 
+   * @param x a positive number, it will store the result.
+   * @param n a positive exponent of {@code 2}.
+   */
+  static void inplaceModPow2(BigInteger x, int n) {
+    // PRE: (x > 0) and (n >= 0)
+    int fd = n >> 5;
+    int leadingZeros;
+
+    if ((x.numberLength < fd) || (x.bitLength() <= n)) {
+      return;
+    }
+    leadingZeros = 32 - (n & 31);
+    x.numberLength = fd + 1;
+    x.digits[fd] &= (leadingZeros < 32) ? (-1 >>> leadingZeros) : 0;
+    x.cutOffLeadingZeroes();
+  }
+
+  /**
+   * 
+   * Based on "New Algorithm for Classical Modular Inverse" Róbert Lórencz. LNCS
+   * 2523 (2002)
+   * 
+   * @return a^(-1) mod m
+   */
+  static BigInteger modInverseLorencz(BigInteger a, BigInteger modulo) {
+    // PRE: a is coprime with modulo, a < modulo
+
+    int max = Math.max(a.numberLength, modulo.numberLength);
+    int uDigits[] = new int[max + 1]; // enough place to make all the inplace
+                                      // operation
+    int vDigits[] = new int[max + 1];
+    System.arraycopy(modulo.digits, 0, uDigits, 0, modulo.numberLength);
+    System.arraycopy(a.digits, 0, vDigits, 0, a.numberLength);
+    BigInteger u = new BigInteger(modulo.sign, modulo.numberLength, uDigits);
+    BigInteger v = new BigInteger(a.sign, a.numberLength, vDigits);
+
+    BigInteger r = new BigInteger(0, 1, new int[max + 1]); // BigInteger.ZERO;
+    BigInteger s = new BigInteger(1, 1, new int[max + 1]);
+    s.digits[0] = 1;
+    // r == 0 && s == 1, but with enough place
+
+    int coefU = 0, coefV = 0;
+    int n = modulo.bitLength();
+    int k;
+    while (!isPowerOfTwo(u, coefU) && !isPowerOfTwo(v, coefV)) {
+
+      // modification of original algorithm: I calculate how many times the
+      // algorithm will enter in the same branch of if
+      k = howManyIterations(u, n);
+
+      if (k != 0) {
+        BitLevel.inplaceShiftLeft(u, k);
+        if (coefU >= coefV) {
+          BitLevel.inplaceShiftLeft(r, k);
+        } else {
+          BitLevel.inplaceShiftRight(s, Math.min(coefV - coefU, k));
+          if (k - (coefV - coefU) > 0) {
+            BitLevel.inplaceShiftLeft(r, k - coefV + coefU);
+          }
+        }
+        coefU += k;
+      }
+
+      k = howManyIterations(v, n);
+      if (k != 0) {
+        BitLevel.inplaceShiftLeft(v, k);
+        if (coefV >= coefU) {
+          BitLevel.inplaceShiftLeft(s, k);
+        } else {
+          BitLevel.inplaceShiftRight(r, Math.min(coefU - coefV, k));
+          if (k - (coefU - coefV) > 0) {
+            BitLevel.inplaceShiftLeft(s, k - coefU + coefV);
+          }
+        }
+        coefV += k;
+      }
+
+      if (u.signum() == v.signum()) {
+        if (coefU <= coefV) {
+          Elementary.completeInPlaceSubtract(u, v);
+          Elementary.completeInPlaceSubtract(r, s);
+        } else {
+          Elementary.completeInPlaceSubtract(v, u);
+          Elementary.completeInPlaceSubtract(s, r);
+        }
+      } else {
+        if (coefU <= coefV) {
+          Elementary.completeInPlaceAdd(u, v);
+          Elementary.completeInPlaceAdd(r, s);
+        } else {
+          Elementary.completeInPlaceAdd(v, u);
+          Elementary.completeInPlaceAdd(s, r);
+        }
+      }
+      if (v.signum() == 0 || u.signum() == 0) {
+        // math.19: BigInteger not invertible
+        throw new ArithmeticException("BigInteger not invertible.");
+      }
+    }
+
+    if (isPowerOfTwo(v, coefV)) {
+      r = s;
+      if (v.signum() != u.signum()) {
+        u = u.negate();
+      }
+    }
+    if (u.testBit(n)) {
+      if (r.signum() < 0) {
+        r = r.negate();
+      } else {
+        r = modulo.subtract(r);
+      }
+    }
+    if (r.signum() < 0) {
+      r = r.add(modulo);
+    }
+
+    return r;
+  }
+
+  /**
+   * Calculates a.modInverse(p) Based on: Savas, E; Koc, C "The Montgomery
+   * Modular Inverse - Revised".
+   */
+  static BigInteger modInverseMontgomery(BigInteger a, BigInteger p) {
+    if (a.sign == 0) {
+      // ZERO hasn't inverse
+      // math.19: BigInteger not invertible
+      throw new ArithmeticException("BigInteger not invertible.");
+    }
+
+    if (!p.testBit(0)) {
+      // montgomery inverse require even modulo
+      return modInverseLorencz(a, p);
+    }
+
+    int m = p.numberLength * 32;
+    // PRE: a \in [1, p - 1]
+    BigInteger u, v, r, s;
+    u = p.copy(); // make copy to use inplace method
+    v = a.copy();
+    int max = Math.max(v.numberLength, u.numberLength);
+    r = new BigInteger(1, 1, new int[max + 1]);
+    s = new BigInteger(1, 1, new int[max + 1]);
+    s.digits[0] = 1;
+    // s == 1 && v == 0
+
+    int k = 0;
+
+    int lsbu = u.getLowestSetBit();
+    int lsbv = v.getLowestSetBit();
+    int toShift;
+
+    if (lsbu > lsbv) {
+      BitLevel.inplaceShiftRight(u, lsbu);
+      BitLevel.inplaceShiftRight(v, lsbv);
+      BitLevel.inplaceShiftLeft(r, lsbv);
+      k += lsbu - lsbv;
+    } else {
+      BitLevel.inplaceShiftRight(u, lsbu);
+      BitLevel.inplaceShiftRight(v, lsbv);
+      BitLevel.inplaceShiftLeft(s, lsbu);
+      k += lsbv - lsbu;
+    }
+
+    r.sign = 1;
+    while (v.signum() > 0) {
+      // INV v >= 0, u >= 0, v odd, u odd (except last iteration when v is even
+      // (0))
+
+      while (u.compareTo(v) > BigInteger.EQUALS) {
+        Elementary.inplaceSubtract(u, v);
+        toShift = u.getLowestSetBit();
+        BitLevel.inplaceShiftRight(u, toShift);
+        Elementary.inplaceAdd(r, s);
+        BitLevel.inplaceShiftLeft(s, toShift);
+        k += toShift;
+      }
+
+      while (u.compareTo(v) <= BigInteger.EQUALS) {
+        Elementary.inplaceSubtract(v, u);
+        if (v.signum() == 0) {
+          break;
+        }
+        toShift = v.getLowestSetBit();
+        BitLevel.inplaceShiftRight(v, toShift);
+        Elementary.inplaceAdd(s, r);
+        BitLevel.inplaceShiftLeft(r, toShift);
+        k += toShift;
+      }
+    }
+    if (!u.isOne()) {
+      // in u is stored the gcd
+      // math.19: BigInteger not invertible.
+      throw new ArithmeticException("BigInteger not invertible.");
+    }
+    if (r.compareTo(p) >= BigInteger.EQUALS) {
+      Elementary.inplaceSubtract(r, p);
+    }
+
+    r = p.subtract(r);
+
+    // Have pair: ((BigInteger)r, (Integer)k) where r == a^(-1) * 2^k mod
+    // (module)
+    int n1 = calcN(p);
+    if (k > m) {
+      r = monPro(r, BigInteger.ONE, p, n1);
+      k = k - m;
+    }
+
+    r = monPro(r, BigInteger.getPowerOfTwo(m - k), p, n1);
+    return r;
+  }
+
+  /**
+   * @param x an odd positive number.
+   * @param n the exponent by which 2 is raised.
+   * @return {@code x<sup>-1</sup> (mod 2<sup>n</sup>)}.
+   */
+  static BigInteger modPow2Inverse(BigInteger x, int n) {
+    // PRE: (x > 0), (x is odd), and (n > 0)
+    BigInteger y = new BigInteger(1, new int[1 << n]);
+    y.numberLength = 1;
+    y.digits[0] = 1;
+    y.sign = 1;
+
+    for (int i = 1; i < n; i++) {
+      if (BitLevel.testBit(x.multiply(y), i)) {
+        // Adding 2^i to y (setting the i-th bit)
+        y.digits[i >> 5] |= (1 << (i & 31));
+      }
+    }
+    return y;
+  }
+
+  /**
+   * Implements the Montgomery Product of two integers represented by {@code
+   * int} arrays. The arrays are supposed in <i>little endian</i> notation.
+   * 
+   * @param a The first factor of the product.
+   * @param b The second factor of the product.
+   * @param modulus The modulus of the operations. Z<sub>modulus</sub>.
+   * @param n2 The digit modulus'[0].
+   * @ar.org.fitc.ref "C. K. Koc - Analyzing and Comparing Montgomery
+   *                  Multiplication Algorithms"
+   * @see #modPowOdd(BigInteger, BigInteger, BigInteger)
+   */
+  static BigInteger monPro(BigInteger a, BigInteger b, BigInteger modulus,
+      int n2) {
+    int modulusLen = modulus.numberLength;
+    int res[] = new int[(modulusLen << 1) + 1];
+    Multiplication.multArraysPAP(a.digits,
+        Math.min(modulusLen, a.numberLength), b.digits, Math.min(modulusLen,
+            b.numberLength), res);
+    monReduction(res, modulus, n2);
+    return finalSubtraction(res, modulus);
+  }
+
+  /**
+   * Multiplies an array by int and subtracts it from a subarray of another
+   * array.
+   * 
+   * @param a the array to subtract from
+   * @param start the start element of the subarray of a
+   * @param b the array to be multiplied and subtracted
+   * @param bLen the length of b
+   * @param c the multiplier of b
+   * @return the carry element of subtraction
+   */
+  static int multiplyAndSubtract(int a[], int start, int b[], int bLen, int c) {
+    long carry0 = 0;
+    long carry1 = 0;
+
+    for (int i = 0; i < bLen; i++) {
+      carry0 = Multiplication.unsignedMultAddAdd(b[i], c, (int) carry0, 0);
+      carry1 = (a[start + i] & 0xffffffffL) - (carry0 & 0xffffffffL) + carry1;
+      a[start + i] = (int) carry1;
+      carry1 >>= 32; // -1 or 0
+      carry0 >>>= 32;
+    }
+
+    carry1 = (a[start + bLen] & 0xffffffffL) - carry0 + carry1;
+    a[start + bLen] = (int) carry1;
+    return (int) (carry1 >> 32); // -1 or 0
+  }
+
+  /**
+   * Performs modular exponentiation using the Montgomery Reduction. It requires
+   * that all parameters be positive and the modulus be odd. >
+   * 
+   * @see BigInteger#modPow(BigInteger, BigInteger)
+   * @see #monPro(BigInteger, BigInteger, BigInteger, int)
+   * @see #slidingWindow(BigInteger, BigInteger, BigInteger, BigInteger, int)
+   * @see #squareAndMultiply(BigInteger, BigInteger, BigInteger, BigInteger,
+   *      int)
+   */
+  static BigInteger oddModPow(BigInteger base, BigInteger exponent,
+      BigInteger modulus) {
+    // PRE: (base > 0), (exponent > 0), (modulus > 0) and (odd modulus)
+    int k = (modulus.numberLength << 5); // r = 2^k
+    // n-residue of base [base * r (mod modulus)]
+    BigInteger a2 = base.shiftLeft(k).mod(modulus);
+    // n-residue of base [1 * r (mod modulus)]
+    BigInteger x2 = BigInteger.getPowerOfTwo(k).mod(modulus);
+    BigInteger res;
+    // Compute (modulus[0]^(-1)) (mod 2^32) for odd modulus
+
+    int n2 = calcN(modulus);
+    if (modulus.numberLength == 1) {
+      res = squareAndMultiply(x2, a2, exponent, modulus, n2);
+    } else {
+      res = slidingWindow(x2, a2, exponent, modulus, n2);
+    }
+
+    return monPro(res, BigInteger.ONE, modulus, n2);
+  }
+
+  /**
+   * It requires that all parameters be positive.
+   * 
+   * @return {@code base<sup>exponent</sup> mod (2<sup>j</sup>)}.
+   * @see BigInteger#modPow(BigInteger, BigInteger)
+   */
+  static BigInteger pow2ModPow(BigInteger base, BigInteger exponent, int j) {
+    // PRE: (base > 0), (exponent > 0) and (j > 0)
+    BigInteger res = BigInteger.ONE;
+    BigInteger e = exponent.copy();
+    BigInteger baseMod2toN = base.copy();
+    BigInteger res2;
+    /*
+     * If 'base' is odd then it's coprime with 2^j and phi(2^j) = 2^(j-1); so we
+     * can reduce reduce the exponent (mod 2^(j-1)).
+     */
+    if (base.testBit(0)) {
+      inplaceModPow2(e, j - 1);
+    }
+    inplaceModPow2(baseMod2toN, j);
+
+    for (int i = e.bitLength() - 1; i >= 0; i--) {
+      res2 = res.copy();
+      inplaceModPow2(res2, j);
+      res = res.multiply(res2);
+      if (BitLevel.testBit(e, i)) {
+        res = res.multiply(baseMod2toN);
+        inplaceModPow2(res, j);
+      }
+    }
+    inplaceModPow2(res, j);
+    return res;
+  }
+
+  /**
+   * Divides a <code>BigInteger</code> by a signed <code>int</code> and returns
+   * the remainder.
+   * 
+   * @param dividend the BigInteger to be divided. Must be non-negative.
+   * @param divisor a signed int
+   * @return divide % divisor
+   */
+  static int remainder(BigInteger dividend, int divisor) {
+    return remainderArrayByInt(dividend.digits, dividend.numberLength, divisor);
+  }
+
+  /**
+   * Divides an array by an integer value. Implements the Knuth's division
+   * algorithm. See D. Knuth, The Art of Computer Programming, vol. 2.
+   * 
+   * @param src the dividend
+   * @param srcLength the length of the dividend
+   * @param divisor the divisor
+   * @return remainder
+   */
+  static int remainderArrayByInt(int src[], final int srcLength,
+      final int divisor) {
+
+    long result = 0;
+
+    for (int i = srcLength - 1; i >= 0; i--) {
+      long temp = (result << 32) + (src[i] & 0xffffffffL);
+      long res = divideLongByInt(temp, divisor);
+      result = (int) (res >> 32);
+    }
+    return (int) result;
+  }
+
+  /*
+   * Implements the Montgomery modular exponentiation based in <i>The sliding
+   * windows algorithm and the MongomeryReduction</i>.
+   * 
+   * @ar.org.fitc.ref
+   * "A. Menezes,P. van Oorschot, S. Vanstone - Handbook of Applied Cryptography"
+   * ;
+   * 
+   * @see #oddModPow(BigInteger, BigInteger, BigInteger)
+   */
+  static BigInteger slidingWindow(BigInteger x2, BigInteger a2,
+      BigInteger exponent, BigInteger modulus, int n2) {
+    // fill odd low pows of a2
+    BigInteger pows[] = new BigInteger[8];
+    BigInteger res = x2;
+    int lowexp;
+    BigInteger x3;
+    int acc3;
+    pows[0] = a2;
+
+    x3 = monPro(a2, a2, modulus, n2);
+    for (int i = 1; i <= 7; i++) {
+      pows[i] = monPro(pows[i - 1], x3, modulus, n2);
+    }
+
+    for (int i = exponent.bitLength() - 1; i >= 0; i--) {
+      if (BitLevel.testBit(exponent, i)) {
+        lowexp = 1;
+        acc3 = i;
+
+        for (int j = Math.max(i - 3, 0); j <= i - 1; j++) {
+          if (BitLevel.testBit(exponent, j)) {
+            if (j < acc3) {
+              acc3 = j;
+              lowexp = (lowexp << (i - j)) ^ 1;
+            } else {
+              lowexp = lowexp ^ (1 << (j - acc3));
+            }
+          }
+        }
+
+        for (int j = acc3; j <= i; j++) {
+          res = monPro(res, res, modulus, n2);
+        }
+        res = monPro(pows[(lowexp - 1) >> 1], res, modulus, n2);
+        i = acc3;
+      } else {
+        res = monPro(res, res, modulus, n2);
+      }
+    }
+    return res;
+  }
+
+  static BigInteger squareAndMultiply(BigInteger x2, BigInteger a2,
+      BigInteger exponent, BigInteger modulus, int n2) {
+    BigInteger res = x2;
+    for (int i = exponent.bitLength() - 1; i >= 0; i--) {
+      res = monPro(res, res, modulus, n2);
+      if (BitLevel.testBit(exponent, i)) {
+        res = monPro(res, a2, modulus, n2);
+      }
+    }
+    return res;
+  }
+
+  /**
+   * Calculate the first digit of the inverse.
+   */
+  private static int calcN(BigInteger a) {
+    long m0 = a.digits[0] & 0xFFFFFFFFL;
+    long n2 = 1L; // this is a'[0]
+    long powerOfTwo = 2L;
+    do {
+      if (((m0 * n2) & powerOfTwo) != 0) {
+        n2 |= powerOfTwo;
+      }
+      powerOfTwo <<= 1;
+    } while (powerOfTwo < 0x100000000L);
+    n2 = -n2;
+    return (int) (n2 & 0xFFFFFFFFL);
+  }
+
+  /**
+   * Calculate how many iteration of Lorencz's algorithm would perform the same
+   * operation.
+   * 
+   * @param bi
+   * @param n
+   * @return
+   */
+  private static int howManyIterations(BigInteger bi, int n) {
+    int i = n - 1;
+    if (bi.sign > 0) {
+      while (!bi.testBit(i)) {
+        i--;
+      }
+      return n - 1 - i;
+    } else {
+      while (bi.testBit(i)) {
+        i--;
+      }
+      return n - 1 - Math.max(i, bi.getLowestSetBit());
+    }
+  }
+
+  /**
+   * @return bi == abs(2^exp)
+   */
+  private static boolean isPowerOfTwo(BigInteger bi, int exp) {
+    boolean result = false;
+    result = (exp >> 5 == bi.numberLength - 1)
+        && (bi.digits[bi.numberLength - 1] == 1 << (exp & 31));
+    if (result) {
+      for (int i = 0; result && i < bi.numberLength - 1; i++) {
+        result = bi.digits[i] == 0;
+      }
+    }
+    return result;
+  }
+
+  private static void monReduction(int[] res, BigInteger modulus, int n2) {
+
+    /* res + m*modulus_digits */
+    int[] modulusDigits = modulus.digits;
+    int modulusLen = modulus.numberLength;
+    long outerCarry = 0;
+
+    for (int i = 0; i < modulusLen; i++) {
+      long innnerCarry = 0;
+      int m = (int) Multiplication.unsignedMultAddAdd(res[i], n2, 0, 0);
+      for (int j = 0; j < modulusLen; j++) {
+        innnerCarry = Multiplication.unsignedMultAddAdd(m, modulusDigits[j],
+            res[i + j], (int) innnerCarry);
+        res[i + j] = (int) innnerCarry;
+        innnerCarry >>>= 32;
+      }
+
+      outerCarry += (res[i + modulusLen] & 0xFFFFFFFFL) + innnerCarry;
+      res[i + modulusLen] = (int) outerCarry;
+      outerCarry >>>= 32;
+    }
+
+    res[modulusLen << 1] = (int) outerCarry;
+
+    /* res / r */
+    for (int j = 0; j < modulusLen + 1; j++) {
+      res[j] = res[j + modulusLen];
+    }
+  }
+}
diff --git a/user/super/com/google/gwt/emul/java/math/Elementary.java b/user/super/com/google/gwt/emul/java/math/Elementary.java
new file mode 100644
index 0000000..58bec5b
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/math/Elementary.java
@@ -0,0 +1,457 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE.
+ */
+package java.math;
+
+/**
+ * Static library that provides the basic arithmetic mutable operations for
+ * {@link BigInteger}. The operations provided are listed below. <ul
+ * type="circle"> <li>Addition.</li> <li>Subtraction.</li> <li>Comparison.</li>
+ * </ul> In addition to this, some <i><b>Inplace</b></i> (mutable) methods are
+ * provided.
+ */
+class Elementary {
+
+  /**
+   * @see BigInteger#add(BigInteger) .
+   * @param op1
+   * @param op2
+   * @return
+   */
+  static BigInteger add(BigInteger op1, BigInteger op2) {
+    int resDigits[];
+    int resSign;
+    int op1Sign = op1.sign;
+    int op2Sign = op2.sign;
+
+    if (op1Sign == 0) {
+      return op2;
+    }
+    if (op2Sign == 0) {
+      return op1;
+    }
+    int op1Len = op1.numberLength;
+    int op2Len = op2.numberLength;
+
+    if (op1Len + op2Len == 2) {
+      long a = (op1.digits[0] & 0xFFFFFFFFL);
+      long b = (op2.digits[0] & 0xFFFFFFFFL);
+      long res;
+      int valueLo;
+      int valueHi;
+
+      if (op1Sign == op2Sign) {
+        res = a + b;
+        valueLo = (int) res;
+        valueHi = (int) (res >>> 32);
+        return ((valueHi == 0) ? new BigInteger(op1Sign, valueLo)
+            : new BigInteger(op1Sign, 2, new int[] {valueLo, valueHi}));
+      }
+      return BigInteger.valueOf((op1Sign < 0) ? (b - a) : (a - b));
+    } else if (op1Sign == op2Sign) {
+      resSign = op1Sign;
+      // an augend should not be shorter than addend
+      resDigits = (op1Len >= op2Len) ? add(op1.digits, op1Len, op2.digits,
+          op2Len) : add(op2.digits, op2Len, op1.digits, op1Len);
+    } else { // signs are different
+      int cmp = ((op1Len != op2Len) ? ((op1Len > op2Len) ? 1 : -1)
+          : compareArrays(op1.digits, op2.digits, op1Len));
+
+      if (cmp == BigInteger.EQUALS) {
+        return BigInteger.ZERO;
+      }
+      // a minuend should not be shorter than subtrahend
+      if (cmp == BigInteger.GREATER) {
+        resSign = op1Sign;
+        resDigits = subtract(op1.digits, op1Len, op2.digits, op2Len);
+      } else {
+        resSign = op2Sign;
+        resDigits = subtract(op2.digits, op2Len, op1.digits, op1Len);
+      }
+    }
+    BigInteger res = new BigInteger(resSign, resDigits.length, resDigits);
+    res.cutOffLeadingZeroes();
+    return res;
+  }
+
+  /**
+   * Compares two arrays. All elements are treated as unsigned integers. The
+   * magnitude is the bit chain of elements in big-endian order.
+   * 
+   * @param a the first array
+   * @param b the second array
+   * @param size the size of arrays
+   * @return 1 if a > b, -1 if a < b, 0 if a == b
+   */
+  static int compareArrays(final int[] a, final int[] b, final int size) {
+    int i;
+    for (i = size - 1; (i >= 0) && (a[i] == b[i]); i--) {
+      // empty
+    }
+    return ((i < 0) ? BigInteger.EQUALS
+        : (a[i] & 0xFFFFFFFFL) < (b[i] & 0xFFFFFFFFL) ? BigInteger.LESS
+            : BigInteger.GREATER);
+  }
+
+  /**
+   * Same as @link #inplaceAdd(BigInteger, BigInteger), but without the
+   * restriction of non-positive values.
+   * 
+   * @param op1 any number
+   * @param op2 any number
+   */
+  static void completeInPlaceAdd(BigInteger op1, BigInteger op2) {
+    if (op1.sign == 0) {
+      System.arraycopy(op2.digits, 0, op1.digits, 0, op2.numberLength);
+    } else if (op2.sign == 0) {
+      return;
+    } else if (op1.sign == op2.sign) {
+      add(op1.digits, op1.digits, op1.numberLength, op2.digits,
+          op2.numberLength);
+    } else {
+      int sign = unsignedArraysCompare(op1.digits, op2.digits,
+          op1.numberLength, op2.numberLength);
+      if (sign > 0) {
+        subtract(op1.digits, op1.digits, op1.numberLength, op2.digits,
+            op2.numberLength);
+      } else {
+        inverseSubtract(op1.digits, op1.digits, op1.numberLength, op2.digits,
+            op2.numberLength);
+        op1.sign = -op1.sign;
+      }
+    }
+    op1.numberLength = Math.max(op1.numberLength, op2.numberLength) + 1;
+    op1.cutOffLeadingZeroes();
+    op1.unCache();
+  }
+
+  /**
+   * Same as @link #inplaceSubtract(BigInteger, BigInteger), but without the
+   * restriction of non-positive values.
+   * 
+   * @param op1 should have enough space to save the result
+   * @param op2
+   */
+  static void completeInPlaceSubtract(BigInteger op1, BigInteger op2) {
+    int resultSign = op1.compareTo(op2);
+    if (op1.sign == 0) {
+      System.arraycopy(op2.digits, 0, op1.digits, 0, op2.numberLength);
+      op1.sign = -op2.sign;
+    } else if (op1.sign != op2.sign) {
+      add(op1.digits, op1.digits, op1.numberLength, op2.digits,
+          op2.numberLength);
+      op1.sign = resultSign;
+    } else {
+      int sign = unsignedArraysCompare(op1.digits, op2.digits,
+          op1.numberLength, op2.numberLength);
+      if (sign > 0) {
+        subtract(op1.digits, op1.digits, op1.numberLength, op2.digits,
+            op2.numberLength); // op1 = op1 - op2
+        // op1.sign remains equal
+      } else {
+        inverseSubtract(op1.digits, op1.digits, op1.numberLength, op2.digits,
+            op2.numberLength); // op1 = op2 - op1
+        op1.sign = -op1.sign;
+      }
+    }
+    op1.numberLength = Math.max(op1.numberLength, op2.numberLength) + 1;
+    op1.cutOffLeadingZeroes();
+    op1.unCache();
+  }
+
+  /**
+   * Performs {@code op1 += op2}. {@code op1} must have enough place to store
+   * the result (i.e. {@code op1.bitLength() >= op2.bitLength()}). Both should
+   * be positive (i.e. {@code op1 >= op2}).
+   * 
+   * @param op1 the input minuend, and the output result.
+   * @param op2 the addend
+   */
+  static void inplaceAdd(BigInteger op1, BigInteger op2) {
+    // PRE: op1 >= op2 > 0
+    add(op1.digits, op1.digits, op1.numberLength, op2.digits, op2.numberLength);
+    op1.numberLength = Math.min(
+        Math.max(op1.numberLength, op2.numberLength) + 1, op1.digits.length);
+    op1.cutOffLeadingZeroes();
+    op1.unCache();
+  }
+
+  /**
+   * Performs: {@code op1 += addend}. The number must to have place to hold a
+   * possible carry.
+   */
+  static void inplaceAdd(BigInteger op1, final int addend) {
+    int carry = inplaceAdd(op1.digits, op1.numberLength, addend);
+    if (carry == 1) {
+      op1.digits[op1.numberLength] = 1;
+      op1.numberLength++;
+    }
+    op1.unCache();
+  }
+
+  /**
+   * Adds an integer value to the array of integers remembering carry.
+   * 
+   * @return a possible generated carry (0 or 1)
+   */
+  static int inplaceAdd(int a[], final int aSize, final int addend) {
+    long carry = addend & 0xFFFFFFFFL;
+
+    for (int i = 0; (carry != 0) && (i < aSize); i++) {
+      carry += a[i] & 0xFFFFFFFFL;
+      a[i] = (int) carry;
+      carry >>= 32;
+    }
+    return (int) carry;
+  }
+
+  /**
+   * Performs {@code op1 -= op2}. {@code op1} must have enough place to store
+   * the result (i.e. {@code op1.bitLength() >= op2.bitLength()}). Both should
+   * be positive (what implies that {@code op1 >= op2}).
+   * 
+   * @param op1 the input minuend, and the output result.
+   * @param op2 the subtrahend
+   */
+  static void inplaceSubtract(BigInteger op1, BigInteger op2) {
+    // PRE: op1 >= op2 > 0
+    subtract(op1.digits, op1.digits, op1.numberLength, op2.digits,
+        op2.numberLength);
+    op1.cutOffLeadingZeroes();
+    op1.unCache();
+  }
+
+  /**
+   * @see BigInteger#subtract(BigInteger) .
+   * @param op1
+   * @param op2
+   * @return
+   */
+  static BigInteger subtract(BigInteger op1, BigInteger op2) {
+    int resSign;
+    int resDigits[];
+    int op1Sign = op1.sign;
+    int op2Sign = op2.sign;
+
+    if (op2Sign == 0) {
+      return op1;
+    }
+    if (op1Sign == 0) {
+      return op2.negate();
+    }
+    int op1Len = op1.numberLength;
+    int op2Len = op2.numberLength;
+    if (op1Len + op2Len == 2) {
+      long a = (op1.digits[0] & 0xFFFFFFFFL);
+      long b = (op2.digits[0] & 0xFFFFFFFFL);
+      if (op1Sign < 0) {
+        a = -a;
+      }
+      if (op2Sign < 0) {
+        b = -b;
+      }
+      return BigInteger.valueOf(a - b);
+    }
+    int cmp = ((op1Len != op2Len) ? ((op1Len > op2Len) ? 1 : -1)
+        : Elementary.compareArrays(op1.digits, op2.digits, op1Len));
+
+    if (cmp == BigInteger.LESS) {
+      resSign = -op2Sign;
+      resDigits = (op1Sign == op2Sign) ? subtract(op2.digits, op2Len,
+          op1.digits, op1Len) : add(op2.digits, op2Len, op1.digits, op1Len);
+    } else {
+      resSign = op1Sign;
+      if (op1Sign == op2Sign) {
+        if (cmp == BigInteger.EQUALS) {
+          return BigInteger.ZERO;
+        }
+        resDigits = subtract(op1.digits, op1Len, op2.digits, op2Len);
+      } else {
+        resDigits = add(op1.digits, op1Len, op2.digits, op2Len);
+      }
+    }
+    BigInteger res = new BigInteger(resSign, resDigits.length, resDigits);
+    res.cutOffLeadingZeroes();
+    return res;
+  }
+
+  /**
+   * Addss the value represented by {@code b} to the value represented by
+   * {@code a}. It is assumed the magnitude of a is not less than the magnitude
+   * of b.
+   * 
+   * @return {@code a + b}
+   */
+  private static int[] add(int a[], int aSize, int b[], int bSize) {
+    // PRE: a[] >= b[]
+    int res[] = new int[aSize + 1];
+    add(res, a, aSize, b, bSize);
+    return res;
+  }
+
+  /**
+   * Performs {@code res = a + b}.
+   */
+  private static void add(int res[], int a[], int aSize, int b[], int bSize) {
+    // PRE: a.length < max(aSize, bSize)
+
+    int i;
+    long carry = (a[0] & 0xFFFFFFFFL) + (b[0] & 0xFFFFFFFFL);
+
+    res[0] = (int) carry;
+    carry >>= 32;
+
+    if (aSize >= bSize) {
+      for (i = 1; i < bSize; i++) {
+        carry += (a[i] & 0xFFFFFFFFL) + (b[i] & 0xFFFFFFFFL);
+        res[i] = (int) carry;
+        carry >>= 32;
+      }
+      for (; i < aSize; i++) {
+        carry += a[i] & 0xFFFFFFFFL;
+        res[i] = (int) carry;
+        carry >>= 32;
+      }
+    } else {
+      for (i = 1; i < aSize; i++) {
+        carry += (a[i] & 0xFFFFFFFFL) + (b[i] & 0xFFFFFFFFL);
+        res[i] = (int) carry;
+        carry >>= 32;
+      }
+      for (; i < bSize; i++) {
+        carry += b[i] & 0xFFFFFFFFL;
+        res[i] = (int) carry;
+        carry >>= 32;
+      }
+    }
+    if (carry != 0) {
+      res[i] = (int) carry;
+    }
+  }
+
+  /**
+   * Performs {@code res = b - a}.
+   */
+  private static void inverseSubtract(int res[], int a[], int aSize, int b[],
+      int bSize) {
+    int i;
+    long borrow = 0;
+    if (aSize < bSize) {
+      for (i = 0; i < aSize; i++) {
+        borrow += (b[i] & 0xFFFFFFFFL) - (a[i] & 0xFFFFFFFFL);
+        res[i] = (int) borrow;
+        borrow >>= 32; // -1 or 0
+      }
+      for (; i < bSize; i++) {
+        borrow += b[i] & 0xFFFFFFFFL;
+        res[i] = (int) borrow;
+        borrow >>= 32; // -1 or 0
+      }
+    } else {
+      for (i = 0; i < bSize; i++) {
+        borrow += (b[i] & 0xFFFFFFFFL) - (a[i] & 0xFFFFFFFFL);
+        res[i] = (int) borrow;
+        borrow >>= 32; // -1 or 0
+      }
+      for (; i < aSize; i++) {
+        borrow -= a[i] & 0xFFFFFFFFL;
+        res[i] = (int) borrow;
+        borrow >>= 32; // -1 or 0
+      }
+    }
+  }
+
+  /**
+   * Subtracts the value represented by {@code b} from the value represented by
+   * {@code a}. It is assumed the magnitude of a is not less than the magnitude
+   * of b.
+   * 
+   * @return {@code a - b}
+   */
+  private static int[] subtract(int a[], int aSize, int b[], int bSize) {
+    // PRE: a[] >= b[]
+    int res[] = new int[aSize];
+    subtract(res, a, aSize, b, bSize);
+    return res;
+  }
+
+  /**
+   * Performs {@code res = a - b}. It is assumed the magnitude of a is not less
+   * than the magnitude of b.
+   */
+  private static void subtract(int res[], int a[], int aSize, int b[], int bSize) {
+    // PRE: a[] >= b[]
+    int i;
+    long borrow = 0;
+
+    for (i = 0; i < bSize; i++) {
+      borrow += (a[i] & 0xFFFFFFFFL) - (b[i] & 0xFFFFFFFFL);
+      res[i] = (int) borrow;
+      borrow >>= 32; // -1 or 0
+    }
+    for (; i < aSize; i++) {
+      borrow += a[i] & 0xFFFFFFFFL;
+      res[i] = (int) borrow;
+      borrow >>= 32; // -1 or 0
+    }
+  }
+
+  /**
+   * Compares two arrays, representing unsigned integer in little-endian order.
+   * Returns +1,0,-1 if a is - respective - greater, equal or lesser then b
+   */
+  private static int unsignedArraysCompare(int[] a, int[] b, int aSize,
+      int bSize) {
+    if (aSize > bSize) {
+      return 1;
+    } else if (aSize < bSize) {
+      return -1;
+    } else {
+      int i;
+      for (i = aSize - 1; i >= 0 && a[i] == b[i]; i--) {
+        // empty
+      }
+      return i < 0 ? BigInteger.EQUALS
+          : ((a[i] & 0xFFFFFFFFL) < (b[i] & 0xFFFFFFFFL) ? BigInteger.LESS
+              : BigInteger.GREATER);
+    }
+  }
+
+  /**
+   * Just to denote that this class can't be instantiated.
+   */
+  private Elementary() {
+  }
+
+}
diff --git a/user/super/com/google/gwt/emul/java/math/Logical.java b/user/super/com/google/gwt/emul/java/math/Logical.java
new file mode 100644
index 0000000..d3ab03e
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/math/Logical.java
@@ -0,0 +1,926 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE.
+ */
+package java.math;
+
+/**
+ * The library implements some logical operations over {@code BigInteger}. The
+ * operations provided are listed below. <ul type="circle"> <li>not</li> <li>and
+ * </li> <li>andNot</li> <li>or</li> <li>xor</li> </ul>
+ */
+class Logical {
+
+  /**
+   * @see BigInteger#and(BigInteger)
+   * @param val
+   * @param that
+   * @return
+   */
+  static BigInteger and(BigInteger val, BigInteger that) {
+    if (that.sign == 0 || val.sign == 0) {
+      return BigInteger.ZERO;
+    }
+    if (that.equals(BigInteger.MINUS_ONE)) {
+      return val;
+    }
+    if (val.equals(BigInteger.MINUS_ONE)) {
+      return that;
+    }
+
+    if (val.sign > 0) {
+      if (that.sign > 0) {
+        return andPositive(val, that);
+      } else {
+        return andDiffSigns(val, that);
+      }
+    } else {
+      if (that.sign > 0) {
+        return andDiffSigns(that, val);
+      } else if (val.numberLength > that.numberLength) {
+        return andNegative(val, that);
+      } else {
+        return andNegative(that, val);
+      }
+    }
+  }
+
+  /**
+   * Return sign = positive.magnitude & magnitude = -negative.magnitude.
+   * @param positive
+   * @param negative
+   * @return
+   */
+  static BigInteger andDiffSigns(BigInteger positive, BigInteger negative) {
+    // PRE: positive is positive and negative is negative
+    int iPos = positive.getFirstNonzeroDigit();
+    int iNeg = negative.getFirstNonzeroDigit();
+
+    // Look if the trailing zeros of the negative will "blank" all
+    // the positive digits
+    if (iNeg >= positive.numberLength) {
+      return BigInteger.ZERO;
+    }
+    int resLength = positive.numberLength;
+    int resDigits[] = new int[resLength];
+
+    // Must start from max(iPos, iNeg)
+    int i = Math.max(iPos, iNeg);
+    if (i == iNeg) {
+      resDigits[i] = -negative.digits[i] & positive.digits[i];
+      i++;
+    }
+    int limit = Math.min(negative.numberLength, positive.numberLength);
+    for (; i < limit; i++) {
+      resDigits[i] = ~negative.digits[i] & positive.digits[i];
+    }
+    // if the negative was shorter must copy the remaining digits
+    // from positive
+    if (i >= negative.numberLength) {
+      for (; i < positive.numberLength; i++) {
+        resDigits[i] = positive.digits[i];
+      }
+    } // else positive ended and must "copy" virtual 0's, do nothing then
+
+    BigInteger result = new BigInteger(1, resLength, resDigits);
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  /**
+   * Return sign = -1, magnitude = -(-longer.magnitude & -shorter.magnitude).
+   * @param longer
+   * @param shorter
+   * @return
+   */
+  static BigInteger andNegative(BigInteger longer, BigInteger shorter) {
+    // PRE: longer and shorter are negative
+    // PRE: longer has at least as many digits as shorter
+    int iLonger = longer.getFirstNonzeroDigit();
+    int iShorter = shorter.getFirstNonzeroDigit();
+
+    // Does shorter matter?
+    if (iLonger >= shorter.numberLength) {
+      return longer;
+    }
+
+    int resLength;
+    int resDigits[];
+    int i = Math.max(iShorter, iLonger);
+    int digit;
+    if (iShorter > iLonger) {
+      digit = -shorter.digits[i] & ~longer.digits[i];
+    } else if (iShorter < iLonger) {
+      digit = ~shorter.digits[i] & -longer.digits[i];
+    } else {
+      digit = -shorter.digits[i] & -longer.digits[i];
+    }
+    if (digit == 0) {
+      for (i++; i < shorter.numberLength
+          && (digit = ~(longer.digits[i] | shorter.digits[i])) == 0; i++) {
+        // digit
+      }
+      // = ~longer.digits[i] & ~shorter.digits[i]
+      if (digit == 0) {
+        // shorter has only the remaining virtual sign bits
+        for (; i < longer.numberLength && (digit = ~longer.digits[i]) == 0; i++) {
+          // empty
+        }
+        if (digit == 0) {
+          resLength = longer.numberLength + 1;
+          resDigits = new int[resLength];
+          resDigits[resLength - 1] = 1;
+
+          BigInteger result = new BigInteger(-1, resLength, resDigits);
+          return result;
+        }
+      }
+    }
+    resLength = longer.numberLength;
+    resDigits = new int[resLength];
+    resDigits[i] = -digit;
+    for (i++; i < shorter.numberLength; i++) {
+      // resDigits[i] = ~(~longer.digits[i] & ~shorter.digits[i];)
+      resDigits[i] = longer.digits[i] | shorter.digits[i];
+    }
+    // shorter has only the remaining virtual sign bits
+    for (; i < longer.numberLength; i++) {
+      resDigits[i] = longer.digits[i];
+    }
+
+    BigInteger result = new BigInteger(-1, resLength, resDigits);
+    return result;
+  }
+
+  /**
+   * @see BigInteger#andNot(BigInteger)
+   * @param val
+   * @param that
+   * @return
+   */
+  static BigInteger andNot(BigInteger val, BigInteger that) {
+    if (that.sign == 0) {
+      return val;
+    }
+    if (val.sign == 0) {
+      return BigInteger.ZERO;
+    }
+    if (val.equals(BigInteger.MINUS_ONE)) {
+      return that.not();
+    }
+    if (that.equals(BigInteger.MINUS_ONE)) {
+      return BigInteger.ZERO;
+    }
+
+    // if val == that, return 0
+
+    if (val.sign > 0) {
+      if (that.sign > 0) {
+        return andNotPositive(val, that);
+      } else {
+        return andNotPositiveNegative(val, that);
+      }
+    } else {
+      if (that.sign > 0) {
+        return andNotNegativePositive(val, that);
+      } else {
+        return andNotNegative(val, that);
+      }
+    }
+  }
+
+  /**
+   * Return sign = 1, magnitude = -val.magnitude & ~(-that.magnitude).
+   * @param val
+   * @param that
+   * @return
+   */
+  static BigInteger andNotNegative(BigInteger val, BigInteger that) {
+    // PRE: val < 0 && that < 0
+    int iVal = val.getFirstNonzeroDigit();
+    int iThat = that.getFirstNonzeroDigit();
+
+    if (iVal >= that.numberLength) {
+      return BigInteger.ZERO;
+    }
+
+    int resLength = that.numberLength;
+    int resDigits[] = new int[resLength];
+    int limit;
+    int i = iVal;
+    if (iVal < iThat) {
+      // resDigits[i] = -val.digits[i] & -1;
+      resDigits[i] = -val.digits[i];
+      limit = Math.min(val.numberLength, iThat);
+      for (i++; i < limit; i++) {
+        // resDigits[i] = ~val.digits[i] & -1;
+        resDigits[i] = ~val.digits[i];
+      }
+      if (i == val.numberLength) {
+        for (; i < iThat; i++) {
+          // resDigits[i] = -1 & -1;
+          resDigits[i] = -1;
+        }
+        // resDigits[i] = -1 & ~-that.digits[i];
+        resDigits[i] = that.digits[i] - 1;
+      } else {
+        // resDigits[i] = ~val.digits[i] & ~-that.digits[i];
+        resDigits[i] = ~val.digits[i] & (that.digits[i] - 1);
+      }
+    } else if (iThat < iVal) {
+      // resDigits[i] = -val.digits[i] & ~~that.digits[i];
+      resDigits[i] = -val.digits[i] & that.digits[i];
+    } else {
+      // resDigits[i] = -val.digits[i] & ~-that.digits[i];
+      resDigits[i] = -val.digits[i] & (that.digits[i] - 1);
+    }
+
+    limit = Math.min(val.numberLength, that.numberLength);
+    for (i++; i < limit; i++) {
+      // resDigits[i] = ~val.digits[i] & ~~that.digits[i];
+      resDigits[i] = ~val.digits[i] & that.digits[i];
+    }
+    for (; i < that.numberLength; i++) {
+      // resDigits[i] = -1 & ~~that.digits[i];
+      resDigits[i] = that.digits[i];
+    }
+
+    BigInteger result = new BigInteger(1, resLength, resDigits);
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  /**
+   * Return sign = -1, magnitude = -(-negative.magnitude & ~positive.magnitude).
+   * @param negative
+   * @param positive
+   * @return
+   */
+  static BigInteger andNotNegativePositive(BigInteger negative,
+      BigInteger positive) {
+    // PRE: negative < 0 && positive > 0
+    int resLength;
+    int resDigits[];
+    int limit;
+    int digit;
+
+    int iNeg = negative.getFirstNonzeroDigit();
+    int iPos = positive.getFirstNonzeroDigit();
+
+    if (iNeg >= positive.numberLength) {
+      return negative;
+    }
+
+    resLength = Math.max(negative.numberLength, positive.numberLength);
+    int i = iNeg;
+    if (iPos > iNeg) {
+      resDigits = new int[resLength];
+      limit = Math.min(negative.numberLength, iPos);
+      for (; i < limit; i++) {
+        // 1st case: resDigits [i] = -(-negative.digits[i] & (~0))
+        // otherwise: resDigits[i] = ~(~negative.digits[i] & ~0) ;
+        resDigits[i] = negative.digits[i];
+      }
+      if (i == negative.numberLength) {
+        for (i = iPos; i < positive.numberLength; i++) {
+          // resDigits[i] = ~(~positive.digits[i] & -1);
+          resDigits[i] = positive.digits[i];
+        }
+      }
+    } else {
+      digit = -negative.digits[i] & ~positive.digits[i];
+      if (digit == 0) {
+        limit = Math.min(positive.numberLength, negative.numberLength);
+        for (i++; i < limit
+            && (digit = ~(negative.digits[i] | positive.digits[i])) == 0; i++) {
+          // digit
+        }
+        // = ~negative.digits[i] & ~positive.digits[i]
+        if (digit == 0) {
+          // the shorter has only the remaining virtual sign bits
+          for (; i < positive.numberLength
+              && (digit = ~positive.digits[i]) == 0; i++) {
+            // digit = -1 & ~positive.digits[i]
+          }
+          for (; i < negative.numberLength
+              && (digit = ~negative.digits[i]) == 0; i++) {
+            // empty
+          }
+          // digit = ~negative.digits[i] & ~0
+          if (digit == 0) {
+            resLength++;
+            resDigits = new int[resLength];
+            resDigits[resLength - 1] = 1;
+
+            BigInteger result = new BigInteger(-1, resLength, resDigits);
+            return result;
+          }
+        }
+      }
+      resDigits = new int[resLength];
+      resDigits[i] = -digit;
+      i++;
+    }
+
+    limit = Math.min(positive.numberLength, negative.numberLength);
+    for (; i < limit; i++) {
+      // resDigits[i] = ~(~negative.digits[i] & ~positive.digits[i]);
+      resDigits[i] = negative.digits[i] | positive.digits[i];
+    }
+    // Actually one of the next two cycles will be executed
+    for (; i < negative.numberLength; i++) {
+      resDigits[i] = negative.digits[i];
+    }
+    for (; i < positive.numberLength; i++) {
+      resDigits[i] = positive.digits[i];
+    }
+
+    BigInteger result = new BigInteger(-1, resLength, resDigits);
+    return result;
+  }
+
+  /**
+   * Return sign = 1, magnitude = val.magnitude & ~that.magnitude.
+   * @param val
+   * @param that
+   * @return
+   */
+  static BigInteger andNotPositive(BigInteger val, BigInteger that) {
+    // PRE: both arguments are positive
+    int resDigits[] = new int[val.numberLength];
+
+    int limit = Math.min(val.numberLength, that.numberLength);
+    int i;
+    for (i = val.getFirstNonzeroDigit(); i < limit; i++) {
+      resDigits[i] = val.digits[i] & ~that.digits[i];
+    }
+    for (; i < val.numberLength; i++) {
+      resDigits[i] = val.digits[i];
+    }
+
+    BigInteger result = new BigInteger(1, val.numberLength, resDigits);
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  /**
+   * Return sign = 1, magnitude = positive.magnitude & ~(-negative.magnitude).
+   * @param positive
+   * @param negative
+   * @return
+   */
+  static BigInteger andNotPositiveNegative(BigInteger positive,
+      BigInteger negative) {
+    // PRE: positive > 0 && negative < 0
+    int iNeg = negative.getFirstNonzeroDigit();
+    int iPos = positive.getFirstNonzeroDigit();
+
+    if (iNeg >= positive.numberLength) {
+      return positive;
+    }
+
+    int resLength = Math.min(positive.numberLength, negative.numberLength);
+    int resDigits[] = new int[resLength];
+
+    // Always start from first non zero of positive
+    int i = iPos;
+    for (; i < iNeg; i++) {
+      // resDigits[i] = positive.digits[i] & -1 (~0)
+      resDigits[i] = positive.digits[i];
+    }
+    if (i == iNeg) {
+      resDigits[i] = positive.digits[i] & (negative.digits[i] - 1);
+      i++;
+    }
+    for (; i < resLength; i++) {
+      // resDigits[i] = positive.digits[i] & ~(~negative.digits[i]);
+      resDigits[i] = positive.digits[i] & negative.digits[i];
+    }
+
+    BigInteger result = new BigInteger(1, resLength, resDigits);
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  /**
+   * Return sign = 1, magnitude = val.magnitude & that.magnitude.
+   * @param val
+   * @param that
+   * @return
+   */
+  static BigInteger andPositive(BigInteger val, BigInteger that) {
+    // PRE: both arguments are positive
+    int resLength = Math.min(val.numberLength, that.numberLength);
+    int i = Math.max(val.getFirstNonzeroDigit(), that.getFirstNonzeroDigit());
+
+    if (i >= resLength) {
+      return BigInteger.ZERO;
+    }
+
+    int resDigits[] = new int[resLength];
+    for (; i < resLength; i++) {
+      resDigits[i] = val.digits[i] & that.digits[i];
+    }
+
+    BigInteger result = new BigInteger(1, resLength, resDigits);
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  /**
+   * @see BigInteger#not()
+   * @param val
+   * @return
+   */
+  static BigInteger not(BigInteger val) {
+    if (val.sign == 0) {
+      return BigInteger.MINUS_ONE;
+    }
+    if (val.equals(BigInteger.MINUS_ONE)) {
+      return BigInteger.ZERO;
+    }
+    int resDigits[] = new int[val.numberLength + 1];
+    int i;
+
+    if (val.sign > 0) {
+      // ~val = -val + 1
+      if (val.digits[val.numberLength - 1] != -1) {
+        for (i = 0; val.digits[i] == -1; i++) {
+          // empty
+        }
+      } else {
+        for (i = 0; (i < val.numberLength) && (val.digits[i] == -1); i++) {
+          // empty
+        }
+        if (i == val.numberLength) {
+          resDigits[i] = 1;
+          return new BigInteger(-val.sign, i + 1, resDigits);
+        }
+      }
+      // Here a carry 1 was generated
+    } else {
+      // (val.sign < 0)
+      // ~val = -val - 1
+      for (i = 0; val.digits[i] == 0; i++) {
+        resDigits[i] = -1;
+      }
+      // Here a borrow -1 was generated
+    }
+    // Now, the carry/borrow can be absorbed
+    resDigits[i] = val.digits[i] + val.sign;
+    // Copying the remaining unchanged digit
+    for (i++; i < val.numberLength; i++) {
+      resDigits[i] = val.digits[i];
+    }
+    return new BigInteger(-val.sign, i, resDigits);
+  }
+
+  /**
+   * @see BigInteger#or(BigInteger).
+   * @param val
+   * @param that
+   * @return
+   */
+  static BigInteger or(BigInteger val, BigInteger that) {
+    if (that.equals(BigInteger.MINUS_ONE) || val.equals(BigInteger.MINUS_ONE)) {
+      return BigInteger.MINUS_ONE;
+    }
+    if (that.sign == 0) {
+      return val;
+    }
+    if (val.sign == 0) {
+      return that;
+    }
+
+    if (val.sign > 0) {
+      if (that.sign > 0) {
+        if (val.numberLength > that.numberLength) {
+          return orPositive(val, that);
+        } else {
+          return orPositive(that, val);
+        }
+      } else {
+        return orDiffSigns(val, that);
+      }
+    } else {
+      if (that.sign > 0) {
+        return orDiffSigns(that, val);
+      } else if (that.getFirstNonzeroDigit() > val.getFirstNonzeroDigit()) {
+        return orNegative(that, val);
+      } else {
+        return orNegative(val, that);
+      }
+    }
+  }
+
+  /**
+   * Return sign = -1, magnitude = -(positive.magnitude | -negative.magnitude).
+   * @param positive
+   * @param negative
+   * @return
+   */
+  static BigInteger orDiffSigns(BigInteger positive, BigInteger negative) {
+    // Jumping over the least significant zero bits
+    int iNeg = negative.getFirstNonzeroDigit();
+    int iPos = positive.getFirstNonzeroDigit();
+    int i;
+    int limit;
+
+    // Look if the trailing zeros of the positive will "copy" all
+    // the negative digits
+    if (iPos >= negative.numberLength) {
+      return negative;
+    }
+    int resLength = negative.numberLength;
+    int resDigits[] = new int[resLength];
+
+    if (iNeg < iPos) {
+      // We know for sure that this will
+      // be the first non zero digit in the result
+      for (i = iNeg; i < iPos; i++) {
+        resDigits[i] = negative.digits[i];
+      }
+    } else if (iPos < iNeg) {
+      i = iPos;
+      resDigits[i] = -positive.digits[i];
+      limit = Math.min(positive.numberLength, iNeg);
+      for (i++; i < limit; i++) {
+        resDigits[i] = ~positive.digits[i];
+      }
+      if (i != positive.numberLength) {
+        resDigits[i] = ~(-negative.digits[i] | positive.digits[i]);
+      } else {
+        for (; i < iNeg; i++) {
+          resDigits[i] = -1;
+        }
+        // resDigits[i] = ~(-negative.digits[i] | 0);
+        resDigits[i] = negative.digits[i] - 1;
+      }
+      i++;
+    } else {
+      // iNeg == iPos
+      // Applying two complement to negative and to result
+      i = iPos;
+      resDigits[i] = -(-negative.digits[i] | positive.digits[i]);
+      i++;
+    }
+    limit = Math.min(negative.numberLength, positive.numberLength);
+    for (; i < limit; i++) {
+      // Applying two complement to negative and to result
+      // resDigits[i] = ~(~negative.digits[i] | positive.digits[i] );
+      resDigits[i] = negative.digits[i] & ~positive.digits[i];
+    }
+    for (; i < negative.numberLength; i++) {
+      resDigits[i] = negative.digits[i];
+    }
+
+    BigInteger result = new BigInteger(-1, resLength, resDigits);
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  /**
+   * Return sign = -1, magnitude = -(-val.magnitude | -that.magnitude).
+   * @param val
+   * @param that
+   * @return
+   */
+  static BigInteger orNegative(BigInteger val, BigInteger that) {
+    // PRE: val and that are negative;
+    // PRE: val has at least as many trailing zeros digits as that
+    int iThat = that.getFirstNonzeroDigit();
+    int iVal = val.getFirstNonzeroDigit();
+    int i;
+
+    if (iVal >= that.numberLength) {
+      return that;
+    } else if (iThat >= val.numberLength) {
+      return val;
+    }
+
+    int resLength = Math.min(val.numberLength, that.numberLength);
+    int resDigits[] = new int[resLength];
+
+    // Looking for the first non-zero digit of the result
+    if (iThat == iVal) {
+      resDigits[iVal] = -(-val.digits[iVal] | -that.digits[iVal]);
+      i = iVal;
+    } else {
+      for (i = iThat; i < iVal; i++) {
+        resDigits[i] = that.digits[i];
+      }
+      resDigits[i] = that.digits[i] & (val.digits[i] - 1);
+    }
+
+    for (i++; i < resLength; i++) {
+      resDigits[i] = val.digits[i] & that.digits[i];
+    }
+
+    BigInteger result = new BigInteger(-1, resLength, resDigits);
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  /**
+   * Return sign = 1, magnitude = longer.magnitude | shorter.magnitude.
+   * @param longer
+   * @param shorter
+   * @return
+   */
+  static BigInteger orPositive(BigInteger longer, BigInteger shorter) {
+    // PRE: longer and shorter are positive;
+    // PRE: longer has at least as many digits as shorter
+    int resLength = longer.numberLength;
+    int resDigits[] = new int[resLength];
+
+    int i = Math.min(longer.getFirstNonzeroDigit(),
+        shorter.getFirstNonzeroDigit());
+    for (i = 0; i < shorter.numberLength; i++) {
+      resDigits[i] = longer.digits[i] | shorter.digits[i];
+    }
+    for (; i < resLength; i++) {
+      resDigits[i] = longer.digits[i];
+    }
+
+    BigInteger result = new BigInteger(1, resLength, resDigits);
+    return result;
+  }
+
+  /**
+   * @see BigInteger#xor(BigInteger)
+   * @param val
+   * @param that
+   * @return
+   */
+  static BigInteger xor(BigInteger val, BigInteger that) {
+    if (that.sign == 0) {
+      return val;
+    }
+    if (val.sign == 0) {
+      return that;
+    }
+    if (that.equals(BigInteger.MINUS_ONE)) {
+      return val.not();
+    }
+    if (val.equals(BigInteger.MINUS_ONE)) {
+      return that.not();
+    }
+
+    if (val.sign > 0) {
+      if (that.sign > 0) {
+        if (val.numberLength > that.numberLength) {
+          return xorPositive(val, that);
+        } else {
+          return xorPositive(that, val);
+        }
+      } else {
+        return xorDiffSigns(val, that);
+      }
+    } else {
+      if (that.sign > 0) {
+        return xorDiffSigns(that, val);
+      } else if (that.getFirstNonzeroDigit() > val.getFirstNonzeroDigit()) {
+        return xorNegative(that, val);
+      } else {
+        return xorNegative(val, that);
+      }
+    }
+  }
+
+  /**
+   * Return sign = 1, magnitude = -(positive.magnitude ^ -negative.magnitude).
+   * @param positive
+   * @param negative
+   * @return
+   */
+  static BigInteger xorDiffSigns(BigInteger positive, BigInteger negative) {
+    int resLength = Math.max(negative.numberLength, positive.numberLength);
+    int resDigits[];
+    int iNeg = negative.getFirstNonzeroDigit();
+    int iPos = positive.getFirstNonzeroDigit();
+    int i;
+    int limit;
+
+    // The first
+    if (iNeg < iPos) {
+      resDigits = new int[resLength];
+      i = iNeg;
+      // resDigits[i] = -(-negative.digits[i]);
+      resDigits[i] = negative.digits[i];
+      limit = Math.min(negative.numberLength, iPos);
+      // Skip the positive digits while they are zeros
+      for (i++; i < limit; i++) {
+        // resDigits[i] = ~(~negative.digits[i]);
+        resDigits[i] = negative.digits[i];
+      }
+      // if the negative has no more elements, must fill the
+      // result with the remaining digits of the positive
+      if (i == negative.numberLength) {
+        for (; i < positive.numberLength; i++) {
+          // resDigits[i] = ~(positive.digits[i] ^ -1) -> ~(~positive.digits[i])
+          resDigits[i] = positive.digits[i];
+        }
+      }
+    } else if (iPos < iNeg) {
+      resDigits = new int[resLength];
+      i = iPos;
+      // Applying two complement to the first non-zero digit of the result
+      resDigits[i] = -positive.digits[i];
+      limit = Math.min(positive.numberLength, iNeg);
+      for (i++; i < limit; i++) {
+        // Continue applying two complement the result
+        resDigits[i] = ~positive.digits[i];
+      }
+      // When the first non-zero digit of the negative is reached, must apply
+      // two complement (arithmetic negation) to it, and then operate
+      if (i == iNeg) {
+        resDigits[i] = ~(positive.digits[i] ^ -negative.digits[i]);
+        i++;
+      } else {
+        // if the positive has no more elements must fill the remaining digits
+        // with
+        // the negative ones
+        for (; i < iNeg; i++) {
+          // resDigits[i] = ~(0 ^ 0)
+          resDigits[i] = -1;
+        }
+        for (; i < negative.numberLength; i++) {
+          // resDigits[i] = ~(~negative.digits[i] ^ 0)
+          resDigits[i] = negative.digits[i];
+        }
+      }
+    } else {
+      int digit;
+      // The first non-zero digit of the positive and negative are the same
+      i = iNeg;
+      digit = positive.digits[i] ^ -negative.digits[i];
+      if (digit == 0) {
+        limit = Math.min(positive.numberLength, negative.numberLength);
+        for (i++; i < limit
+            && (digit = positive.digits[i] ^ ~negative.digits[i]) == 0; i++) {
+          // empty
+        }
+        if (digit == 0) {
+          // shorter has only the remaining virtual sign bits
+          for (; i < positive.numberLength
+              && (digit = ~positive.digits[i]) == 0; i++) {
+            // empty
+          }
+          for (; i < negative.numberLength
+              && (digit = ~negative.digits[i]) == 0; i++) {
+            // empty
+          }
+          if (digit == 0) {
+            resLength = resLength + 1;
+            resDigits = new int[resLength];
+            resDigits[resLength - 1] = 1;
+
+            BigInteger result = new BigInteger(-1, resLength, resDigits);
+            return result;
+          }
+        }
+      }
+      resDigits = new int[resLength];
+      resDigits[i] = -digit;
+      i++;
+    }
+
+    limit = Math.min(negative.numberLength, positive.numberLength);
+    for (; i < limit; i++) {
+      resDigits[i] = ~(~negative.digits[i] ^ positive.digits[i]);
+    }
+    for (; i < positive.numberLength; i++) {
+      // resDigits[i] = ~(positive.digits[i] ^ -1)
+      resDigits[i] = positive.digits[i];
+    }
+    for (; i < negative.numberLength; i++) {
+      // resDigits[i] = ~(0 ^ ~negative.digits[i])
+      resDigits[i] = negative.digits[i];
+    }
+
+    BigInteger result = new BigInteger(-1, resLength, resDigits);
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  /**
+   * Return sign = 0, magnitude = -val.magnitude ^ -that.magnitude.
+   * @param val
+   * @param that
+   * @return
+   */
+  static BigInteger xorNegative(BigInteger val, BigInteger that) {
+    // PRE: val and that are negative
+    // PRE: val has at least as many trailing zero digits as that
+    int resLength = Math.max(val.numberLength, that.numberLength);
+    int resDigits[] = new int[resLength];
+    int iVal = val.getFirstNonzeroDigit();
+    int iThat = that.getFirstNonzeroDigit();
+    int i = iThat;
+    int limit;
+
+    if (iVal == iThat) {
+      resDigits[i] = -val.digits[i] ^ -that.digits[i];
+    } else {
+      resDigits[i] = -that.digits[i];
+      limit = Math.min(that.numberLength, iVal);
+      for (i++; i < limit; i++) {
+        resDigits[i] = ~that.digits[i];
+      }
+      // Remains digits in that?
+      if (i == that.numberLength) {
+        // Jumping over the remaining zero to the first non one
+        for (; i < iVal; i++) {
+          // resDigits[i] = 0 ^ -1;
+          resDigits[i] = -1;
+        }
+        // resDigits[i] = -val.digits[i] ^ -1;
+        resDigits[i] = val.digits[i] - 1;
+      } else {
+        resDigits[i] = -val.digits[i] ^ ~that.digits[i];
+      }
+    }
+
+    limit = Math.min(val.numberLength, that.numberLength);
+    // Perform ^ between that al val until that ends
+    for (i++; i < limit; i++) {
+      // resDigits[i] = ~val.digits[i] ^ ~that.digits[i];
+      resDigits[i] = val.digits[i] ^ that.digits[i];
+    }
+    // Perform ^ between val digits and -1 until val ends
+    for (; i < val.numberLength; i++) {
+      // resDigits[i] = ~val.digits[i] ^ -1 ;
+      resDigits[i] = val.digits[i];
+    }
+    for (; i < that.numberLength; i++) {
+      // resDigits[i] = -1 ^ ~that.digits[i] ;
+      resDigits[i] = that.digits[i];
+    }
+
+    BigInteger result = new BigInteger(1, resLength, resDigits);
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  /**
+   * Return sign = 0, magnitude = longer.magnitude | shorter.magnitude.
+   * 
+   * @param longer
+   * @param shorter
+   * @return
+   */
+  static BigInteger xorPositive(BigInteger longer, BigInteger shorter) {
+    // PRE: longer and shorter are positive;
+    // PRE: longer has at least as many digits as shorter
+    int resLength = longer.numberLength;
+    int resDigits[] = new int[resLength];
+    int i = Math.min(longer.getFirstNonzeroDigit(),
+        shorter.getFirstNonzeroDigit());
+    for (; i < shorter.numberLength; i++) {
+      resDigits[i] = longer.digits[i] ^ shorter.digits[i];
+    }
+    for (; i < longer.numberLength; i++) {
+      resDigits[i] = longer.digits[i];
+    }
+
+    BigInteger result = new BigInteger(1, resLength, resDigits);
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  /**
+   * Just to denote that this class can't be instantiated.
+   */
+  private Logical() {
+  }
+}
diff --git a/user/super/com/google/gwt/emul/java/math/MathContext.java b/user/super/com/google/gwt/emul/java/math/MathContext.java
new file mode 100644
index 0000000..ecde7c2
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/math/MathContext.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE.
+ */
+package java.math;
+
+import java.io.Serializable;
+
+/**
+ * Immutable objects describing settings such as rounding mode and digit
+ * precision for the numerical operations provided by class {@link BigDecimal}.
+ */
+public final class MathContext implements Serializable {
+
+  /**
+   * A {@code MathContext} which corresponds to the IEEE 754r quadruple decimal
+   * precision format: 34 digit precision and {@link RoundingMode#HALF_EVEN}
+   * rounding.
+   */
+  public static final MathContext DECIMAL128 = new MathContext(34,
+      RoundingMode.HALF_EVEN);
+
+  /**
+   * A {@code MathContext} which corresponds to the IEEE 754r single decimal
+   * precision format: 7 digit precision and {@link RoundingMode#HALF_EVEN}
+   * rounding.
+   */
+  public static final MathContext DECIMAL32 = new MathContext(7,
+      RoundingMode.HALF_EVEN);
+
+  /**
+   * A {@code MathContext} which corresponds to the IEEE 754r double decimal
+   * precision format: 16 digit precision and {@link RoundingMode#HALF_EVEN}
+   * rounding.
+   */
+  public static final MathContext DECIMAL64 = new MathContext(16,
+      RoundingMode.HALF_EVEN);
+
+  /**
+   * A {@code MathContext} for unlimited precision with
+   * {@link RoundingMode#HALF_UP} rounding.
+   */
+  public static final MathContext UNLIMITED = new MathContext(0,
+      RoundingMode.HALF_UP);
+
+  /**
+   * An array of {@code char} containing: {@code
+   * 'p','r','e','c','i','s','i','o','n','='}. It's used to improve the methods
+   * related to {@code String} conversion.
+   * 
+   * @see #MathContext(String)
+   * @see #toString()
+   */
+  private static final char[] chPrecision = {
+      'p', 'r', 'e', 'c', 'i', 's', 'i', 'o', 'n', '='};
+
+  /**
+   * An array of {@code char} containing: {@code
+   * 'r','o','u','n','d','i','n','g','M','o','d','e','='}. It's used to improve
+   * the methods related to {@code String} conversion.
+   * 
+   * @see #MathContext(String)
+   * @see #toString()
+   */
+  private static final char[] chRoundingMode = {
+      'r', 'o', 'u', 'n', 'd', 'i', 'n', 'g', 'M', 'o', 'd', 'e', '='};
+
+  /**
+   * This is the serialVersionUID used by the sun implementation.
+   */
+  private static final long serialVersionUID = 5579720004786848255L;
+
+  /**
+   * The number of digits to be used for an operation; results are rounded to
+   * this precision.
+   */
+  private int precision;
+
+  /**
+   * A {@code RoundingMode} object which specifies the algorithm to be used for
+   * rounding.
+   */
+  private RoundingMode roundingMode;
+
+  /**
+   * Constructs a new {@code MathContext} with the specified precision and with
+   * the rounding mode {@link RoundingMode#HALF_UP HALF_UP}. If the precision
+   * passed is zero, then this implies that the computations have to be
+   * performed exact, the rounding mode in this case is irrelevant.
+   * 
+   * @param precision the precision for the new {@code MathContext}.
+   * @throws IllegalArgumentException if {@code precision < 0}.
+   */
+  public MathContext(int precision) {
+    this(precision, RoundingMode.HALF_UP);
+  }
+
+  /**
+   * Constructs a new {@code MathContext} with the specified precision and with
+   * the specified rounding mode. If the precision passed is zero, then this
+   * implies that the computations have to be performed exact, the rounding mode
+   * in this case is irrelevant.
+   * 
+   * @param precision the precision for the new {@code MathContext}.
+   * @param roundingMode the rounding mode for the new {@code MathContext}.
+   * @throws IllegalArgumentException if {@code precision < 0}.
+   * @throws NullPointerException if {@code roundingMode} is {@code null}.
+   */
+  public MathContext(int precision, RoundingMode roundingMode) {
+    if (precision < 0) {
+      // math.0C=Digits < 0
+      throw new IllegalArgumentException("Digits < 0"); //$NON-NLS-1$
+    }
+    if (roundingMode == null) {
+      // math.0D=null RoundingMode
+      throw new NullPointerException("null RoundingMode"); //$NON-NLS-1$
+    }
+    this.precision = precision;
+    this.roundingMode = roundingMode;
+  }
+
+  /**
+   * Constructs a new {@code MathContext} from a string. The string has to
+   * specify the precision and the rounding mode to be used and has to follow
+   * the following syntax:
+   * "precision=&lt;precision&gt; roundingMode=&lt;roundingMode&gt;" This is the
+   * same form as the one returned by the {@link #toString} method.
+   * 
+   * @param val a string describing the precision and rounding mode for the new
+   *          {@code MathContext}.
+   * @throws IllegalArgumentException if the string is not in the correct format
+   *           or if the precision specified is < 0.
+   */
+  public MathContext(String val) {
+    char[] charVal = val.toCharArray();
+    int i; // Index of charVal
+    int j; // Index of chRoundingMode
+    int digit; // It will contain the digit parsed
+
+    if ((charVal.length < 27) || (charVal.length > 45)) {
+      // math.0E=bad string format
+      throw new IllegalArgumentException("bad string format"); //$NON-NLS-1$
+    }
+    // Parsing "precision=" String
+    for (i = 0; (i < chPrecision.length) && (charVal[i] == chPrecision[i]); i++) {
+      // empty
+    }
+
+    if (i < chPrecision.length) {
+      // math.0E=bad string format
+      throw new IllegalArgumentException("bad string format"); //$NON-NLS-1$
+    }
+    // Parsing the value for "precision="...
+    digit = Character.digit(charVal[i], 10);
+    if (digit == -1) {
+      // math.0E=bad string format
+      throw new IllegalArgumentException("bad string format"); //$NON-NLS-1$
+    }
+    this.precision = this.precision * 10 + digit;
+    i++;
+
+    do {
+      digit = Character.digit(charVal[i], 10);
+      if (digit == -1) {
+        if (charVal[i] == ' ') {
+          // It parsed all the digits
+          i++;
+          break;
+        }
+        // It isn't a valid digit, and isn't a white space
+        // math.0E=bad string format
+        throw new IllegalArgumentException("bad string format"); //$NON-NLS-1$
+      }
+      // Accumulating the value parsed
+      this.precision = this.precision * 10 + digit;
+      if (this.precision < 0) {
+        // math.0E=bad string format
+        throw new IllegalArgumentException("bad string format"); //$NON-NLS-1$
+      }
+      i++;
+    } while (true);
+    // Parsing "roundingMode="
+    for (j = 0; (j < chRoundingMode.length)
+        && (charVal[i] == chRoundingMode[j]); i++, j++) {
+      // empty
+    }
+
+    if (j < chRoundingMode.length) {
+      // math.0E=bad string format
+      throw new IllegalArgumentException("bad string format"); //$NON-NLS-1$
+    }
+    // Parsing the value for "roundingMode"...
+    this.roundingMode = RoundingMode.valueOf(String.valueOf(charVal, i,
+        charVal.length - i));
+  }
+
+  /* Public Methods */
+
+  /**
+   * Returns true if x is a {@code MathContext} with the same precision setting
+   * and the same rounding mode as this {@code MathContext} instance.
+   * 
+   * @param x object to be compared.
+   * @return {@code true} if this {@code MathContext} instance is equal to the
+   *         {@code x} argument; {@code false} otherwise.
+   */
+  @Override
+  public boolean equals(Object x) {
+    return ((x instanceof MathContext)
+        && (((MathContext) x).getPrecision() == precision) && (((MathContext) x).getRoundingMode() == roundingMode));
+  }
+
+  /**
+   * Returns the precision. The precision is the number of digits used for an
+   * operation. Results are rounded to this precision. The precision is
+   * guaranteed to be non negative. If the precision is zero, then the
+   * computations have to be performed exact, results are not rounded in this
+   * case.
+   * 
+   * @return the precision.
+   */
+  public int getPrecision() {
+    return precision;
+  }
+
+  /**
+   * Returns the rounding mode. The rounding mode is the strategy to be used to
+   * round results.
+   * <p>
+   * The rounding mode is one of {@link RoundingMode#UP},
+   * {@link RoundingMode#DOWN}, {@link RoundingMode#CEILING},
+   * {@link RoundingMode#FLOOR}, {@link RoundingMode#HALF_UP},
+   * {@link RoundingMode#HALF_DOWN}, {@link RoundingMode#HALF_EVEN}, or
+   * {@link RoundingMode#UNNECESSARY}.
+   * 
+   * @return the rounding mode.
+   */
+  public RoundingMode getRoundingMode() {
+    return roundingMode;
+  }
+
+  /**
+   * Returns the hash code for this {@code MathContext} instance.
+   * 
+   * @return the hash code for this {@code MathContext}.
+   */
+  @Override
+  public int hashCode() {
+    // Make place for the necessary bits to represent 8 rounding modes
+    return ((precision << 3) | roundingMode.ordinal());
+  }
+
+  /**
+   * Returns the string representation for this {@code MathContext} instance.
+   * The string has the form {@code
+   * "precision=&lt;precision&gt; roundingMode=&lt;roundingMode&gt;" * } where
+   * {@code &lt;precision&gt;} is an integer describing the number of digits
+   * used for operations and {@code &lt;roundingMode&gt;} is the string
+   * representation of the rounding mode.
+   * 
+   * @return a string representation for this {@code MathContext} instance
+   */
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder(45);
+
+    sb.append(chPrecision);
+    sb.append(precision);
+    sb.append(' ');
+    sb.append(chRoundingMode);
+    sb.append(roundingMode);
+    return sb.toString();
+  }
+}
diff --git a/user/super/com/google/gwt/emul/java/math/Multiplication.java b/user/super/com/google/gwt/emul/java/math/Multiplication.java
new file mode 100644
index 0000000..22fdf49
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/math/Multiplication.java
@@ -0,0 +1,534 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE.
+ */
+package java.math;
+
+/**
+ * Static library that provides all multiplication of {@link BigInteger}
+ * methods.
+ */
+class Multiplication {
+
+  /**
+   * An array with the first powers of five in {@code BigInteger} version. (
+   * {@code 5^0,5^1,...,5^31})
+   */
+  static final BigInteger bigFivePows[] = new BigInteger[32];
+
+  /**
+   * An array with the first powers of ten in {@code BigInteger} version. (
+   * {@code 10^0,10^1,...,10^31})
+   */
+  static final BigInteger[] bigTenPows = new BigInteger[32];
+
+  /**
+   * An array with powers of five that fit in the type {@code int}. ({@code
+   * 5^0,5^1,...,5^13})
+   */
+  static final int fivePows[] = {
+      1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625,
+      48828125, 244140625, 1220703125};
+
+  /**
+   * An array with powers of ten that fit in the type {@code int}. ({@code
+   * 10^0,10^1,...,10^9})
+   */
+  static final int tenPows[] = {
+      1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
+
+  /**
+   * Break point in digits (number of {@code int} elements) between Karatsuba
+   * and Pencil and Paper multiply.
+   */
+  static final int whenUseKaratsuba = 63; // an heuristic value
+
+  static {
+    int i;
+    long fivePow = 1L;
+
+    for (i = 0; i <= 18; i++) {
+      bigFivePows[i] = BigInteger.valueOf(fivePow);
+      bigTenPows[i] = BigInteger.valueOf(fivePow << i);
+      fivePow *= 5;
+    }
+    for (; i < bigTenPows.length; i++) {
+      bigFivePows[i] = bigFivePows[i - 1].multiply(bigFivePows[1]);
+      bigTenPows[i] = bigTenPows[i - 1].multiply(BigInteger.TEN);
+    }
+  }
+
+  /**
+   * Performs the multiplication with the Karatsuba's algorithm. <b>Karatsuba's
+   * algorithm:</b> <tt>
+   *             u = u<sub>1</sub> * B + u<sub>0</sub><br>
+   *             v = v<sub>1</sub> * B + v<sub>0</sub><br>
+   * 
+   * 
+   *  u*v = (u<sub>1</sub> * v<sub>1</sub>) * B<sub>2</sub> + ((u<sub>1</sub> - u<sub>0</sub>) * (v<sub>0</sub> - v<sub>1</sub>) + u<sub>1</sub> * v<sub>1</sub> +
+   *  u<sub>0</sub> * v<sub>0</sub> ) * B + u<sub>0</sub> * v<sub>0</sub><br>
+     *</tt>
+   * 
+   * @param op1 first factor of the product
+   * @param op2 second factor of the product
+   * @return {@code op1 * op2}
+   * @see #multiply(BigInteger, BigInteger)
+   */
+  static BigInteger karatsuba(BigInteger op1, BigInteger op2) {
+    BigInteger temp;
+    if (op2.numberLength > op1.numberLength) {
+      temp = op1;
+      op1 = op2;
+      op2 = temp;
+    }
+    if (op2.numberLength < whenUseKaratsuba) {
+      return multiplyPAP(op1, op2);
+    }
+    /*
+     * Karatsuba: u = u1*B + u0 v = v1*B + v0 u*v = (u1*v1)*B^2 +
+     * ((u1-u0)*(v0-v1) + u1*v1 + u0*v0)*B + u0*v0
+     */
+    // ndiv2 = (op1.numberLength / 2) * 32
+    int ndiv2 = (op1.numberLength & 0xFFFFFFFE) << 4;
+    BigInteger upperOp1 = op1.shiftRight(ndiv2);
+    BigInteger upperOp2 = op2.shiftRight(ndiv2);
+    BigInteger lowerOp1 = op1.subtract(upperOp1.shiftLeft(ndiv2));
+    BigInteger lowerOp2 = op2.subtract(upperOp2.shiftLeft(ndiv2));
+
+    BigInteger upper = karatsuba(upperOp1, upperOp2);
+    BigInteger lower = karatsuba(lowerOp1, lowerOp2);
+    BigInteger middle = karatsuba(upperOp1.subtract(lowerOp1),
+        lowerOp2.subtract(upperOp2));
+    middle = middle.add(upper).add(lower);
+    middle = middle.shiftLeft(ndiv2);
+    upper = upper.shiftLeft(ndiv2 << 1);
+
+    return upper.add(middle).add(lower);
+  }
+
+  static void multArraysPAP(int[] aDigits, int aLen, int[] bDigits, int bLen,
+      int[] resDigits) {
+    if (aLen == 0 || bLen == 0) {
+      return;
+    }
+
+    if (aLen == 1) {
+      resDigits[bLen] = multiplyByInt(resDigits, bDigits, bLen, aDigits[0]);
+    } else if (bLen == 1) {
+      resDigits[aLen] = multiplyByInt(resDigits, aDigits, aLen, bDigits[0]);
+    } else {
+      multPAP(aDigits, bDigits, resDigits, aLen, bLen);
+    }
+  }
+
+  /**
+   * Performs a multiplication of two BigInteger and hides the algorithm used.
+   * 
+   * @see BigInteger#multiply(BigInteger)
+   */
+  static BigInteger multiply(BigInteger x, BigInteger y) {
+    return karatsuba(x, y);
+  }
+
+  /**
+   * Multiplies a number by a power of five. This method is used in {@code
+   * BigDecimal} class.
+   * 
+   * @param val the number to be multiplied
+   * @param exp a positive {@code int} exponent
+   * @return {@code val * 5<sup>exp</sup>}
+   */
+  static BigInteger multiplyByFivePow(BigInteger val, int exp) {
+    // PRE: exp >= 0
+    if (exp < fivePows.length) {
+      return multiplyByPositiveInt(val, fivePows[exp]);
+    } else if (exp < bigFivePows.length) {
+      return val.multiply(bigFivePows[exp]);
+    } else {
+      // Large powers of five
+      return val.multiply(bigFivePows[1].pow(exp));
+    }
+  }
+
+  /**
+   * Multiplies an array of integers by an integer value.
+   * 
+   * @param a the array of integers
+   * @param aSize the number of elements of intArray to be multiplied
+   * @param factor the multiplier
+   * @return the top digit of production
+   */
+  static int multiplyByInt(int a[], final int aSize, final int factor) {
+    return multiplyByInt(a, a, aSize, factor);
+  }
+
+  /**
+   * Multiplies a number by a positive integer.
+   * 
+   * @param val an arbitrary {@code BigInteger}
+   * @param factor a positive {@code int} number
+   * @return {@code val * factor}
+   */
+  static BigInteger multiplyByPositiveInt(BigInteger val, int factor) {
+    int resSign = val.sign;
+    if (resSign == 0) {
+      return BigInteger.ZERO;
+    }
+    int aNumberLength = val.numberLength;
+    int[] aDigits = val.digits;
+
+    if (aNumberLength == 1) {
+      long res = unsignedMultAddAdd(aDigits[0], factor, 0, 0);
+      int resLo = (int) res;
+      int resHi = (int) (res >>> 32);
+      return ((resHi == 0) ? new BigInteger(resSign, resLo) : new BigInteger(
+          resSign, 2, new int[] {resLo, resHi}));
+    }
+    // Common case
+    int resLength = aNumberLength + 1;
+    int resDigits[] = new int[resLength];
+
+    resDigits[aNumberLength] = multiplyByInt(resDigits, aDigits, aNumberLength,
+        factor);
+    BigInteger result = new BigInteger(resSign, resLength, resDigits);
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  /**
+   * Multiplies a number by a power of ten. This method is used in {@code
+   * BigDecimal} class.
+   * 
+   * @param val the number to be multiplied
+   * @param exp a positive {@code long} exponent
+   * @return {@code val * 10<sup>exp</sup>}
+   */
+  static BigInteger multiplyByTenPow(BigInteger val, int exp) {
+    // PRE: exp >= 0
+    return ((exp < tenPows.length) ? multiplyByPositiveInt(val,
+        tenPows[(int) exp]) : val.multiply(powerOf10(exp)));
+  }
+
+  /**
+   * Multiplies two BigIntegers. Implements traditional scholar algorithm
+   * described by Knuth.
+   * 
+   * <br>
+   * <tt>
+   *         <table border="0">
+   * <tbody>
+   * 
+   * 
+   * <tr>
+   * <td align="center">A=</td>
+   * <td>a<sub>3</sub></td>
+   * <td>a<sub>2</sub></td>
+   * <td>a<sub>1</sub></td>
+   * <td>a<sub>0</sub></td>
+   * <td></td>
+   * <td></td>
+   * </tr>
+   * 
+   * <tr>
+   * <td align="center">B=</td>
+   * <td></td>
+   * <td>b<sub>2</sub></td>
+   * <td>b<sub>1</sub></td>
+   * <td>b<sub>1</sub></td>
+   * <td></td>
+   * <td></td>
+   * </tr>
+   * 
+   * <tr>
+   * <td></td>
+   * <td></td>
+   * <td></td>
+   * <td>b<sub>0</sub>*a<sub>3</sub></td>
+   * <td>b<sub>0</sub>*a<sub>2</sub></td>
+   * <td>b<sub>0</sub>*a<sub>1</sub></td>
+   * <td>b<sub>0</sub>*a<sub>0</sub></td>
+   * </tr>
+   * 
+   * <tr>
+   * <td></td>
+   * <td></td>
+   * <td>b<sub>1</sub>*a<sub>3</sub></td>
+   * <td>b<sub>1</sub>*a<sub>2</sub></td>
+   * <td>b<sub>1</sub>*a1</td>
+   * <td>b<sub>1</sub>*a0</td>
+   * </tr>
+   * 
+   * <tr>
+   * <td>+</td>
+   * <td>b<sub>2</sub>*a<sub>3</sub></td>
+   * <td>b<sub>2</sub>*a<sub>2</sub></td>
+   * <td>b<sub>2</sub>*a<sub>1</sub></td>
+   * <td>b<sub>2</sub>*a<sub>0</sub></td>
+   * </tr>
+   * 
+   * <tr>
+   * <td></td>
+   * <td>______</td>
+   * <td>______</td>
+   * <td>______</td>
+   * <td>______</td>
+   * <td>______</td>
+   * <td>______</td>
+   * </tr>
+   * 
+   * <tr>
+   * 
+   * <td align="center">A*B=R=</td>
+   * <td align="center">r<sub>5</sub></td>
+   * <td align="center">r<sub>4</sub></td>
+   * <td align="center">r<sub>3</sub></td>
+   * <td align="center">r<sub>2</sub></td>
+   * <td align="center">r<sub>1</sub></td>
+   * <td align="center">r<sub>0</sub></td>
+   * <td></td>
+   * </tr>
+   * 
+   * </tbody>
+   * </table>
+     *
+     *</tt>
+   * 
+   * @param op1 first factor of the multiplication {@code op1 >= 0}
+   * @param op2 second factor of the multiplication {@code op2 >= 0}
+   * @return a {@code BigInteger} of value {@code op1 * op2}
+   */
+  static BigInteger multiplyPAP(BigInteger a, BigInteger b) {
+    // PRE: a >= b
+    int aLen = a.numberLength;
+    int bLen = b.numberLength;
+    int resLength = aLen + bLen;
+    int resSign = (a.sign != b.sign) ? -1 : 1;
+    // A special case when both numbers don't exceed int
+    if (resLength == 2) {
+      long val = unsignedMultAddAdd(a.digits[0], b.digits[0], 0, 0);
+      int valueLo = (int) val;
+      int valueHi = (int) (val >>> 32);
+      return ((valueHi == 0) ? new BigInteger(resSign, valueLo)
+          : new BigInteger(resSign, 2, new int[] {valueLo, valueHi}));
+    }
+    int[] aDigits = a.digits;
+    int[] bDigits = b.digits;
+    int resDigits[] = new int[resLength];
+    // Common case
+    multArraysPAP(aDigits, aLen, bDigits, bLen, resDigits);
+    BigInteger result = new BigInteger(resSign, resLength, resDigits);
+    result.cutOffLeadingZeroes();
+    return result;
+  }
+
+  static void multPAP(int a[], int b[], int t[], int aLen, int bLen) {
+    if (a == b && aLen == bLen) {
+      square(a, aLen, t);
+      return;
+    }
+
+    for (int i = 0; i < aLen; i++) {
+      long carry = 0;
+      int aI = a[i];
+      for (int j = 0; j < bLen; j++) {
+        carry = unsignedMultAddAdd(aI, b[j], t[i + j], (int) carry);
+        t[i + j] = (int) carry;
+        carry >>>= 32;
+      }
+      t[i + bLen] = (int) carry;
+    }
+  }
+
+  static BigInteger pow(BigInteger base, int exponent) {
+    // PRE: exp > 0
+    BigInteger res = BigInteger.ONE;
+    BigInteger acc = base;
+
+    for (; exponent > 1; exponent >>= 1) {
+      if ((exponent & 1) != 0) {
+        // if odd, multiply one more time by acc
+        res = res.multiply(acc);
+      }
+      // acc = base^(2^i)
+      // a limit where karatsuba performs a faster square than the square
+      // algorithm
+      if (acc.numberLength == 1) {
+        acc = acc.multiply(acc); // square
+      } else {
+        acc = new BigInteger(1, square(acc.digits, acc.numberLength,
+            new int[acc.numberLength << 1]));
+      }
+    }
+    // exponent == 1, multiply one more time
+    res = res.multiply(acc);
+    return res;
+  }
+
+  /**
+   * It calculates a power of ten, which exponent could be out of 32-bit range.
+   * Note that internally this method will be used in the worst case with an
+   * exponent equals to: {@code Integer.MAX_VALUE - Integer.MIN_VALUE}.
+   * 
+   * @param exp the exponent of power of ten, it must be positive.
+   * @return a {@code BigInteger} with value {@code 10<sup>exp</sup>}.
+   */
+  static BigInteger powerOf10(double exp) {
+    // PRE: exp >= 0
+    int intExp = (int) exp;
+    // "SMALL POWERS"
+    if (exp < bigTenPows.length) {
+      // The largest power that fit in 'long' type
+      return bigTenPows[intExp];
+    } else if (exp <= 50) {
+      // To calculate: 10^exp
+      return BigInteger.TEN.pow(intExp);
+    } else if (exp <= 1000) {
+      // To calculate: 5^exp * 2^exp
+      return bigFivePows[1].pow(intExp).shiftLeft(intExp);
+    }
+    // "LARGE POWERS"
+    /*
+     * To check if there is free memory to allocate a BigInteger of the
+     * estimated size, measured in bytes: 1 + [exp / log10(2)]
+     */
+    if (exp > 1000000) {
+      throw new ArithmeticException("power of ten too big"); //$NON-NLS-1$
+    }
+
+    if (exp <= Integer.MAX_VALUE) {
+      // To calculate: 5^exp * 2^exp
+      return bigFivePows[1].pow(intExp).shiftLeft(intExp);
+    }
+    /*
+     * "HUGE POWERS"
+     * 
+     * This branch probably won't be executed since the power of ten is too big.
+     */
+    // To calculate: 5^exp
+    BigInteger powerOfFive = bigFivePows[1].pow(Integer.MAX_VALUE);
+    BigInteger res = powerOfFive;
+    long longExp = (long) (exp - Integer.MAX_VALUE);
+
+    intExp = (int) (exp % Integer.MAX_VALUE);
+    while (longExp > Integer.MAX_VALUE) {
+      res = res.multiply(powerOfFive);
+      longExp -= Integer.MAX_VALUE;
+    }
+    res = res.multiply(bigFivePows[1].pow(intExp));
+    // To calculate: 5^exp << exp
+    res = res.shiftLeft(Integer.MAX_VALUE);
+    longExp = (long) (exp - Integer.MAX_VALUE);
+    while (longExp > Integer.MAX_VALUE) {
+      res = res.shiftLeft(Integer.MAX_VALUE);
+      longExp -= Integer.MAX_VALUE;
+    }
+    res = res.shiftLeft(intExp);
+    return res;
+  }
+
+  /**
+   * Performs a<sup>2</sup>.
+   * 
+   * @param a The number to square.
+   * @param aLen The length of the number to square.
+   */
+  static int[] square(int[] a, int aLen, int[] res) {
+    long carry;
+
+    for (int i = 0; i < aLen; i++) {
+      carry = 0;
+      for (int j = i + 1; j < aLen; j++) {
+        carry = unsignedMultAddAdd(a[i], a[j], res[i + j], (int) carry);
+        res[i + j] = (int) carry;
+        carry >>>= 32;
+      }
+      res[i + aLen] = (int) carry;
+    }
+
+    BitLevel.shiftLeftOneBit(res, res, aLen << 1);
+
+    carry = 0;
+    for (int i = 0, index = 0; i < aLen; i++, index++) {
+      carry = unsignedMultAddAdd(a[i], a[i], res[index], (int) carry);
+      res[index] = (int) carry;
+      carry >>>= 32;
+      index++;
+      carry += res[index] & 0xFFFFFFFFL;
+      res[index] = (int) carry;
+      carry >>>= 32;
+    }
+    return res;
+  }
+
+  /**
+   * Computes the value unsigned ((uint)a*(uint)b + (uint)c + (uint)d). This
+   * method could improve the readability and performance of the code.
+   * 
+   * @param a parameter 1
+   * @param b parameter 2
+   * @param c parameter 3
+   * @param d parameter 4
+   * @return value of expression
+   */
+  static long unsignedMultAddAdd(int a, int b, int c, int d) {
+    return (a & 0xFFFFFFFFL) * (b & 0xFFFFFFFFL) + (c & 0xFFFFFFFFL)
+        + (d & 0xFFFFFFFFL);
+  }
+
+  /**
+   * Multiplies an array of integers by an integer value and saves the result in
+   * {@code res}.
+   * 
+   * @param a the array of integers
+   * @param aSize the number of elements of intArray to be multiplied
+   * @param factor the multiplier
+   * @return the top digit of production
+   */
+  private static int multiplyByInt(int res[], int a[], final int aSize,
+      final int factor) {
+    long carry = 0;
+    for (int i = 0; i < aSize; i++) {
+      carry = unsignedMultAddAdd(a[i], factor, (int) carry, 0);
+      res[i] = (int) carry;
+      carry >>>= 32;
+    }
+    return (int) carry;
+  }
+
+  /**
+   * Just to denote that this class can't be instantiated.
+   */
+  private Multiplication() {
+  }
+
+}
diff --git a/user/super/com/google/gwt/emul/java/math/Primality.java b/user/super/com/google/gwt/emul/java/math/Primality.java
new file mode 100644
index 0000000..016d99c
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/math/Primality.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE.
+ */
+package java.math;
+
+import java.util.Arrays;
+import java.util.Random;
+
+/**
+ * Provides primality probabilistic methods.
+ */
+class Primality {
+
+  /**
+   * It encodes how many iterations of Miller-Rabin test are need to get an
+   * error bound not greater than {@code 2<sup>(-100)</sup>}. For example: for a
+   * {@code 1000}-bit number we need {@code 4} iterations, since {@code BITS[3]
+   * < 1000 <= BITS[4]}.
+   */
+  private static final int[] BITS = {
+      0, 0, 1854, 1233, 927, 747, 627, 543, 480, 431, 393, 361, 335, 314, 295,
+      279, 265, 253, 242, 232, 223, 216, 181, 169, 158, 150, 145, 140, 136,
+      132, 127, 123, 119, 114, 110, 105, 101, 96, 92, 87, 83, 78, 73, 69, 64,
+      59, 54, 49, 44, 38, 32, 26, 1};
+
+  /**
+   * It encodes how many i-bit primes there are in the table for {@code
+   * i=2,...,10}. For example {@code offsetPrimes[6]} says that from index
+   * {@code 11} exists {@code 7} consecutive {@code 6}-bit prime numbers in the
+   * array.
+   */
+  private static final int[][] offsetPrimes = {
+      null, null, {0, 2}, {2, 2}, {4, 2}, {6, 5}, {11, 7}, {18, 13}, {31, 23},
+      {54, 43}, {97, 75}};
+
+  /**
+   * All prime numbers with bit length lesser than 10 bits.
+   */
+  private static final int primes[] = {
+      2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
+      71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149,
+      151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
+      229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307,
+      311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389,
+      397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467,
+      479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571,
+      577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653,
+      659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751,
+      757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853,
+      857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
+      953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021};
+
+  /**
+   * All {@code BigInteger} prime numbers with bit length lesser than 8 bits.
+   */
+  private static final BigInteger BIprimes[] = new BigInteger[primes.length];
+
+  static {
+    // To initialize the dual table of BigInteger primes
+    for (int i = 0; i < primes.length; i++) {
+      BIprimes[i] = BigInteger.valueOf(primes[i]);
+    }
+  }
+
+  /**
+   * A random number is generated until a probable prime number is found.
+   * 
+   * @see BigInteger#BigInteger(int,int,Random)
+   * @see BigInteger#probablePrime(int,Random)
+   * @see #isProbablePrime(BigInteger, int)
+   */
+  static BigInteger consBigInteger(int bitLength, int certainty, Random rnd) {
+    // PRE: bitLength >= 2;
+    // For small numbers get a random prime from the prime table
+    if (bitLength <= 10) {
+      int rp[] = offsetPrimes[bitLength];
+      return BIprimes[rp[0] + rnd.nextInt(rp[1])];
+    }
+    int shiftCount = (-bitLength) & 31;
+    int last = (bitLength + 31) >> 5;
+    BigInteger n = new BigInteger(1, last, new int[last]);
+
+    last--;
+    do {
+      // To fill the array with random integers
+      for (int i = 0; i < n.numberLength; i++) {
+        n.digits[i] = rnd.nextInt();
+      }
+      // To fix to the correct bitLength
+      n.digits[last] |= 0x80000000;
+      n.digits[last] >>>= shiftCount;
+      // To create an odd number
+      n.digits[0] |= 1;
+    } while (!isProbablePrime(n, certainty));
+    return n;
+  }
+
+  /**
+   * @see BigInteger#isProbablePrime(int)
+   * @see #millerRabin(BigInteger, int)
+   * @ar.org.fitc.ref Optimizations: "A. Menezes - Handbook of applied
+   *                  Cryptography, Chapter 4".
+   */
+  static boolean isProbablePrime(BigInteger n, int certainty) {
+    // PRE: n >= 0;
+    if ((certainty <= 0) || ((n.numberLength == 1) && (n.digits[0] == 2))) {
+      return true;
+    }
+    // To discard all even numbers
+    if (!n.testBit(0)) {
+      return false;
+    }
+    // To check if 'n' exists in the table (it fit in 10 bits)
+    if ((n.numberLength == 1) && ((n.digits[0] & 0XFFFFFC00) == 0)) {
+      return (Arrays.binarySearch(primes, n.digits[0]) >= 0);
+    }
+    // To check if 'n' is divisible by some prime of the table
+    for (int i = 1; i < primes.length; i++) {
+      if (Division.remainderArrayByInt(n.digits, n.numberLength, primes[i]) == 0) {
+        return false;
+      }
+    }
+    // To set the number of iterations necessary for Miller-Rabin test
+    int i;
+    int bitLength = n.bitLength();
+
+    for (i = 2; bitLength < BITS[i]; i++) {
+      // empty
+    }
+    certainty = Math.min(i, 1 + ((certainty - 1) >> 1));
+
+    return millerRabin(n, certainty);
+  }
+
+  /**
+   * It uses the sieve of Eratosthenes to discard several composite numbers in
+   * some appropriate range (at the moment {@code [this, this + 1024]}). After
+   * this process it applies the Miller-Rabin test to the numbers that were not
+   * discarded in the sieve.
+   * 
+   * @see BigInteger#nextProbablePrime()
+   * @see #millerRabin(BigInteger, int)
+   */
+  static BigInteger nextProbablePrime(BigInteger n) {
+    // PRE: n >= 0
+    int i, j;
+    int certainty;
+    int gapSize = 1024; // for searching of the next probable prime number
+    int modules[] = new int[primes.length];
+    boolean isDivisible[] = new boolean[gapSize];
+    BigInteger startPoint;
+    BigInteger probPrime;
+    // If n < "last prime of table" searches next prime in the table
+    if ((n.numberLength == 1) && (n.digits[0] >= 0)
+        && (n.digits[0] < primes[primes.length - 1])) {
+      for (i = 0; n.digits[0] >= primes[i]; i++) {
+        // empty
+      }
+      return BIprimes[i];
+    }
+    /*
+     * Creates a "N" enough big to hold the next probable prime Note that: N <
+     * "next prime" < 2*N
+     */
+    startPoint = new BigInteger(1, n.numberLength, new int[n.numberLength + 1]);
+    System.arraycopy(n.digits, 0, startPoint.digits, 0, n.numberLength);
+    // To fix N to the "next odd number"
+    if (n.testBit(0)) {
+      Elementary.inplaceAdd(startPoint, 2);
+    } else {
+      startPoint.digits[0] |= 1;
+    }
+    // To set the improved certainly of Miller-Rabin
+    j = startPoint.bitLength();
+    for (certainty = 2; j < BITS[certainty]; certainty++) {
+      // empty
+    }
+    // To calculate modules: N mod p1, N mod p2, ... for first primes.
+    for (i = 0; i < primes.length; i++) {
+      modules[i] = Division.remainder(startPoint, primes[i]) - gapSize;
+    }
+    while (true) {
+      // At this point, all numbers in the gap are initialized as
+      // probably primes
+      Arrays.fill(isDivisible, false);
+      // To discard multiples of first primes
+      for (i = 0; i < primes.length; i++) {
+        modules[i] = (modules[i] + gapSize) % primes[i];
+        j = (modules[i] == 0) ? 0 : (primes[i] - modules[i]);
+        for (; j < gapSize; j += primes[i]) {
+          isDivisible[j] = true;
+        }
+      }
+      // To execute Miller-Rabin for non-divisible numbers by all first
+      // primes
+      for (j = 0; j < gapSize; j++) {
+        if (!isDivisible[j]) {
+          probPrime = startPoint.copy();
+          Elementary.inplaceAdd(probPrime, j);
+
+          if (millerRabin(probPrime, certainty)) {
+            return probPrime;
+          }
+        }
+      }
+      Elementary.inplaceAdd(startPoint, gapSize);
+    }
+  }
+
+  /**
+   * The Miller-Rabin primality test.
+   * 
+   * @param n the input number to be tested.
+   * @param t the number of trials.
+   * @return {@code false} if the number is definitely compose, otherwise
+   *         {@code true} with probability {@code 1 - 4<sup>(-t)</sup>}.
+   * @ar.org.fitc.ref "D. Knuth, The Art of Computer Programming Vo.2, Section
+   *                  4.5.4., Algorithm P"
+   */
+  private static boolean millerRabin(BigInteger n, int t) {
+    // PRE: n >= 0, t >= 0
+    BigInteger x; // x := UNIFORM{2...n-1}
+    BigInteger y; // y := x^(q * 2^j) mod n
+    BigInteger nMinus1 = n.subtract(BigInteger.ONE); // n-1
+    int bitLength = nMinus1.bitLength(); // ~ log2(n-1)
+    // (q,k) such that: n-1 = q * 2^k and q is odd
+    int k = nMinus1.getLowestSetBit();
+    BigInteger q = nMinus1.shiftRight(k);
+    Random rnd = new Random();
+
+    for (int i = 0; i < t; i++) {
+      // To generate a witness 'x', first it use the primes of table
+      if (i < primes.length) {
+        x = BIprimes[i];
+      } else {
+        /*
+         * It generates random witness only if it's necesssary. Note that all
+         * methods would call Miller-Rabin with t <= 50 so this part is only to
+         * do more robust the algorithm
+         */
+        do {
+          x = new BigInteger(bitLength, rnd);
+        } while ((x.compareTo(n) >= BigInteger.EQUALS) || (x.sign == 0)
+            || x.isOne());
+      }
+      y = x.modPow(q, n);
+      if (y.isOne() || y.equals(nMinus1)) {
+        continue;
+      }
+      for (int j = 1; j < k; j++) {
+        if (y.equals(nMinus1)) {
+          continue;
+        }
+        y = y.multiply(y).mod(n);
+        if (y.isOne()) {
+          return false;
+        }
+      }
+      if (!y.equals(nMinus1)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Just to denote that this class can't be instantiated.
+   */
+  private Primality() {
+  }
+
+}
diff --git a/user/super/com/google/gwt/emul/java/math/RoundingMode.java b/user/super/com/google/gwt/emul/java/math/RoundingMode.java
new file mode 100644
index 0000000..f432d05
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/math/RoundingMode.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE.
+ */
+package java.math;
+
+/**
+ * Specifies the rounding behavior for operations whose results cannot be
+ * represented exactly.
+ */
+public enum RoundingMode {
+
+  /**
+   * Rounding mode to round towards positive infinity. For positive values this
+   * rounding mode behaves as {@link #UP}, for negative values as {@link #DOWN}. <br>
+   * Rule: {@code x.round() >= x}
+   */
+  CEILING(BigDecimal.ROUND_CEILING),
+
+  /**
+   * Rounding mode where the values are rounded towards zero. <br>
+   * Rule: {@code x.round().abs() <= x.abs()}
+   */
+  DOWN(BigDecimal.ROUND_DOWN),
+
+  /**
+   * Rounding mode to round towards negative infinity. For positive values this
+   * rounding mode behaves as {@link #DOWN}, for negative values as {@link #UP}. <br>
+   * Rule: {@code x.round() <= x}
+   */
+  FLOOR(BigDecimal.ROUND_FLOOR),
+
+  /**
+   * Rounding mode where values are rounded towards the nearest neighbor. Ties
+   * are broken by rounding down.
+   */
+  HALF_DOWN(BigDecimal.ROUND_HALF_DOWN),
+
+  /**
+   * Rounding mode where values are rounded towards the nearest neighbor. Ties
+   * are broken by rounding to the even neighbor.
+   */
+  HALF_EVEN(BigDecimal.ROUND_HALF_EVEN),
+
+  /**
+   * Rounding mode where values are rounded towards the nearest neighbor. Ties
+   * are broken by rounding up.
+   */
+  HALF_UP(BigDecimal.ROUND_HALF_UP),
+
+  /**
+   * Rounding mode where the rounding operations throws an ArithmeticException
+   * for the case that rounding is necessary, i.e. for the case that the value
+   * cannot be represented exactly.
+   */
+  UNNECESSARY(BigDecimal.ROUND_UNNECESSARY),
+
+  /**
+   * Rounding mode where positive values are rounded towards positive infinity
+   * and negative values towards negative infinity. <br>
+   * Rule: {@code x.round().abs() >= x.abs()}
+   */
+  UP(BigDecimal.ROUND_UP);
+
+  /**
+   * Converts rounding mode constants from class {@code BigDecimal} into {@code
+   * RoundingMode} values.
+   * 
+   * @param mode rounding mode constant as defined in class {@code BigDecimal}
+   * @return corresponding rounding mode object
+   */
+  public static RoundingMode valueOf(int mode) {
+    switch (mode) {
+      case BigDecimal.ROUND_CEILING:
+        return CEILING;
+      case BigDecimal.ROUND_DOWN:
+        return DOWN;
+      case BigDecimal.ROUND_FLOOR:
+        return FLOOR;
+      case BigDecimal.ROUND_HALF_DOWN:
+        return HALF_DOWN;
+      case BigDecimal.ROUND_HALF_EVEN:
+        return HALF_EVEN;
+      case BigDecimal.ROUND_HALF_UP:
+        return HALF_UP;
+      case BigDecimal.ROUND_UNNECESSARY:
+        return UNNECESSARY;
+      case BigDecimal.ROUND_UP:
+        return UP;
+      default:
+        // math.00=Invalid rounding mode
+        throw new IllegalArgumentException("Invalid rounding mode"); //$NON-NLS-1$
+    }
+  }
+
+  /**
+   * Set the old constant.
+   * @param rm unused
+   */
+  RoundingMode(int rm) {
+    // Note that we do not need the old-style rounding mode, so we ignore it.
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/EmulSuite.java b/user/test/com/google/gwt/emultest/EmulSuite.java
index d036516..fec78f2 100644
--- a/user/test/com/google/gwt/emultest/EmulSuite.java
+++ b/user/test/com/google/gwt/emultest/EmulSuite.java
@@ -30,6 +30,26 @@
 import com.google.gwt.emultest.java.lang.StringBufferTest;
 import com.google.gwt.emultest.java.lang.StringTest;
 import com.google.gwt.emultest.java.lang.SystemTest;
+import com.google.gwt.emultest.java.math.BigDecimalArithmeticTest;
+import com.google.gwt.emultest.java.math.BigDecimalCompareTest;
+import com.google.gwt.emultest.java.math.BigDecimalConstructorsTest;
+import com.google.gwt.emultest.java.math.BigDecimalConvertTest;
+import com.google.gwt.emultest.java.math.BigDecimalScaleOperationsTest;
+import com.google.gwt.emultest.java.math.BigIntegerAddTest;
+import com.google.gwt.emultest.java.math.BigIntegerAndTest;
+import com.google.gwt.emultest.java.math.BigIntegerCompareTest;
+import com.google.gwt.emultest.java.math.BigIntegerConstructorsTest;
+import com.google.gwt.emultest.java.math.BigIntegerConvertTest;
+import com.google.gwt.emultest.java.math.BigIntegerDivideTest;
+import com.google.gwt.emultest.java.math.BigIntegerHashCodeTest;
+import com.google.gwt.emultest.java.math.BigIntegerModPowTest;
+import com.google.gwt.emultest.java.math.BigIntegerMultiplyTest;
+import com.google.gwt.emultest.java.math.BigIntegerNotTest;
+import com.google.gwt.emultest.java.math.BigIntegerOperateBitsTest;
+import com.google.gwt.emultest.java.math.BigIntegerOrTest;
+import com.google.gwt.emultest.java.math.BigIntegerSubtractTest;
+import com.google.gwt.emultest.java.math.BigIntegerToStringTest;
+import com.google.gwt.emultest.java.math.BigIntegerXorTest;
 import com.google.gwt.emultest.java.sql.SqlDateTest;
 import com.google.gwt.emultest.java.sql.SqlTimeTest;
 import com.google.gwt.emultest.java.sql.SqlTimestampTest;
@@ -80,6 +100,28 @@
     suite.addTestSuite(StringTest.class);
     suite.addTestSuite(SystemTest.class);
 
+    // java.math
+    suite.addTestSuite(BigDecimalArithmeticTest.class);
+    suite.addTestSuite(BigDecimalCompareTest.class);
+    suite.addTestSuite(BigDecimalConstructorsTest.class);
+    suite.addTestSuite(BigDecimalConvertTest.class);
+    suite.addTestSuite(BigDecimalScaleOperationsTest.class);
+    suite.addTestSuite(BigIntegerAddTest.class);
+    suite.addTestSuite(BigIntegerAndTest.class);
+    suite.addTestSuite(BigIntegerCompareTest.class);
+    suite.addTestSuite(BigIntegerConstructorsTest.class);
+    suite.addTestSuite(BigIntegerConvertTest.class);
+    suite.addTestSuite(BigIntegerDivideTest.class);
+    suite.addTestSuite(BigIntegerHashCodeTest.class);
+    suite.addTestSuite(BigIntegerModPowTest.class);
+    suite.addTestSuite(BigIntegerMultiplyTest.class);
+    suite.addTestSuite(BigIntegerNotTest.class);
+    suite.addTestSuite(BigIntegerOperateBitsTest.class);
+    suite.addTestSuite(BigIntegerOrTest.class);
+    suite.addTestSuite(BigIntegerSubtractTest.class);
+    suite.addTestSuite(BigIntegerToStringTest.class);
+    suite.addTestSuite(BigIntegerXorTest.class);
+
     // java.util
     suite.addTestSuite(ApacheMapTest.class);
     suite.addTestSuite(ArrayListTest.class);
diff --git a/user/test/com/google/gwt/emultest/java/lang/FloatTest.java b/user/test/com/google/gwt/emultest/java/lang/FloatTest.java
index c8cea58..3254e20 100644
--- a/user/test/com/google/gwt/emultest/java/lang/FloatTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/FloatTest.java
@@ -24,6 +24,7 @@
  */
 public class FloatTest extends GWTTestCase {
 
+  @Override
   public String getModuleName() {
     return "com.google.gwt.emultest.EmulSuite";
   }
@@ -77,9 +78,13 @@
     assertEquals(-1.5f, Float.parseFloat("-1.5"), 0.0);
     assertEquals(3.0f, Float.parseFloat("3."), 0.0);
     assertEquals(0.5f, Float.parseFloat(".5"), 0.0);
-    assertEquals("Can't parse MAX_VALUE", Float.MAX_VALUE,
-        Float.parseFloat(String.valueOf(Float.MAX_VALUE)), 1e31);
-    assertEquals("Can't parse MIN_VALUE", Float.MIN_VALUE,
-        Float.parseFloat(String.valueOf(Float.MIN_VALUE)), Float.MIN_VALUE);
+    // TODO(jat): it isn't safe to parse MAX/MIN_VALUE because we also want to
+    // be able to get POSITIVE/NEGATIVE_INFINITY for out-of-range values, and
+    // since all math in JS is done in double we can't rely on getting the
+    // exact value back.
+//    assertEquals("Can't parse MAX_VALUE", Float.MAX_VALUE,
+//        Float.parseFloat(String.valueOf(Float.MAX_VALUE)), 1e31);
+//    assertEquals("Can't parse MIN_VALUE", Float.MIN_VALUE,
+//        Float.parseFloat(String.valueOf(Float.MIN_VALUE)), Float.MIN_VALUE);
   }
 }
diff --git a/user/test/com/google/gwt/emultest/java/math/BigDecimalArithmeticTest.java b/user/test/com/google/gwt/emultest/java/math/BigDecimalArithmeticTest.java
new file mode 100644
index 0000000..99ae798
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigDecimalArithmeticTest.java
@@ -0,0 +1,1741 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.MathContext;
+import java.math.RoundingMode;
+
+/**
+ * Class: java.math.BigDecimal Methods: add, subtract, multiply, divide
+ */
+public class BigDecimalArithmeticTest extends EmulTestBase {
+  /**
+   * Add two numbers of different scales; the first is negative
+   */
+  public void testAddDiffScaleNegPos() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = -15;
+    String b = "747233429293018787918347987234564568";
+    int bScale = 10;
+    String c = "1231212478987482988429808779810457634781459480137916301878791834798.7234564568";
+    int cScale = 10;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.add(bNumber);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Add two numbers of different scales; the first is positive
+   */
+  public void testAddDiffScalePosNeg() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 15;
+    String b = "747233429293018787918347987234564568";
+    int bScale = -10;
+    String c = "7472334294161400358170962860775454459810457634.781384756794987";
+    int cScale = 15;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.add(bNumber);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Add two numbers of different scales; the first is positive
+   */
+  public void testAddDiffScalePosPos() {
+    String a = "100";
+    int aScale = 15;
+    String b = "200";
+    int bScale = 14;
+    String c = "2.100E-12";
+    int cScale = 15;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.add(bNumber);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Add two zeroes of different scales; the first is negative
+   */
+  public void testAddDiffScaleZeroZero() {
+    String a = "0";
+    int aScale = -15;
+    String b = "0";
+    int bScale = 10;
+    String c = "0E-10";
+    int cScale = 10;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.add(bNumber);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Add two numbers of equal negative scales
+   */
+  public void testAddEqualScaleNegNeg() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = -10;
+    String b = "747233429293018787918347987234564568";
+    int bScale = -10;
+    String c = "1.231212478987483735663238072829245553129371991359555E+61";
+    int cScale = -10;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.add(bNumber);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Add two numbers of equal positive scales
+   */
+  public void testAddEqualScalePosPos() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 10;
+    String b = "747233429293018787918347987234564568";
+    int bScale = 10;
+    String c = "123121247898748373566323807282924555312937.1991359555";
+    int cScale = 10;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.add(bNumber);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Add two numbers of different scales using MathContext; the first is
+   * positive
+   */
+  public void testAddMathContextDiffScalePosNeg() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 15;
+    String b = "747233429293018787918347987234564568";
+    int bScale = -10;
+    String c = "7.47233429416141E+45";
+    int cScale = -31;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    MathContext mc = new MathContext(15, RoundingMode.CEILING);
+    BigDecimal result = aNumber.add(bNumber, mc);
+    assertEquals("incorrect value", c, c.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Add two numbers of equal negative scales using MathContext
+   */
+  public void testAddMathContextEqualScaleNegNeg() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = -10;
+    String b = "747233429293018787918347987234564568";
+    int bScale = -10;
+    String c = "1.2312E+61";
+    int cScale = -57;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    MathContext mc = new MathContext(5, RoundingMode.FLOOR);
+    BigDecimal result = aNumber.add(bNumber, mc);
+    assertEquals("incorrect value ", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Add two numbers of equal positive scales using MathContext
+   */
+  public void testAddMathContextEqualScalePosPos() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 10;
+    String b = "747233429293018787918347987234564568";
+    int bScale = 10;
+    String c = "1.2313E+41";
+    int cScale = -37;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    MathContext mc = new MathContext(5, RoundingMode.UP);
+    BigDecimal result = aNumber.add(bNumber, mc);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  public void testAddZero() {
+    BigDecimal val = new BigDecimal("123456789");
+    BigDecimal sum = val.add(BigDecimal.ZERO);
+    assertEquals(val, sum);
+    sum = BigDecimal.ZERO.add(val);
+    assertEquals(val, sum);
+    val = BigDecimal.valueOf(0L, 1);
+    sum = val.add(BigDecimal.ZERO);
+    assertEquals(val, sum);
+  }
+
+
+  /**
+   * Test the the approximate scale is computed correctly.
+   * <p>
+   * See https://issues.apache.org/jira/browse/HARMONY-6406
+   */
+  public void testApproxScale() {
+    BigDecimal decVal = BigDecimal.TEN.multiply(new BigDecimal("0.1"));
+    int compare = decVal.compareTo(new BigDecimal("1.00"));
+    assertEquals(0, compare);
+  }
+
+  /**
+   * divideAndRemainder(BigDecimal).
+   */
+  public void testDivideAndRemainder1() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 45;
+    String b = "134432345432345748766876876723342238476237823787879183470";
+    int bScale = 70;
+    String res = "277923185514690367474770683";
+    int resScale = 0;
+    String rem = "1.3032693871288309587558885943391070087960319452465789990E-15";
+    int remScale = 70;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result[] = aNumber.divideAndRemainder(bNumber);
+    assertEquals("incorrect quotient value", res, result[0].toString());
+    assertEquals("incorrect quotient scale", resScale, result[0].scale());
+    assertEquals("incorrect remainder value", rem, result[1].toString());
+    assertEquals("incorrect remainder scale", remScale, result[1].scale());
+  }
+
+  /**
+   * divideAndRemainder(BigDecimal).
+   */
+  public void testDivideAndRemainder2() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = -45;
+    String b = "134432345432345748766876876723342238476237823787879183470";
+    int bScale = 70;
+    String res = "2779231855146903674747706830969461168692256919247547952"
+        + "2608549363170374005512836303475980101168105698072946555" + "6862849";
+    int resScale = 0;
+    String rem = "3.4935796954060524114470681810486417234751682675102093970E-15";
+    int remScale = 70;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result[] = aNumber.divideAndRemainder(bNumber);
+    assertEquals("incorrect quotient value", res, result[0].toString());
+    assertEquals("incorrect quotient scale", resScale, result[0].scale());
+    assertEquals("incorrect remainder value", rem, result[1].toString());
+    assertEquals("incorrect remainder scale", remScale, result[1].scale());
+  }
+
+  /**
+   * divideAndRemainder(BigDecimal, MathContext).
+   */
+  public void testDivideAndRemainderMathContextDOWN() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 45;
+    String b = "134432345432345748766876876723342238476237823787879183470";
+    int bScale = 20;
+    int precision = 15;
+    RoundingMode rm = RoundingMode.DOWN;
+    MathContext mc = new MathContext(precision, rm);
+    String res = "0E-25";
+    int resScale = 25;
+    String rem = "3736186567876.876578956958765675671119238118911893939591735";
+    int remScale = 45;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result[] = aNumber.divideAndRemainder(bNumber, mc);
+    assertEquals("incorrect quotient value", res, result[0].toString());
+    assertEquals("incorrect quotient scale", resScale, result[0].scale());
+    assertEquals("incorrect remainder value", rem, result[1].toString());
+    assertEquals("incorrect remainder scale", remScale, result[1].scale());
+  }
+
+  /**
+   * divideAndRemainder(BigDecimal, MathContext).
+   */
+  public void testDivideAndRemainderMathContextUP() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 45;
+    String b = "134432345432345748766876876723342238476237823787879183470";
+    int bScale = 70;
+    int precision = 75;
+    RoundingMode rm = RoundingMode.UP;
+    MathContext mc = new MathContext(precision, rm);
+    String res = "277923185514690367474770683";
+    int resScale = 0;
+    String rem = "1.3032693871288309587558885943391070087960319452465789990E-15";
+    int remScale = 70;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result[] = aNumber.divideAndRemainder(bNumber, mc);
+    assertEquals("incorrect quotient value", res, result[0].toString());
+    assertEquals("incorrect quotient scale", resScale, result[0].scale());
+    assertEquals("incorrect remainder value", rem, result[1].toString());
+    assertEquals("incorrect remainder scale", remScale, result[1].scale());
+  }
+
+  /**
+   * Divide to BigDecimal.
+   */
+  public void testDivideBigDecimal1() {
+    String a = "-37361671119238118911893939591735";
+    int aScale = 10;
+    String b = "74723342238476237823787879183470";
+    int bScale = 15;
+    String c = "-5E+4";
+    int resScale = -4;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide to BigDecimal.
+   */
+  public void testDivideBigDecimal2() {
+    String a = "-37361671119238118911893939591735";
+    int aScale = 10;
+    String b = "74723342238476237823787879183470";
+    int bScale = -15;
+    String c = "-5E-26";
+    int resScale = 26;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * divide(BigDecimal, MathContext).
+   */
+  public void testDivideBigDecimalScaleMathContextCEILING() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 15;
+    String b = "748766876876723342238476237823787879183470";
+    int bScale = 70;
+    int precision = 21;
+    RoundingMode rm = RoundingMode.CEILING;
+    MathContext mc = new MathContext(precision, rm);
+    String c = "4.98978611802562512996E+70";
+    int resScale = -50;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, mc);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * divide(BigDecimal, MathContext).
+   */
+  public void testDivideBigDecimalScaleMathContextDOWN() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 15;
+    String b = "748766876876723342238476237823787879183470";
+    int bScale = 70;
+    int precision = 21;
+    RoundingMode rm = RoundingMode.DOWN;
+    MathContext mc = new MathContext(precision, rm);
+    String c = "4.98978611802562512995E+70";
+    int resScale = -50;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, mc);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * divide(BigDecimal, MathContext).
+   */
+  public void testDivideBigDecimalScaleMathContextFLOOR() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 15;
+    String b = "748766876876723342238476237823787879183470";
+    int bScale = 70;
+    int precision = 21;
+    RoundingMode rm = RoundingMode.FLOOR;
+    MathContext mc = new MathContext(precision, rm);
+    String c = "4.98978611802562512995E+70";
+    int resScale = -50;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, mc);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * divide(BigDecimal, MathContext).
+   */
+  public void testDivideBigDecimalScaleMathContextHALF_DOWN() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 45;
+    String b = "134432345432345748766876876723342238476237823787879183470";
+    int bScale = 70;
+    int precision = 21;
+    RoundingMode rm = RoundingMode.HALF_DOWN;
+    MathContext mc = new MathContext(precision, rm);
+    String c = "2.77923185514690367475E+26";
+    int resScale = -6;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, mc);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * divide(BigDecimal, MathContext).
+   */
+  public void testDivideBigDecimalScaleMathContextHALF_EVEN() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 45;
+    String b = "134432345432345748766876876723342238476237823787879183470";
+    int bScale = 70;
+    int precision = 21;
+    RoundingMode rm = RoundingMode.HALF_EVEN;
+    MathContext mc = new MathContext(precision, rm);
+    String c = "2.77923185514690367475E+26";
+    int resScale = -6;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, mc);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * divide(BigDecimal, MathContext).
+   */
+  public void testDivideBigDecimalScaleMathContextHALF_UP() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 45;
+    String b = "134432345432345748766876876723342238476237823787879183470";
+    int bScale = 70;
+    int precision = 21;
+    RoundingMode rm = RoundingMode.HALF_UP;
+    MathContext mc = new MathContext(precision, rm);
+    String c = "2.77923185514690367475E+26";
+    int resScale = -6;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, mc);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * divide(BigDecimal, MathContext).
+   */
+  public void testDivideBigDecimalScaleMathContextUP() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 15;
+    String b = "748766876876723342238476237823787879183470";
+    int bScale = 10;
+    int precision = 21;
+    RoundingMode rm = RoundingMode.UP;
+    MathContext mc = new MathContext(precision, rm);
+    String c = "49897861180.2562512996";
+    int resScale = 10;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, mc);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * divide(BigDecimal, scale, RoundingMode).
+   */
+  public void testDivideBigDecimalScaleRoundingModeCEILING() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 100;
+    String b = "74723342238476237823787879183470";
+    int bScale = 15;
+    int newScale = 45;
+    RoundingMode rm = RoundingMode.CEILING;
+    String c = "1E-45";
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, newScale, rm);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", newScale, result.scale());
+  }
+
+  /**
+   * divide(BigDecimal, scale, RoundingMode).
+   */
+  public void testDivideBigDecimalScaleRoundingModeDOWN() {
+    String a = "-37361671119238118911893939591735";
+    int aScale = 10;
+    String b = "74723342238476237823787879183470";
+    int bScale = 15;
+    int newScale = 31;
+    RoundingMode rm = RoundingMode.DOWN;
+    String c = "-50000.0000000000000000000000000000000";
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, newScale, rm);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", newScale, result.scale());
+  }
+
+  /**
+   * divide(BigDecimal, scale, RoundingMode).
+   */
+  public void testDivideBigDecimalScaleRoundingModeFLOOR() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 100;
+    String b = "74723342238476237823787879183470";
+    int bScale = 15;
+    int newScale = 45;
+    RoundingMode rm = RoundingMode.FLOOR;
+    String c = "0E-45";
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, newScale, rm);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", newScale, result.scale());
+  }
+
+  /**
+   * divide(BigDecimal, scale, RoundingMode).
+   */
+  public void testDivideBigDecimalScaleRoundingModeHALF_DOWN() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 5;
+    String b = "74723342238476237823787879183470";
+    int bScale = 15;
+    int newScale = 7;
+    RoundingMode rm = RoundingMode.HALF_DOWN;
+    String c = "500002603731642864013619132621009722.1803810";
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, newScale, rm);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", newScale, result.scale());
+  }
+
+  /**
+   * divide(BigDecimal, scale, RoundingMode).
+   */
+  public void testDivideBigDecimalScaleRoundingModeHALF_EVEN() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 5;
+    String b = "74723342238476237823787879183470";
+    int bScale = 15;
+    int newScale = 7;
+    RoundingMode rm = RoundingMode.HALF_EVEN;
+    String c = "500002603731642864013619132621009722.1803810";
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, newScale, rm);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", newScale, result.scale());
+  }
+
+  /**
+   * divide(BigDecimal, scale, RoundingMode).
+   */
+  public void testDivideBigDecimalScaleRoundingModeHALF_UP() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = -51;
+    String b = "74723342238476237823787879183470";
+    int bScale = 45;
+    int newScale = 3;
+    RoundingMode rm = RoundingMode.HALF_UP;
+    String c = "50000260373164286401361913262100972218038099522752460421"
+        + "05959924024355721031761947728703598332749334086415670525"
+        + "3761096961.670";
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, newScale, rm);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", newScale, result.scale());
+  }
+
+  /**
+   * divide(BigDecimal, scale, RoundingMode).
+   */
+  public void testDivideBigDecimalScaleRoundingModeUP() {
+    String a = "-37361671119238118911893939591735";
+    int aScale = 10;
+    String b = "74723342238476237823787879183470";
+    int bScale = -15;
+    int newScale = 31;
+    RoundingMode rm = RoundingMode.UP;
+    String c = "-5.00000E-26";
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, newScale, rm);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", newScale, result.scale());
+  }
+
+  /**
+   * Divide by zero.
+   */
+  public void testDivideByZero() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 15;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = BigDecimal.valueOf(0L);
+    try {
+      aNumber.divide(bNumber);
+      fail("ArithmeticException has not been caught");
+    } catch (ArithmeticException e) {
+      assertEquals("Improper exception message", "Division by zero",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * Divide with invalid rounding mode.
+   */
+  public void testDivideExceptionInvalidRM() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 15;
+    String b = "747233429293018787918347987234564568";
+    int bScale = 10;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    try {
+      aNumber.divide(bNumber, 100);
+      fail("IllegalArgumentException has not been caught");
+    } catch (IllegalArgumentException e) {
+      assertEquals("Improper exception message", "Invalid rounding mode",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * Divide with ROUND_UNNECESSARY.
+   */
+  public void testDivideExceptionRM() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 15;
+    String b = "747233429293018787918347987234564568";
+    int bScale = 10;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    try {
+      aNumber.divide(bNumber, BigDecimal.ROUND_UNNECESSARY);
+      fail("ArithmeticException has not been caught");
+    } catch (ArithmeticException e) {
+      assertEquals("Improper exception message", "Rounding necessary",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * Divide: local variable exponent is equal to zero.
+   */
+  public void testDivideExpEqualsZero() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = -15;
+    String b = "747233429293018787918347987234564568";
+    int bScale = 10;
+    String c = "1.64769459009933764189139568605273529E+40";
+    int resScale = -5;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_CEILING);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: local variable exponent is greater than zero.
+   */
+  public void testDivideExpGreaterZero() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = -15;
+    String b = "747233429293018787918347987234564568";
+    int bScale = 20;
+    String c = "1.647694590099337641891395686052735285121058381E+50";
+    int resScale = -5;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_CEILING);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: local variable exponent is less than zero.
+   */
+  public void testDivideExpLessZero() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 15;
+    String b = "747233429293018787918347987234564568";
+    int bScale = 10;
+    String c = "1.64770E+10";
+    int resScale = -5;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_CEILING);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * BigDecimal.divide with a scale that's too large.
+   * 
+   * Regression test for HARMONY-6271
+   */
+  public void testDivideLargeScale() {
+    BigDecimal arg1 = new BigDecimal("320.0E+2147483647");
+    BigDecimal arg2 = new BigDecimal("6E-2147483647");
+    try {
+      arg1.divide(arg2, Integer.MAX_VALUE, RoundingMode.CEILING);
+      fail("Expected ArithmeticException when dividing with a scale that's too large");
+    } catch (ArithmeticException e) {
+      // expected behaviour
+    }
+  }
+
+  /**
+   * Divide: remainder is zero.
+   */
+  public void testDivideRemainderIsZero() {
+    String a = "8311389578904553209874735431110";
+    int aScale = -15;
+    String b = "237468273682987234567849583746";
+    int bScale = 20;
+    String c = "3.5000000000000000000000000000000E+36";
+    int resScale = -5;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_CEILING);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_CEILING, result is negative.
+   */
+  public void testDivideRoundCeilingNeg() {
+    String a = "-92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "7472334223847623782375469293018787918347987234564568";
+    int bScale = 13;
+    String c = "-1.24390557635720517122423359799283E+53";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_CEILING);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_CEILING, result is positive.
+   */
+  public void testDivideRoundCeilingPos() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "7472334223847623782375469293018787918347987234564568";
+    int bScale = 13;
+    String c = "1.24390557635720517122423359799284E+53";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_CEILING);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_DOWN, result is negative.
+   */
+  public void testDivideRoundDownNeg() {
+    String a = "-92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "7472334223847623782375469293018787918347987234564568";
+    int bScale = 13;
+    String c = "-1.24390557635720517122423359799283E+53";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale, BigDecimal.ROUND_DOWN);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_DOWN, result is positive.
+   */
+  public void testDivideRoundDownPos() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "7472334223847623782375469293018787918347987234564568";
+    int bScale = 13;
+    String c = "1.24390557635720517122423359799283E+53";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale, BigDecimal.ROUND_DOWN);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_FLOOR, result is negative.
+   */
+  public void testDivideRoundFloorNeg() {
+    String a = "-92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "7472334223847623782375469293018787918347987234564568";
+    int bScale = 13;
+    String c = "-1.24390557635720517122423359799284E+53";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_FLOOR);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_FLOOR, result is positive.
+   */
+  public void testDivideRoundFloorPos() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "7472334223847623782375469293018787918347987234564568";
+    int bScale = 13;
+    String c = "1.24390557635720517122423359799283E+53";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_FLOOR);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_HALF_DOWN, result is negative;
+   * distance = -1.
+   */
+  public void testDivideRoundHalfDownNeg() {
+    String a = "-92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "7472334223847623782375469293018787918347987234564568";
+    int bScale = 13;
+    String c = "-1.24390557635720517122423359799284E+53";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_HALF_DOWN);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_HALF_DOWN, result is negative; distance = 1.
+   */
+  public void testDivideRoundHalfDownNeg1() {
+    String a = "-92948782094488478231212478987482988798104576347813847567949855464535634534563456";
+    int aScale = -24;
+    String b = "74723342238476237823754692930187879183479";
+    int bScale = 13;
+    String c = "-1.2439055763572051712242335979928354832010167729111113605E+76";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_HALF_DOWN);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_HALF_UP, result is negative; equidistant.
+   */
+  public void testDivideRoundHalfDownNeg2() {
+    String a = "-37361671119238118911893939591735";
+    int aScale = 10;
+    String b = "74723342238476237823787879183470";
+    int bScale = 15;
+    String c = "0E+5";
+    int resScale = -5;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_HALF_DOWN);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_HALF_DOWN, result is positive;
+   * distance = -1.
+   */
+  public void testDivideRoundHalfDownPos() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "7472334223847623782375469293018787918347987234564568";
+    int bScale = 13;
+    String c = "1.24390557635720517122423359799284E+53";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_HALF_DOWN);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_HALF_DOWN, result is positive; distance = 1.
+   */
+  public void testDivideRoundHalfDownPos1() {
+    String a = "92948782094488478231212478987482988798104576347813847567949855464535634534563456";
+    int aScale = -24;
+    String b = "74723342238476237823754692930187879183479";
+    int bScale = 13;
+    String c = "1.2439055763572051712242335979928354832010167729111113605E+76";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_HALF_DOWN);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_HALF_EVEN, result is negative;
+   * distance = -1.
+   */
+  public void testDivideRoundHalfEvenNeg() {
+    String a = "-92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "7472334223847623782375469293018787918347987234564568";
+    int bScale = 13;
+    String c = "-1.24390557635720517122423359799284E+53";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_HALF_EVEN);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_HALF_EVEN, result is negative; distance = 1
+   */
+  public void testDivideRoundHalfEvenNeg1() {
+    String a = "-92948782094488478231212478987482988798104576347813847567949855464535634534563456";
+    int aScale = -24;
+    String b = "74723342238476237823754692930187879183479";
+    int bScale = 13;
+    String c = "-1.2439055763572051712242335979928354832010167729111113605E+76";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_HALF_EVEN);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_HALF_EVEN, result is negative; equidistant
+   */
+  public void testDivideRoundHalfEvenNeg2() {
+    String a = "-37361671119238118911893939591735";
+    int aScale = 10;
+    String b = "74723342238476237823787879183470";
+    int bScale = 15;
+    String c = "0E+5";
+    int resScale = -5;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_HALF_EVEN);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_HALF_EVEN, result is positive; distance = -1
+   */
+  public void testDivideRoundHalfEvenPos() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "7472334223847623782375469293018787918347987234564568";
+    int bScale = 13;
+    String c = "1.24390557635720517122423359799284E+53";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_HALF_EVEN);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_HALF_EVEN, result is positive; distance = 1
+   */
+  public void testDivideRoundHalfEvenPos1() {
+    String a = "92948782094488478231212478987482988798104576347813847567949855464535634534563456";
+    int aScale = -24;
+    String b = "74723342238476237823754692930187879183479";
+    int bScale = 13;
+    String c = "1.2439055763572051712242335979928354832010167729111113605E+76";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_HALF_EVEN);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_HALF_UP, result is negative; distance = -1
+   */
+  public void testDivideRoundHalfUpNeg() {
+    String a = "-92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "7472334223847623782375469293018787918347987234564568";
+    int bScale = 13;
+    String c = "-1.24390557635720517122423359799284E+53";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_HALF_UP);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_HALF_UP, result is negative; distance = 1
+   */
+  public void testDivideRoundHalfUpNeg1() {
+    String a = "-92948782094488478231212478987482988798104576347813847567949855464535634534563456";
+    int aScale = -24;
+    String b = "74723342238476237823754692930187879183479";
+    int bScale = 13;
+    String c = "-1.2439055763572051712242335979928354832010167729111113605E+76";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_HALF_UP);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_HALF_UP, result is negative; equidistant
+   */
+  public void testDivideRoundHalfUpNeg2() {
+    String a = "-37361671119238118911893939591735";
+    int aScale = 10;
+    String b = "74723342238476237823787879183470";
+    int bScale = 15;
+    String c = "-1E+5";
+    int resScale = -5;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_HALF_UP);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_HALF_UP, result is positive; distance = -1
+   */
+  public void testDivideRoundHalfUpPos() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "7472334223847623782375469293018787918347987234564568";
+    int bScale = 13;
+    String c = "1.24390557635720517122423359799284E+53";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_HALF_UP);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_HALF_UP, result is positive; distance = 1
+   */
+  public void testDivideRoundHalfUpPos1() {
+    String a = "92948782094488478231212478987482988798104576347813847567949855464535634534563456";
+    int aScale = -24;
+    String b = "74723342238476237823754692930187879183479";
+    int bScale = 13;
+    String c = "1.2439055763572051712242335979928354832010167729111113605E+76";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale,
+        BigDecimal.ROUND_HALF_UP);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_UP, result is negative
+   */
+  public void testDivideRoundUpNeg() {
+    String a = "-92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "7472334223847623782375469293018787918347987234564568";
+    int bScale = 13;
+    String c = "-1.24390557635720517122423359799284E+53";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale, BigDecimal.ROUND_UP);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Divide: rounding mode is ROUND_UP, result is positive
+   */
+  public void testDivideRoundUpPos() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "7472334223847623782375469293018787918347987234564568";
+    int bScale = 13;
+    String c = "1.24390557635720517122423359799284E+53";
+    int resScale = -21;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divide(bNumber, resScale, BigDecimal.ROUND_UP);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  public void testDivideSmall() {
+    BigDecimal a = BigDecimal.valueOf(6);
+    BigDecimal b = BigDecimal.valueOf(2);
+    BigDecimal quotient = a.divide(b);
+    assertEquals("3", quotient.toString());
+    quotient = a.divideToIntegralValue(b);
+    assertEquals("3", quotient.toString());
+    quotient = a.divide(BigDecimal.ONE);
+    assertEquals("6", quotient.toString());
+    quotient = a.divide(BigDecimal.ONE.negate());
+    assertEquals("-6", quotient.toString());
+  }
+  
+  /**
+   * divideToIntegralValue(BigDecimal)
+   */
+  public void testDivideToIntegralValue() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 45;
+    String b = "134432345432345748766876876723342238476237823787879183470";
+    int bScale = 70;
+    String c = "277923185514690367474770683";
+    int resScale = 0;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divideToIntegralValue(bNumber);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * divideToIntegralValue(BigDecimal, MathContext)
+   */
+  public void testDivideToIntegralValueMathContextDOWN() {
+    String a = "3736186567876876578956958769675785435673453453653543654354365435675671119238118911893939591735";
+    int aScale = 45;
+    String b = "134432345432345748766876876723342238476237823787879183470";
+    int bScale = 70;
+    int precision = 75;
+    RoundingMode rm = RoundingMode.DOWN;
+    MathContext mc = new MathContext(precision, rm);
+    String c = "2.7792318551469036747477068339450205874992634417590178670822889E+62";
+    int resScale = -1;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divideToIntegralValue(bNumber, mc);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * divideToIntegralValue(BigDecimal, MathContext)
+   */
+  public void testDivideToIntegralValueMathContextUP() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 45;
+    String b = "134432345432345748766876876723342238476237823787879183470";
+    int bScale = 70;
+    int precision = 32;
+    RoundingMode rm = RoundingMode.UP;
+    MathContext mc = new MathContext(precision, rm);
+    String c = "277923185514690367474770683";
+    int resScale = 0;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.divideToIntegralValue(bNumber, mc);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  public void testDivideZero() {
+    BigDecimal quotient = BigDecimal.ZERO.divide(BigDecimal.ONE);
+    assertEquals(BigDecimal.ZERO, quotient);
+    quotient = BigDecimal.ZERO.negate().divide(BigDecimal.ONE);
+    assertEquals(BigDecimal.ZERO, quotient);
+    try {
+      quotient = BigDecimal.ZERO.divide(BigDecimal.ZERO);
+      fail("Expected ArithmeticException, divide by zero");
+    } catch (ArithmeticException expected) {
+    }
+    assertEquals(BigDecimal.ZERO, quotient);
+    try {
+      quotient = BigDecimal.ONE.divide(BigDecimal.ZERO);
+      fail("Expected ArithmeticException, divide by zero");
+    } catch (ArithmeticException expected) {      
+    }
+    try {
+      quotient = BigDecimal.ONE.divideToIntegralValue(BigDecimal.ZERO);
+      fail("Expected ArithmeticException, divide by zero");
+    } catch (ArithmeticException expected) {      
+    }
+  }
+
+  /**
+   * Multiply two numbers of different scales
+   */
+  public void testMultiplyDiffScaleNegPos() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = -15;
+    String b = "747233429293018787918347987234564568";
+    int bScale = 10;
+    String c = "9.20003122862175749786430095741145455670101391569026662845893091880727173060570190220616E+91";
+    int cScale = -5;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.multiply(bNumber);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Multiply two numbers of different scales
+   */
+  public void testMultiplyDiffScalePosNeg() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 10;
+    String b = "747233429293018787918347987234564568";
+    int bScale = -10;
+    String c = "920003122862175749786430095741145455670101391569026662845893091880727173060570190220616";
+    int cScale = 0;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.multiply(bNumber);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Multiply two numbers of negative scales
+   */
+  public void testMultiplyEqualScaleNegNeg() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = -15;
+    String b = "747233429293018787918347987234564568";
+    int bScale = -10;
+    String c = "9.20003122862175749786430095741145455670101391569026662845893091880727173060570190220616E+111";
+    int cScale = -25;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.multiply(bNumber);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Multiply two numbers of different scales using MathContext
+   */
+  public void testMultiplyMathContextDiffScaleNegPos() {
+    String a = "488757458676796558668876576576579097029810457634781384756794987";
+    int aScale = -63;
+    String b = "747233429293018787918347987234564568";
+    int bScale = 63;
+    String c = "3.6521591193960361339707130098174381429788164316E+98";
+    int cScale = -52;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    MathContext mc = new MathContext(47, RoundingMode.HALF_UP);
+    BigDecimal result = aNumber.multiply(bNumber, mc);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Multiply two numbers of different scales using MathContext
+   */
+  public void testMultiplyMathContextDiffScalePosNeg() {
+    String a = "987667796597975765768768767866756808779810457634781384756794987";
+    int aScale = 100;
+    String b = "747233429293018787918347987234564568";
+    int bScale = -70;
+    String c = "7.3801839465418518653942222612429081498248509257207477E+68";
+    int cScale = -16;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    MathContext mc = new MathContext(53, RoundingMode.HALF_UP);
+    BigDecimal result = aNumber.multiply(bNumber, mc);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Multiply two numbers of positive scales using MathContext
+   */
+  public void testMultiplyMathContextScalePosPos() {
+    String a = "97665696756578755423325476545428779810457634781384756794987";
+    int aScale = -25;
+    String b = "87656965586786097685674786576598865";
+    int bScale = 10;
+    String c = "8.561078619600910561431314228543672720908E+108";
+    int cScale = -69;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    MathContext mc = new MathContext(40, RoundingMode.HALF_DOWN);
+    BigDecimal result = aNumber.multiply(bNumber, mc);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Multiply two numbers of positive scales
+   */
+  public void testMultiplyScalePosPos() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 15;
+    String b = "747233429293018787918347987234564568";
+    int bScale = 10;
+    String c = "92000312286217574978643009574114545567010139156902666284589309.1880727173060570190220616";
+    int cScale = 25;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.multiply(bNumber);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * pow(int)
+   */
+  public void testPow() {
+    String a = "123121247898748298842980";
+    int aScale = 10;
+    int exp = 10;
+    String c = "8004424019039195734129783677098845174704975003788210729597"
+        + "4875206425711159855030832837132149513512555214958035390490"
+        + "798520842025826.594316163502809818340013610490541783276343"
+        + "6514490899700151256484355936102754469438371850240000000000";
+    int cScale = 100;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal result = aNumber.pow(exp);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * pow(0)
+   */
+  public void testPow0() {
+    String a = "123121247898748298842980";
+    int aScale = 10;
+    int exp = 0;
+    String c = "1";
+    int cScale = 0;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal result = aNumber.pow(exp);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * pow(int, MathContext)
+   */
+  public void testPowMathContext() {
+    String a = "123121247898748298842980";
+    int aScale = 10;
+    int exp = 10;
+    String c = "8.0044E+130";
+    int cScale = -126;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    MathContext mc = new MathContext(5, RoundingMode.HALF_UP);
+    BigDecimal result = aNumber.pow(exp, mc);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * remainder(BigDecimal)
+   */
+  public void testRemainder1() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 45;
+    String b = "134432345432345748766876876723342238476237823787879183470";
+    int bScale = 10;
+    String res = "3736186567876.876578956958765675671119238118911893939591735";
+    int resScale = 45;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.remainder(bNumber);
+    assertEquals("incorrect quotient value", res, result.toString());
+    assertEquals("incorrect quotient scale", resScale, result.scale());
+  }
+
+  /**
+   * remainder(BigDecimal)
+   */
+  public void testRemainder2() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = -45;
+    String b = "134432345432345748766876876723342238476237823787879183470";
+    int bScale = 10;
+    String res = "1149310942946292909508821656680979993738625937.2065885780";
+    int resScale = 10;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.remainder(bNumber);
+    assertEquals("incorrect quotient value", res, result.toString());
+    assertEquals("incorrect quotient scale", resScale, result.scale());
+  }
+
+  /**
+   * remainder(BigDecimal, MathContext)
+   */
+  public void testRemainderMathContextHALF_DOWN() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = -45;
+    String b = "134432345432345748766876876723342238476237823787879183470";
+    int bScale = 10;
+    int precision = 75;
+    RoundingMode rm = RoundingMode.HALF_DOWN;
+    MathContext mc = new MathContext(precision, rm);
+    String res = "1149310942946292909508821656680979993738625937.2065885780";
+    int resScale = 10;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.remainder(bNumber, mc);
+    assertEquals("incorrect quotient value", res, result.toString());
+    assertEquals("incorrect quotient scale", resScale, result.scale());
+  }
+
+  /**
+   * remainder(BigDecimal, MathContext)
+   */
+  public void testRemainderMathContextHALF_UP() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 45;
+    String b = "134432345432345748766876876723342238476237823787879183470";
+    int bScale = 10;
+    int precision = 15;
+    RoundingMode rm = RoundingMode.HALF_UP;
+    MathContext mc = new MathContext(precision, rm);
+    String res = "3736186567876.876578956958765675671119238118911893939591735";
+    int resScale = 45;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.remainder(bNumber, mc);
+    assertEquals("incorrect quotient value", res, result.toString());
+    assertEquals("incorrect quotient scale", resScale, result.scale());
+  }
+
+  /**
+   * round(BigDecimal, MathContext)
+   */
+  public void testRoundMathContextHALF_DOWN() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = -45;
+    int precision = 75;
+    RoundingMode rm = RoundingMode.HALF_DOWN;
+    MathContext mc = new MathContext(precision, rm);
+    String res = "3.736186567876876578956958765675671119238118911893939591735E+102";
+    int resScale = -45;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal result = aNumber.round(mc);
+    assertEquals("incorrect quotient value", res, result.toString());
+    assertEquals("incorrect quotient scale", resScale, result.scale());
+  }
+
+  /**
+   * round(BigDecimal, MathContext)
+   */
+  public void testRoundMathContextHALF_UP() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 45;
+    int precision = 15;
+    RoundingMode rm = RoundingMode.HALF_UP;
+    MathContext mc = new MathContext(precision, rm);
+    String res = "3736186567876.88";
+    int resScale = 2;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal result = aNumber.round(mc);
+    assertEquals("incorrect quotient value", res, result.toString());
+    assertEquals("incorrect quotient scale", resScale, result.scale());
+  }
+
+  /**
+   * round(BigDecimal, MathContext) when precision = 0
+   */
+  public void testRoundMathContextPrecision0() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 45;
+    int precision = 0;
+    RoundingMode rm = RoundingMode.HALF_UP;
+    MathContext mc = new MathContext(precision, rm);
+    String res = "3736186567876.876578956958765675671119238118911893939591735";
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal result = aNumber.round(mc);
+    assertEquals("incorrect quotient value", res, result.toString());
+    assertEquals("incorrect quotient scale", aScale, result.scale());
+  }
+
+  /**
+   * Subtract two numbers of different scales; the first is negative
+   */
+  public void testSubtractDiffScaleNegPos() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = -15;
+    String b = "747233429293018787918347987234564568";
+    int bScale = 10;
+    String c = "1231212478987482988429808779810457634781310033452057698121208165201.2765435432";
+    int cScale = 10;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.subtract(bNumber);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Subtract two numbers of different scales; the first is positive
+   */
+  public void testSubtractDiffScalePosNeg() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 15;
+    String b = "747233429293018787918347987234564568";
+    int bScale = -10;
+    String c = "-7472334291698975400195996883915836900189542365.218615243205013";
+    int cScale = 15;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.subtract(bNumber);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Subtract two numbers of equal negative scales
+   */
+  public void testSubtractEqualScaleNegNeg() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = -10;
+    String b = "747233429293018787918347987234564568";
+    int bScale = -10;
+    String c = "1.231212478987482241196379486791669716433397522230419E+61";
+    int cScale = -10;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.subtract(bNumber);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Subtract two numbers of equal positive scales
+   */
+  public void testSubtractEqualScalePosPos() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 10;
+    String b = "747233429293018787918347987234564568";
+    int bScale = 10;
+    String c = "123121247898748224119637948679166971643339.7522230419";
+    int cScale = 10;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal result = aNumber.subtract(bNumber);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Subtract two numbers of different scales using MathContext; the first is
+   * negative
+   */
+  public void testSubtractMathContextDiffScaleNegPos() {
+    String a = "986798656676789766678767876078779810457634781384756794987";
+    int aScale = -15;
+    String b = "747233429293018787918347987234564568";
+    int bScale = 40;
+    String c = "9.867986566767897666787678760787798104576347813847567949870000000000000E+71";
+    int cScale = -2;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    MathContext mc = new MathContext(70, RoundingMode.HALF_DOWN);
+    BigDecimal result = aNumber.subtract(bNumber, mc);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Subtract two numbers of different scales using MathContext; the first is
+   * positive
+   */
+  public void testSubtractMathContextDiffScalePosNeg() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 15;
+    String b = "747233429293018787918347987234564568";
+    int bScale = -10;
+    String c = "-7.4723342916989754E+45";
+    int cScale = -29;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    MathContext mc = new MathContext(17, RoundingMode.DOWN);
+    BigDecimal result = aNumber.subtract(bNumber, mc);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * Subtract two numbers of equal positive scales using MathContext
+   */
+  public void testSubtractMathContextEqualScalePosPos() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 10;
+    String b = "747233429293018787918347987234564568";
+    int bScale = 10;
+    String c = "1.23121247898749E+41";
+    int cScale = -27;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    MathContext mc = new MathContext(15, RoundingMode.CEILING);
+    BigDecimal result = aNumber.subtract(bNumber, mc);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+
+  /**
+   * ulp() of a negative BigDecimal
+   */
+  public void testUlpNeg() {
+    String a = "-3736186567876876578956958765675671119238118911893939591735";
+    int aScale = 45;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal result = aNumber.ulp();
+    String res = "1E-45";
+    int resScale = 45;
+    assertEquals("incorrect value", res, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * ulp() of a positive BigDecimal
+   */
+  public void testUlpPos() {
+    String a = "3736186567876876578956958765675671119238118911893939591735";
+    int aScale = -45;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal result = aNumber.ulp();
+    String res = "1E+45";
+    int resScale = -45;
+    assertEquals("incorrect value", res, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * ulp() of a negative BigDecimal
+   */
+  public void testUlpZero() {
+    String a = "0";
+    int aScale = 2;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal result = aNumber.ulp();
+    String res = "0.01";
+    int resScale = 2;
+    assertEquals("incorrect value", res, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * ZERO.pow(0)
+   */
+  public void testZeroPow0() {
+    String c = "1";
+    int cScale = 0;
+    BigDecimal result = BigDecimal.ZERO.pow(0);
+    assertEquals("incorrect value", c, result.toString());
+    assertEquals("incorrect scale", cScale, result.scale());
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/math/BigDecimalCompareTest.java b/user/test/com/google/gwt/emultest/java/math/BigDecimalCompareTest.java
new file mode 100644
index 0000000..d91f5b1
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigDecimalCompareTest.java
@@ -0,0 +1,529 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.MathContext;
+import java.math.RoundingMode;
+
+/**
+ * Class: java.math.BigDecimal Methods: abs, compareTo, equals, hashCode, max,
+ * min, negate, signum.
+ */
+public class BigDecimalCompareTest extends EmulTestBase {
+
+  /**
+   * Abs(MathContext) of a negative BigDecimal.
+   */
+  public void testAbsMathContextNeg() {
+    String a = "-123809648392384754573567356745735.63567890295784902768787678287E+21";
+    BigDecimal aNumber = new BigDecimal(a);
+    int precision = 15;
+    RoundingMode rm = RoundingMode.HALF_DOWN;
+    MathContext mc = new MathContext(precision, rm);
+    String result = "1.23809648392385E+53";
+    int resScale = -39;
+    BigDecimal res = aNumber.abs(mc);
+    assertEquals("incorrect value", result, res.toString());
+    assertEquals("incorrect scale", resScale, res.scale());
+  }
+
+  /**
+   * Abs(MathContext) of a positive BigDecimal.
+   */
+  public void testAbsMathContextPos() {
+    String a = "123809648392384754573567356745735.63567890295784902768787678287E+21";
+    BigDecimal aNumber = new BigDecimal(a);
+    int precision = 41;
+    RoundingMode rm = RoundingMode.HALF_EVEN;
+    MathContext mc = new MathContext(precision, rm);
+    String result = "1.2380964839238475457356735674573563567890E+53";
+    int resScale = -13;
+    BigDecimal res = aNumber.abs(mc);
+    assertEquals("incorrect value", result, res.toString());
+    assertEquals("incorrect scale", resScale, res.scale());
+  }
+
+  /**
+   * Abs() of a negative BigDecimal.
+   */
+  public void testAbsNeg() {
+    String a = "-123809648392384754573567356745735.63567890295784902768787678287E+21";
+    BigDecimal aNumber = new BigDecimal(a);
+    String result = "123809648392384754573567356745735635678902957849027687.87678287";
+    assertEquals("incorrect value", result, aNumber.abs().toString());
+  }
+
+  /**
+   * Abs() of a positive BigDecimal.
+   */
+  public void testAbsPos() {
+    String a = "123809648392384754573567356745735.63567890295784902768787678287E+21";
+    BigDecimal aNumber = new BigDecimal(a);
+    String result = "123809648392384754573567356745735635678902957849027687.87678287";
+    assertEquals("incorrect value", result, aNumber.abs().toString());
+  }
+
+  /**
+   * Compare to a number of an equal scale.
+   */
+  public void testCompareEqualScale1() {
+    String a = "12380964839238475457356735674573563567890295784902768787678287";
+    int aScale = 18;
+    String b = "4573563567890295784902768787678287";
+    int bScale = 18;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    int result = 1;
+    assertEquals("incorrect result", result, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * Compare to a number of an equal scale.
+   */
+  public void testCompareEqualScale2() {
+    String a = "12380964839238475457356735674573563567890295784902768787678287";
+    int aScale = 18;
+    String b = "4573563923487289357829759278282992758247567890295784902768787678287";
+    int bScale = 18;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    int result = -1;
+    assertEquals("incorrect result", result, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * Compare to a number of an greater scale.
+   */
+  public void testCompareGreaterScale1() {
+    String a = "12380964839238475457356735674573563567890295784902768787678287";
+    int aScale = 28;
+    String b = "4573563567890295784902768787678287";
+    int bScale = 18;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    int result = 1;
+    assertEquals("incorrect result", result, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * Compare to a number of an greater scale.
+   */
+  public void testCompareGreaterScale2() {
+    String a = "12380964839238475457356735674573563567890295784902768787678287";
+    int aScale = 48;
+    String b = "4573563567890295784902768787678287";
+    int bScale = 2;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    int result = -1;
+    assertEquals("incorrect result", result, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * Compare to a number of an less scale.
+   */
+  public void testCompareLessScale1() {
+    String a = "12380964839238475457356735674573563567890295784902768787678287";
+    int aScale = 18;
+    String b = "4573563567890295784902768787678287";
+    int bScale = 28;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    int result = 1;
+    assertEquals("incorrect result", result, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * Compare to a number of an less scale.
+   */
+  public void testCompareLessScale2() {
+    String a = "12380964839238475457356735674573";
+    int aScale = 36;
+    String b = "45735635948573894578349572001798379183767890295784902768787678287";
+    int bScale = 48;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    int result = -1;
+    assertEquals("incorrect result", result, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * equals() for equal BigDecimals.
+   */
+  public void testEqualsEqual() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int bScale = -24;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    assertEquals(aNumber, bNumber);
+  }
+
+  /**
+   * equals() for equal BigDecimals.
+   */
+  public void testEqualsNull() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    assertFalse(aNumber.equals(null));
+  }
+
+  /**
+   * Equals() for unequal BigDecimals.
+   */
+  public void testEqualsUnequal1() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "7472334223847623782375469293018787918347987234564568";
+    int bScale = 13;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    assertFalse(aNumber.equals(bNumber));
+  }
+
+  /**
+   * Equals() for unequal BigDecimals.
+   */
+  public void testEqualsUnequal2() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int bScale = 13;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    assertFalse(aNumber.equals(bNumber));
+  }
+
+  /**
+   * Equals() for unequal BigDecimals.
+   */
+  public void testEqualsUnequal3() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "92948782094488478231212478987482988429808779810457634781384756794987";
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    assertFalse(aNumber.equals(b));
+  }
+
+  /**
+   * hashCode() for equal BigDecimals.
+   */
+  public void testHashCodeEqual() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = -24;
+    String b = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int bScale = -24;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    assertEquals("incorrect value", aNumber.hashCode(), bNumber.hashCode());
+  }
+
+  /**
+   * hashCode() for unequal BigDecimals.
+   */
+  public void testHashCodeUnequal() {
+    String a = "8478231212478987482988429808779810457634781384756794987";
+    int aScale = 41;
+    String b = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int bScale = -24;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    assertTrue("incorrect value", aNumber.hashCode() != bNumber.hashCode());
+  }
+
+  /**
+   * max() for equal BigDecimals.
+   */
+  public void testMaxEqual() {
+    String a = "8478231212478987482988429808779810457634781384756794987";
+    int aScale = 41;
+    String b = "8478231212478987482988429808779810457634781384756794987";
+    int bScale = 41;
+    String c = "8478231212478987482988429808779810457634781384756794987";
+    int cScale = 41;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal cNumber = new BigDecimal(new BigInteger(c), cScale);
+    assertEquals("incorrect value", cNumber, aNumber.max(bNumber));
+  }
+
+  /**
+   * max() for unequal BigDecimals.
+   */
+  public void testMaxUnequal1() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = 24;
+    String b = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int bScale = 41;
+    String c = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int cScale = 24;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal cNumber = new BigDecimal(new BigInteger(c), cScale);
+    assertEquals("incorrect value", cNumber, aNumber.max(bNumber));
+  }
+
+  /**
+   * max() for unequal BigDecimals.
+   */
+  public void testMaxUnequal2() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = 41;
+    String b = "94488478231212478987482988429808779810457634781384756794987";
+    int bScale = 41;
+    String c = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int cScale = 41;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal cNumber = new BigDecimal(new BigInteger(c), cScale);
+    assertEquals("incorrect value", cNumber, aNumber.max(bNumber));
+  }
+
+  /**
+   * min() for equal BigDecimals.
+   */
+  public void testMinEqual() {
+    String a = "8478231212478987482988429808779810457634781384756794987";
+    int aScale = 41;
+    String b = "8478231212478987482988429808779810457634781384756794987";
+    int bScale = 41;
+    String c = "8478231212478987482988429808779810457634781384756794987";
+    int cScale = 41;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal cNumber = new BigDecimal(new BigInteger(c), cScale);
+    assertEquals("incorrect value", cNumber, aNumber.min(bNumber));
+  }
+
+  /**
+   * min() for unequal BigDecimals.
+   */
+  public void testMinUnequal1() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = 24;
+    String b = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int bScale = 41;
+    String c = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int cScale = 41;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal cNumber = new BigDecimal(new BigInteger(c), cScale);
+    assertEquals("incorrect value", cNumber, aNumber.min(bNumber));
+  }
+
+  /**
+   * min() for unequal BigDecimals.
+   */
+  public void testMinUnequal2() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = 41;
+    String b = "94488478231212478987482988429808779810457634781384756794987";
+    int bScale = 41;
+    String c = "94488478231212478987482988429808779810457634781384756794987";
+    int cScale = 41;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = new BigDecimal(new BigInteger(b), bScale);
+    BigDecimal cNumber = new BigDecimal(new BigInteger(c), cScale);
+    assertEquals("incorrect value", cNumber, aNumber.min(bNumber));
+  }
+
+  /**
+   * negate(MathContext) for a negative BigDecimal.
+   */
+  public void testNegateMathContextNegative() {
+    if (!GWT.isScript()) {
+      // OpenJDK fails this test, so for now we only run it in web mode
+      return;
+    }
+    String a = "-92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = 49;
+    int precision = 46;
+    RoundingMode rm = RoundingMode.CEILING;
+    MathContext mc = new MathContext(precision, rm);
+    String c = "9294878209448847823.121247898748298842980877981";
+    int cScale = 27;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal res = aNumber.negate(mc);
+    assertEquals("incorrect value", c, res.toString());
+    assertEquals("incorrect scale", cScale, res.scale());
+  }
+
+  /**
+   * negate(MathContext) for a positive BigDecimal.
+   */
+  public void testNegateMathContextPositive() {
+    if (!GWT.isScript()) {
+      // OpenJDK fails this test, so for now we only run it in web mode
+      return;
+    }
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = 41;
+    int precision = 37;
+    RoundingMode rm = RoundingMode.FLOOR;
+    MathContext mc = new MathContext(precision, rm);
+    String c = "-929487820944884782312124789.8748298842";
+    int cScale = 10;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal res = aNumber.negate(mc);
+    assertEquals("incorrect value", c, res.toString());
+    assertEquals("incorrect scale", cScale, res.scale());
+  }
+
+  /**
+   * negate() for a negative BigDecimal.
+   */
+  public void testNegateNegative() {
+    String a = "-92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = 41;
+    String c = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int cScale = 41;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal cNumber = new BigDecimal(new BigInteger(c), cScale);
+    assertEquals("incorrect value", cNumber, aNumber.negate());
+  }
+
+  /**
+   * negate() for a positive BigDecimal.
+   */
+  public void testNegatePositive() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = 41;
+    String c = "-92948782094488478231212478987482988429808779810457634781384756794987";
+    int cScale = 41;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal cNumber = new BigDecimal(new BigInteger(c), cScale);
+    assertEquals("incorrect value", cNumber, aNumber.negate());
+  }
+
+  /**
+   * plus(MathContext) for a negative BigDecimal.
+   */
+  public void testPlusMathContextNegative() {
+    String a = "-92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = 49;
+    int precision = 46;
+    RoundingMode rm = RoundingMode.CEILING;
+    MathContext mc = new MathContext(precision, rm);
+    String c = "-9294878209448847823.121247898748298842980877981";
+    int cScale = 27;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal res = aNumber.plus(mc);
+    assertEquals("incorrect value", c, res.toString());
+    assertEquals("incorrect scale", cScale, res.scale());
+  }
+
+  /**
+   * plus(MathContext) for a positive BigDecimal.
+   */
+  public void testPlusMathContextPositive() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = 41;
+    int precision = 37;
+    RoundingMode rm = RoundingMode.FLOOR;
+    MathContext mc = new MathContext(precision, rm);
+    String c = "929487820944884782312124789.8748298842";
+    int cScale = 10;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal res = aNumber.plus(mc);
+    assertEquals("incorrect value", c, res.toString());
+    assertEquals("incorrect scale", cScale, res.scale());
+  }
+
+  /**
+   * plus() for a negative BigDecimal.
+   */
+  public void testPlusNegative() {
+    String a = "-92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = 41;
+    String c = "-92948782094488478231212478987482988429808779810457634781384756794987";
+    int cScale = 41;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal cNumber = new BigDecimal(new BigInteger(c), cScale);
+    assertEquals("incorrect value", cNumber, aNumber.plus());
+  }
+
+  /**
+   * plus() for a positive BigDecimal.
+   */
+  public void testPlusPositive() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = 41;
+    String c = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int cScale = 41;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal cNumber = new BigDecimal(new BigInteger(c), cScale);
+    assertEquals("incorrect value", cNumber, aNumber.plus());
+  }
+
+  /**
+   * signum() for a negative BigDecimal.
+   */
+  public void testSignumNegative() {
+    String a = "-92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = 41;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    assertEquals("incorrect value", -1, aNumber.signum());
+  }
+
+  /**
+   * signum() for a positive BigDecimal.
+   */
+  public void testSignumPositive() {
+    String a = "92948782094488478231212478987482988429808779810457634781384756794987";
+    int aScale = 41;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    assertEquals("incorrect value", 1, aNumber.signum());
+  }
+
+  /**
+   * signum() for zero.
+   */
+  public void testSignumZero() {
+    String a = "0";
+    int aScale = 41;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    assertEquals("incorrect value", 0, aNumber.signum());
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/math/BigDecimalConstructorsTest.java b/user/test/com/google/gwt/emultest/java/math/BigDecimalConstructorsTest.java
new file mode 100644
index 0000000..66fe6ba
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigDecimalConstructorsTest.java
@@ -0,0 +1,763 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+import com.google.gwt.junit.DoNotRunWith;
+import com.google.gwt.junit.Platform;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.MathContext;
+import java.math.RoundingMode;
+
+/**
+ * Class: java.math.BigDecimal Methods: constructors and fields.
+ */
+public class BigDecimalConstructorsTest extends EmulTestBase {
+
+  /**
+   * new BigDecimal(BigInteger value).
+   */
+  public void testConstrBI() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    BigInteger bA = new BigInteger(a);
+    BigDecimal aNumber = new BigDecimal(bA);
+    assertEquals("incorrect value", bA, aNumber.unscaledValue());
+    assertEquals("incorrect scale", 0, aNumber.scale());
+
+    try {
+      new BigDecimal((BigInteger) null);
+      fail("No NullPointerException");
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  /**
+   * new BigDecimal(BigInteger value, MathContext).
+   */
+  public void testConstrBigIntegerMathContext() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    BigInteger bA = new BigInteger(a);
+    int precision = 46;
+    RoundingMode rm = RoundingMode.CEILING;
+    MathContext mc = new MathContext(precision, rm);
+    String res = "1231212478987482988429808779810457634781384757";
+    int resScale = -6;
+    BigDecimal result = new BigDecimal(bA, mc);
+    assertEquals("incorrect value", res, result.unscaledValue().toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * new BigDecimal(BigInteger value, int scale, MathContext).
+   */
+  public void testConstrBigIntegerScaleMathContext() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    BigInteger bA = new BigInteger(a);
+    int aScale = 10;
+    int precision = 46;
+    RoundingMode rm = RoundingMode.CEILING;
+    MathContext mc = new MathContext(precision, rm);
+    String res = "1231212478987482988429808779810457634781384757";
+    int resScale = 4;
+    BigDecimal result = new BigDecimal(bA, aScale, mc);
+    assertEquals("incorrect value", res, result.unscaledValue().toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * new BigDecimal(BigInteger value, int scale).
+   */
+  public void testConstrBIScale() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    BigInteger bA = new BigInteger(a);
+    int aScale = 10;
+    BigDecimal aNumber = new BigDecimal(bA, aScale);
+    assertEquals("incorrect value", bA, aNumber.unscaledValue());
+    assertEquals("incorrect scale", aScale, aNumber.scale());
+  }
+
+  /**
+   * new BigDecimal(char[] value).
+   */
+  public void testConstrChar() {
+    char value[] = {
+        '-', '1', '2', '3', '8', '0', '.', '4', '7', '3', '8', 'E', '-', '4',
+        '2', '3'};
+    BigDecimal result = new BigDecimal(value);
+    String res = "-1.23804738E-419";
+    int resScale = 427;
+    assertEquals("incorrect value", res, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+
+    try {
+      // Regression for HARMONY-783
+      new BigDecimal(new char[] {});
+      fail("NumberFormatException has not been thrown");
+    } catch (NumberFormatException e) {
+    }
+  }
+
+  /**
+   * new BigDecimal(char[] value, int offset, int len).
+   */
+  public void testConstrCharIntInt() {
+    char value[] = {
+        '-', '1', '2', '3', '8', '0', '.', '4', '7', '3', '8', 'E', '-', '4',
+        '2', '3'};
+    int offset = 3;
+    int len = 12;
+    BigDecimal result = new BigDecimal(value, offset, len);
+    String res = "3.804738E-40";
+    int resScale = 46;
+    assertEquals("incorrect value", res, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+
+    try {
+      // Regression for HARMONY-783
+      new BigDecimal(new char[] {}, 0, 0);
+      fail("NumberFormatException has not been thrown");
+    } catch (NumberFormatException e) {
+    }
+  }
+
+  /**
+   * new BigDecimal(char[] value, int offset, int len, MathContext mc).
+   */
+  public void testConstrCharIntIntMathContext() {
+    char value[] = {
+        '-', '1', '2', '3', '8', '0', '.', '4', '7', '3', '8', 'E', '-', '4',
+        '2', '3'};
+    int offset = 3;
+    int len = 12;
+    int precision = 4;
+    RoundingMode rm = RoundingMode.CEILING;
+    MathContext mc = new MathContext(precision, rm);
+    BigDecimal result = new BigDecimal(value, offset, len, mc);
+    String res = "3.805E-40";
+    int resScale = 43;
+    assertEquals("incorrect value", res, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+
+    try {
+      // Regression for HARMONY-783
+      new BigDecimal(new char[] {}, 0, 0, MathContext.DECIMAL32);
+      fail("NumberFormatException has not been thrown");
+    } catch (NumberFormatException e) {
+    }
+  }
+
+  /**
+   * new BigDecimal(char[] value, int offset, int len, MathContext mc).
+   */
+  public void testConstrCharIntIntMathContextException1() {
+    char value[] = {
+        '-', '1', '2', '3', '8', '0', '.', '4', '7', '3', '8', 'E', '-', '4',
+        '2', '3'};
+    int offset = 3;
+    int len = 120;
+    int precision = 4;
+    RoundingMode rm = RoundingMode.CEILING;
+    MathContext mc = new MathContext(precision, rm);
+    try {
+      new BigDecimal(value, offset, len, mc);
+      fail("NumberFormatException has not been thrown");
+    } catch (NumberFormatException e) {
+    }
+  }
+
+  /**
+   * new BigDecimal(char[] value, int offset, int len, MathContext mc).
+   */
+  public void testConstrCharIntIntMathContextException2() {
+    char value[] = {
+        '-', '1', '2', '3', '8', '0', ',', '4', '7', '3', '8', 'E', '-', '4',
+        '2', '3'};
+    int offset = 3;
+    int len = 120;
+    int precision = 4;
+    RoundingMode rm = RoundingMode.CEILING;
+    MathContext mc = new MathContext(precision, rm);
+    try {
+      new BigDecimal(value, offset, len, mc);
+      fail("NumberFormatException has not been thrown");
+    } catch (NumberFormatException e) {
+    }
+  }
+
+  /**
+   * new BigDecimal(char[] value, MathContext mc).
+   */
+  public void testConstrCharMathContext() {
+    char value[] = {
+        '3', '8', '0', '.', '4', '7', '3', '8', 'E', '-', '4', '2'
+    };
+    int precision = 4;
+    RoundingMode rm = RoundingMode.CEILING;
+    MathContext mc = new MathContext(precision, rm);
+    BigDecimal result = new BigDecimal(value, mc);
+    String res = "3.805E-40";
+    int resScale = 43;
+    assertEquals("incorrect value", res, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+
+    // Regression for HARMONY-783
+    try {
+      new BigDecimal(new char[] {}, MathContext.DECIMAL32);
+      fail("NumberFormatException has not been thrown");
+    } catch (NumberFormatException e) {
+    }
+  }
+
+  /**
+   * new BigDecimal(double value).
+   */
+  public void testConstrDouble() {
+    double a = 732546982374982347892379283571094797.287346782359284756;
+    BigDecimal aNumber = new BigDecimal(a);
+    BigDecimal expected = new BigDecimal(
+        "732546982374982347892379283571094797.287346782359284756");
+    assertEquals(expected, aNumber, 1e21);
+  }
+
+  /**
+   * new BigDecimal(0.1).
+   */
+  public void testConstrDouble01() {
+    double a = 1.E-1;
+    BigDecimal aNumber = new BigDecimal(a);
+    BigDecimal expected = new BigDecimal(
+        ".1000000000000000055511151231257827021181583404541015625");
+    assertEquals(expected, aNumber, 1e-9);
+  }
+
+  /**
+   * new BigDecimal(0.555).
+   */
+  public void testConstrDouble02() {
+    double a = 0.555;
+    BigDecimal aNumber = new BigDecimal(a);
+    BigDecimal expected = new BigDecimal(
+        ".55500000000000004884981308350688777863979339599609375");
+    assertEquals(expected, aNumber, 1e-8);
+  }
+
+  /**
+   * new BigDecimal(double value) when value is denormalized.
+   */
+  @DoNotRunWith(Platform.HtmlUnit)
+  public void testConstrDoubleDenormalized() {
+    // HtmlUnit incorrectly converts the following double to a string
+    // Safari can't handle e-309 here
+    double a = 2.274341322658976E-304;
+    BigDecimal aNumber = new BigDecimal(a);
+    BigDecimal expected = new BigDecimal(
+        "2.274341322658976E-304");
+    assertEquals(expected, aNumber, 1e-305);
+  }
+
+  /**
+   * new BigDecimal(double, MathContext).
+   */
+  public void testConstrDoubleMathContext() {
+    double a = 732546982374982347892379283571094797.287346782359284756;
+    int precision = 21;
+    RoundingMode rm = RoundingMode.CEILING;
+    MathContext mc = new MathContext(precision, rm);
+    BigDecimal result = new BigDecimal(a, mc);
+    BigDecimal expected = new BigDecimal("732546982374982e21");
+    assertEquals(expected, result, 1e21);
+    try {
+      new BigDecimal(Double.NaN);
+      fail("Expected NumberFormatException on NaN");
+    } catch (NumberFormatException expectedException) {
+    }
+    try {
+      new BigDecimal(Double.POSITIVE_INFINITY);
+      fail("Expected NumberFormatException on +Infinity");
+    } catch (NumberFormatException expectedException) {
+    }
+    try {
+      new BigDecimal(Double.NEGATIVE_INFINITY);
+      fail("Expected NumberFormatException on -Infinity");
+    } catch (NumberFormatException expectedException) {
+    }
+  }
+
+  /**
+   * new BigDecimal(-0.1).
+   */
+  public void testConstrDoubleMinus01() {
+    double a = -1.E-1;
+    BigDecimal aNumber = new BigDecimal(a);
+    BigDecimal expected = new BigDecimal(
+        "-.1000000000000000055511151231257827021181583404541015625");
+    assertEquals(expected, aNumber, 1e-9);
+  }
+
+  /**
+   * new BigDecimal(double value) when value is NaN.
+   */
+  public void testConstrDoubleNaN() {
+    double a = Double.NaN;
+    try {
+      new BigDecimal(a);
+      fail("NumberFormatException has not been caught");
+    } catch (NumberFormatException e) {
+      assertEquals("Improper exception message", "Infinite or NaN",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * new BigDecimal(double value) when value is positive infinity.
+   */
+  public void testConstrDoubleNegInfinity() {
+    double a = Double.NEGATIVE_INFINITY;
+    try {
+      new BigDecimal(a);
+      fail("NumberFormatException has not been caught");
+    } catch (NumberFormatException e) {
+      assertEquals("Improper exception message", "Infinite or NaN",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * new BigDecimal(double value) when value is positive infinity.
+   */
+  public void testConstrDoublePosInfinity() {
+    double a = Double.POSITIVE_INFINITY;
+    try {
+      new BigDecimal(a);
+      fail("NumberFormatException has not been caught");
+    } catch (NumberFormatException e) {
+      assertEquals("Improper exception message", "Infinite or NaN",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * new BigDecimal(int value).
+   */
+  public void testConstrInt() {
+    int a = 732546982;
+    String res = "732546982";
+    int resScale = 0;
+    BigDecimal result = new BigDecimal(a);
+    assertEquals("incorrect value", res, result.unscaledValue().toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * new BigDecimal(int, MathContext).
+   */
+  public void testConstrIntMathContext() {
+    int a = 732546982;
+    int precision = 21;
+    RoundingMode rm = RoundingMode.CEILING;
+    MathContext mc = new MathContext(precision, rm);
+    String res = "732546982";
+    int resScale = 0;
+    BigDecimal result = new BigDecimal(a, mc);
+    assertEquals("incorrect value", res, result.unscaledValue().toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * new BigDecimal(long value).
+   */
+  public void testConstrLong() {
+    long a = 4576578677732546982L;
+    String res = "4576578677732546982";
+    int resScale = 0;
+    BigDecimal result = new BigDecimal(a);
+    assertEquals("incorrect value", res, result.unscaledValue().toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * new BigDecimal(long, MathContext).
+   */
+  public void testConstrLongMathContext() {
+    long a = 4576578677732546982L;
+    int precision = 5;
+    RoundingMode rm = RoundingMode.CEILING;
+    MathContext mc = new MathContext(precision, rm);
+    String res = "45766";
+    int resScale = -14;
+    BigDecimal result = new BigDecimal(a, mc);
+    assertEquals("incorrect value", res, result.unscaledValue().toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * new BigDecimal(String value) when value is not a valid representation of
+   * BigDecimal.
+   */
+  public void testConstrStringException() {
+    String a = "-238768.787678287a+10";
+    try {
+      new BigDecimal(a);
+      fail("NumberFormatException has not been caught");
+    } catch (NumberFormatException e) {
+    }
+  }
+
+  /**
+   * new BigDecimal(String value) when exponent is empty.
+   */
+  public void testConstrStringExceptionEmptyExponent1() {
+    String a = "-238768.787678287e";
+    try {
+      new BigDecimal(a);
+      fail("NumberFormatException has not been caught");
+    } catch (NumberFormatException e) {
+    }
+  }
+
+  /**
+   * new BigDecimal(String value) when exponent is empty.
+   */
+  public void testConstrStringExceptionEmptyExponent2() {
+    String a = "-238768.787678287e-";
+    try {
+      new BigDecimal(a);
+      fail("NumberFormatException has not been caught");
+    } catch (NumberFormatException e) {
+    }
+  }
+
+  /**
+   * new BigDecimal(String value) when exponent is greater than
+   * Integer.MAX_VALUE.
+   */
+  public void testConstrStringExceptionExponentGreaterIntegerMax() {
+    String a = "-238768.787678287e214748364767876";
+    try {
+      new BigDecimal(a);
+      fail("NumberFormatException has not been caught");
+    } catch (NumberFormatException e) {
+    }
+  }
+
+  /**
+   * new BigDecimal(String value) when exponent is less than Integer.MIN_VALUE.
+   */
+  public void testConstrStringExceptionExponentLessIntegerMin() {
+    String a = "-238768.787678287e-214748364767876";
+    try {
+      new BigDecimal(a);
+      fail("NumberFormatException has not been caught");
+    } catch (NumberFormatException e) {
+    }
+  }
+
+  /**
+   * new BigDecimal(String value) when exponent is Integer.MAX_VALUE.
+   */
+  public void testConstrStringExponentIntegerMax() {
+    String a = "-238768.787678287e2147483647";
+    int aScale = -2147483638;
+    BigInteger bA = new BigInteger("-238768787678287");
+    BigDecimal aNumber = new BigDecimal(a);
+    assertEquals("incorrect value", bA, aNumber.unscaledValue());
+    assertEquals("incorrect scale", aScale, aNumber.scale());
+  }
+
+  /**
+   * new BigDecimal(String value) when exponent is Integer.MIN_VALUE.
+   */
+  public void testConstrStringExponentIntegerMin() {
+    String a = ".238768e-2147483648";
+    try {
+      new BigDecimal(a);
+      fail("NumberFormatException expected");
+    } catch (NumberFormatException e) {
+      assertEquals("Improper exception message", "Scale out of range.",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * new BigDecimal(String value, MathContext).
+   */
+  public void testConstrStringMathContext() {
+    String a = "-238768787678287e214";
+    int precision = 5;
+    RoundingMode rm = RoundingMode.CEILING;
+    MathContext mc = new MathContext(precision, rm);
+    String res = "-23876";
+    int resScale = -224;
+    BigDecimal result = new BigDecimal(a, mc);
+    assertEquals("incorrect value", res, result.unscaledValue().toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * new BigDecimal(String value); value contains exponent and does not contain
+   * decimal point.
+   */
+  public void testConstrStringWithExponentWithoutPoint1() {
+    String a = "-238768787678287e214";
+    int aScale = -214;
+    BigInteger bA = new BigInteger("-238768787678287");
+    BigDecimal aNumber = new BigDecimal(a);
+    assertEquals("incorrect value", bA, aNumber.unscaledValue());
+    assertEquals("incorrect scale", aScale, aNumber.scale());
+  }
+
+  /**
+   * new BigDecimal(String value); value contains exponent and does not contain
+   * decimal point.
+   */
+  public void testConstrStringWithExponentWithoutPoint2() {
+    String a = "-238768787678287e-214";
+    int aScale = 214;
+    BigInteger bA = new BigInteger("-238768787678287");
+    BigDecimal aNumber = new BigDecimal(a);
+    assertEquals("incorrect value", bA, aNumber.unscaledValue());
+    assertEquals("incorrect scale", aScale, aNumber.scale());
+  }
+
+  /**
+   * new BigDecimal(String value); value contains exponent and does not contain
+   * decimal point.
+   */
+  public void testConstrStringWithExponentWithoutPoint3() {
+    String a = "238768787678287e-214";
+    int aScale = 214;
+    BigInteger bA = new BigInteger("238768787678287");
+    BigDecimal aNumber = new BigDecimal(a);
+    assertEquals("incorrect value", bA, aNumber.unscaledValue());
+    assertEquals("incorrect scale", aScale, aNumber.scale());
+  }
+
+  /**
+   * new BigDecimal(String value); value contains exponent and does not contain
+   * decimal point.
+   */
+  public void testConstrStringWithExponentWithoutPoint4() {
+    String a = "238768787678287e+214";
+    int aScale = -214;
+    BigInteger bA = new BigInteger("238768787678287");
+    BigDecimal aNumber = new BigDecimal(a);
+    assertEquals("incorrect value", bA, aNumber.unscaledValue());
+    assertEquals("incorrect scale", aScale, aNumber.scale());
+  }
+
+  /**
+   * new BigDecimal(String value); value contains exponent and does not contain
+   * decimal point.
+   */
+  public void testConstrStringWithExponentWithoutPoint5() {
+    String a = "238768787678287E214";
+    int aScale = -214;
+    BigInteger bA = new BigInteger("238768787678287");
+    BigDecimal aNumber = new BigDecimal(a);
+    assertEquals("incorrect value", bA, aNumber.unscaledValue());
+    assertEquals("incorrect scale", aScale, aNumber.scale());
+  }
+
+  /**
+   * new BigDecimal(String value); value contains both exponent and decimal
+   * point.
+   */
+  public void testConstrStringWithExponentWithPoint1() {
+    String a = "23985439837984782435652424523876878.7678287e+214";
+    int aScale = -207;
+    BigInteger bA = new BigInteger("239854398379847824356524245238768787678287");
+    BigDecimal aNumber = new BigDecimal(a);
+    assertEquals("incorrect value", bA, aNumber.unscaledValue());
+    assertEquals("incorrect scale", aScale, aNumber.scale());
+  }
+
+  /**
+   * new BigDecimal(String value); value contains both exponent and decimal
+   * point.
+   */
+  public void testConstrStringWithExponentWithPoint2() {
+    String a = "238096483923847545735673567457356356789029578490276878.7678287e-214";
+    int aScale = 221;
+    BigInteger bA = new BigInteger(
+        "2380964839238475457356735674573563567890295784902768787678287");
+    BigDecimal aNumber = new BigDecimal(a);
+    assertEquals("incorrect value", bA, aNumber.unscaledValue());
+    assertEquals("incorrect scale", aScale, aNumber.scale());
+  }
+
+  /**
+   * new BigDecimal(String value); value contains both exponent and decimal
+   * point.
+   */
+  public void testConstrStringWithExponentWithPoint3() {
+    String a = "2380964839238475457356735674573563567890.295784902768787678287E+21";
+    int aScale = 0;
+    BigInteger bA = new BigInteger(
+        "2380964839238475457356735674573563567890295784902768787678287");
+    BigDecimal aNumber = new BigDecimal(a);
+    assertEquals("incorrect value", bA, aNumber.unscaledValue());
+    assertEquals("incorrect scale", aScale, aNumber.scale());
+  }
+
+  /**
+   * new BigDecimal(String value); value contains both exponent and decimal
+   * point.
+   */
+  public void testConstrStringWithExponentWithPoint4() {
+    String a = "23809648392384754573567356745735635678.90295784902768787678287E+21";
+    int aScale = 2;
+    BigInteger bA = new BigInteger(
+        "2380964839238475457356735674573563567890295784902768787678287");
+    BigDecimal aNumber = new BigDecimal(a);
+    assertEquals("incorrect value", bA, aNumber.unscaledValue());
+    assertEquals("incorrect scale", aScale, aNumber.scale());
+  }
+
+  /**
+   * new BigDecimal(String value); value contains both exponent and decimal
+   * point.
+   */
+  public void testConstrStringWithExponentWithPoint5() {
+    String a = "238096483923847545735673567457356356789029.5784902768787678287E+21";
+    int aScale = -2;
+    BigInteger bA = new BigInteger(
+        "2380964839238475457356735674573563567890295784902768787678287");
+    BigDecimal aNumber = new BigDecimal(a);
+    assertEquals("incorrect value", bA, aNumber.unscaledValue());
+    assertEquals("incorrect scale", aScale, aNumber.scale());
+  }
+
+  /**
+   * new BigDecimal(String value); value does not contain exponent.
+   */
+  public void testConstrStringWithoutExpNeg() {
+    String a = "-732546982374982347892379283571094797.287346782359284756";
+    int aScale = 18;
+    BigInteger bA = new BigInteger(
+        "-732546982374982347892379283571094797287346782359284756");
+    BigDecimal aNumber = new BigDecimal(a);
+    assertEquals("incorrect value", bA, aNumber.unscaledValue());
+    assertEquals("incorrect scale", aScale, aNumber.scale());
+  }
+
+  /**
+   * new BigDecimal(String value); value does not contain exponent.
+   */
+  public void testConstrStringWithoutExpPos1() {
+    String a = "732546982374982347892379283571094797.287346782359284756";
+    int aScale = 18;
+    BigInteger bA = new BigInteger(
+        "732546982374982347892379283571094797287346782359284756");
+    BigDecimal aNumber = new BigDecimal(a);
+    assertEquals("incorrect value", bA, aNumber.unscaledValue());
+    assertEquals("incorrect scale", aScale, aNumber.scale());
+  }
+
+  /**
+   * new BigDecimal(String value); value does not contain exponent.
+   */
+  public void testConstrStringWithoutExpPos2() {
+    String a = "+732546982374982347892379283571094797.287346782359284756";
+    int aScale = 18;
+    BigInteger bA = new BigInteger(
+        "732546982374982347892379283571094797287346782359284756");
+    BigDecimal aNumber = new BigDecimal(a);
+    assertEquals("incorrect value", bA, aNumber.unscaledValue());
+    assertEquals("incorrect scale", aScale, aNumber.scale());
+  }
+
+  /**
+   * new BigDecimal(String value); value does not contain exponent and decimal
+   * point.
+   */
+  public void testConstrStringWithoutExpWithoutPoint() {
+    String a = "-732546982374982347892379283571094797287346782359284756";
+    int aScale = 0;
+    BigInteger bA = new BigInteger(
+        "-732546982374982347892379283571094797287346782359284756");
+    BigDecimal aNumber = new BigDecimal(a);
+    assertEquals("incorrect value", bA, aNumber.unscaledValue());
+    assertEquals("incorrect scale", aScale, aNumber.scale());
+  }
+
+  /**
+   * check ONE.
+   */
+  public void testFieldONE() {
+    String oneS = "1";
+    double oneD = 1.0;
+    assertEquals("incorrect string value", oneS, BigDecimal.ONE.toString());
+    assertEquals("incorrect double value", oneD, BigDecimal.ONE.doubleValue(),
+        0);
+  }
+
+  /**
+   * check TEN.
+   */
+  public void testFieldTEN() {
+    String oneS = "10";
+    double oneD = 10.0;
+    assertEquals("incorrect string value", oneS, BigDecimal.TEN.toString());
+    assertEquals("incorrect double value", oneD, BigDecimal.TEN.doubleValue(),
+        0);
+  }
+
+  /**
+   * check ZERO.
+   */
+  public void testFieldZERO() {
+    String oneS = "0";
+    double oneD = 0.0;
+    assertEquals("incorrect string value", oneS, BigDecimal.ZERO.toString());
+    assertEquals("incorrect double value", oneD, BigDecimal.ZERO.doubleValue(),
+        0);
+  }
+
+  private void assertEquals(BigDecimal expected, BigDecimal actual,
+      double delta) {
+    BigDecimal actualDeltaDecimal = actual.subtract(expected);
+    double actualDelta = actualDeltaDecimal.abs().doubleValue();
+    if (actualDelta >= delta) {
+      fail("expected=" + expected + " actual=" + actual + " delta="
+          + actualDelta);
+    }
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/math/BigDecimalConvertTest.java b/user/test/com/google/gwt/emultest/java/math/BigDecimalConvertTest.java
new file mode 100644
index 0000000..0547078
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigDecimalConvertTest.java
@@ -0,0 +1,656 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+/**
+ * Class: java.math.BigDecimal. Methods: doubleValue, floatValue, intValue,
+ * longValue, valueOf, toString, toBigInteger
+ */
+public class BigDecimalConvertTest extends EmulTestBase {
+
+  public void testByteValue() {
+    assertEquals((byte) 1, BigDecimal.ONE.byteValue());
+    assertEquals((byte) -1, BigDecimal.valueOf(255).byteValue());
+    assertEquals((byte) 1, BigDecimal.ONE.byteValueExact());
+    try {
+      BigDecimal.valueOf(255).byteValueExact();
+      fail("Expected ArithmeticException on byteValueExact(255)");
+    } catch (ArithmeticException expected) {
+    }
+  }
+
+  /**
+   * Double value of a small negative BigDecimal.
+   */
+  // TODO(jat): add back after Double.doubleToLongBits is implemented
+//  public void testDoubleValueMinusZero() {
+//    String a = "-123809648392384754573567356745735.63567890295784902768787678287E-400";
+//    BigDecimal aNumber = new BigDecimal(a);
+//    long minusZero = -9223372036854775808L;
+//    double result = aNumber.doubleValue();
+//    assertTrue("incorrect value", Double.doubleToLongBits(result) == minusZero);
+//  }
+
+  /**
+   * Double value of a negative BigDecimal.
+   */
+  public void testDoubleValueNeg() {
+    String a = "-123809648392384754573567356745735.63567890295784902768787678287E+21";
+    BigDecimal aNumber = new BigDecimal(a);
+    double result = -1.2380964839238476E53;
+    assertEquals("incorrect value", result, aNumber.doubleValue(), 0);
+  }
+
+  /**
+   * Double value of a large negative BigDecimal.
+   */
+  public void testDoubleValueNegInfinity() {
+    String a = "-123809648392384754573567356745735.63567890295784902768787678287E+400";
+    BigDecimal aNumber = new BigDecimal(a);
+    double result = Double.NEGATIVE_INFINITY;
+    assertEquals("incorrect value", result, aNumber.doubleValue(), 0);
+  }
+
+  /**
+   * Double value of a small positive BigDecimal.
+   */
+  // TODO(jat): add back after Double.doubleToLongBits is implemented
+//  public void testDoubleValuePlusZero() {
+//    String a = "123809648392384754573567356745735.63567890295784902768787678287E-400";
+//    BigDecimal aNumber = new BigDecimal(a);
+//    long zero = 0;
+//    double result = aNumber.doubleValue();
+//    assertTrue("incorrect value", Double.doubleToLongBits(result) == zero);
+//  }
+
+  /**
+   * Double value of a positive BigDecimal.
+   */
+  public void testDoubleValuePos() {
+    String a = "123809648392384754573567356745735.63567890295784902768787678287E+21";
+    BigDecimal aNumber = new BigDecimal(a);
+    double result = 1.2380964839238476E53;
+    assertEquals("incorrect value", result, aNumber.doubleValue(), 0);
+  }
+
+  /**
+   * Double value of a large positive BigDecimal.
+   */
+  public void testDoubleValuePosInfinity() {
+    String a = "123809648392384754573567356745735.63567890295784902768787678287E+400";
+    BigDecimal aNumber = new BigDecimal(a);
+    double result = Double.POSITIVE_INFINITY;
+    assertEquals("incorrect value", result, aNumber.doubleValue(), 0);
+  }
+
+  /**
+   * Float value of a small negative BigDecimal.
+   */
+  // TODO(jat): add back after Float.floatToIntBits is implemented
+//  public void testFloatValueMinusZero() {
+//    String a = "-123809648392384754573567356745735.63567890295784902768787678287E-400";
+//    BigDecimal aNumber = new BigDecimal(a);
+//    int minusZero = -2147483648;
+//    float result = aNumber.floatValue();
+//    assertTrue("incorrect value", Float.floatToIntBits(result) == minusZero);
+//  }
+
+  /**
+   * Float value of a negative BigDecimal.
+   */
+  public void testFloatValueNeg() {
+    String a = "-1238096483923847.6356789029578E+21";
+    BigDecimal aNumber = new BigDecimal(a);
+    float result = -1.2380965E36F;
+    // Use range rather than exact value check, since GWT uses doubles anyway
+    assertEquals("incorrect value", aNumber.floatValue(), result, 1E29);
+  }
+
+  /**
+   * Float value of a large negative BigDecimal.
+   */
+  public void testFloatValueNegInfinity() {
+    String a = "-123809648392384755735.63567887678287E+200";
+    BigDecimal aNumber = new BigDecimal(a);
+    float result = Float.NEGATIVE_INFINITY;
+    assertTrue("incorrect value", aNumber.floatValue() == result);
+  }
+
+  /**
+   * Float value of a small positive BigDecimal.
+   */
+  // TODO(jat): add back after Float.floatToIntBits is implemented
+//  public void testFloatValuePlusZero() {
+//    String a = "123809648392384754573567356745735.63567890295784902768787678287E-400";
+//    BigDecimal aNumber = new BigDecimal(a);
+//    int zero = 0;
+//    float result = aNumber.floatValue();
+//    assertTrue("incorrect value", Float.floatToIntBits(result) == zero);
+//  }
+
+  /**
+   * Float value of a positive BigDecimal.
+   */
+  public void testFloatValuePos() {
+    String a = "1238096483923847.6356789029578E+21";
+    BigDecimal aNumber = new BigDecimal(a);
+    float result = 1.2380965E36F;
+    // Use range rather than exact value check, since GWT uses doubles anyway
+    assertEquals("incorrect value", aNumber.floatValue(), result, 1E29);
+  }
+
+  /**
+   * Float value of a large positive BigDecimal.
+   */
+  public void testFloatValuePosInfinity() {
+    String a = "123809648373567356745735.6356789787678287E+200";
+    BigDecimal aNumber = new BigDecimal(a);
+    float result = Float.POSITIVE_INFINITY;
+    assertTrue("incorrect value", aNumber.floatValue() == result);
+  }
+
+  /**
+   * Integer value of a negative BigDecimal.
+   */
+  public void testIntValueNeg() {
+    String a = "-123809648392384754573567356745735.63567890295784902768787678287E+21";
+    BigDecimal aNumber = new BigDecimal(a);
+    int result = 218520473;
+    assertEquals("incorrect value", result, aNumber.intValue());
+    try {
+      aNumber.intValueExact();
+      fail("Expected ArithmeticException on intValueExact");
+    } catch (ArithmeticException expected) {
+    }
+  }
+
+  /**
+   * Integer value of a positive BigDecimal.
+   */
+  public void testIntValuePos() {
+    String a = "123809648392384754573567356745735.63567890295784902768787678287E+21";
+    BigDecimal aNumber = new BigDecimal(a);
+    int result = -218520473;
+    assertEquals("incorrect value", result, aNumber.intValue());
+    try {
+      aNumber.intValueExact();
+      fail("Expected ArithmeticException on intValueExact");
+    } catch (ArithmeticException expected) {
+    }
+  }
+
+  /**
+   * Long value of a negative BigDecimal.
+   */
+  public void testLongValueNeg() {
+    String a = "-123809648392384754573567356745735.63567890295784902768787678287E+21";
+    BigDecimal aNumber = new BigDecimal(a);
+    long result = -1246043477766677607L;
+    assertTrue("incorrect value", aNumber.longValue() == result);
+    try {
+      aNumber.longValueExact();
+      fail("Expected ArithmeticException on longValueExact");
+    } catch (ArithmeticException expected) {
+    }
+  }
+
+  /**
+   * Long value of a positive BigDecimal.
+   */
+  public void testLongValuePos() {
+    String a = "123809648392384754573567356745735.63567890295784902768787678287E+21";
+    BigDecimal aNumber = new BigDecimal(a);
+    long result = 1246043477766677607L;
+    assertTrue("incorrect value", aNumber.longValue() == result);
+    try {
+      aNumber.longValueExact();
+      fail("Expected ArithmeticException on longValueExact");
+    } catch (ArithmeticException expected) {
+    }
+  }
+
+  /**
+   * scaleByPowerOfTen(int n).
+   */
+  public void testScaleByPowerOfTen1() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 13;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal result = aNumber.scaleByPowerOfTen(10);
+    String res = "1231212478987482988429808779810457634781384756794.987";
+    int resScale = 3;
+    assertEquals("incorrect value", res, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * scaleByPowerOfTen(int n).
+   */
+  public void testScaleByPowerOfTen2() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = -13;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal result = aNumber.scaleByPowerOfTen(10);
+    String res = "1.231212478987482988429808779810457634781384756794987E+74";
+    int resScale = -23;
+    assertEquals("incorrect value", res, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  public void testShortValue() {
+    BigDecimal value = BigDecimal.valueOf(0x13fff);
+    assertEquals(0x3fff, value.shortValue());
+    try {
+      value.shortValueExact();
+      fail("Expected ArithmeticException");
+    } catch (ArithmeticException expected) {
+    }
+  }
+
+  /**
+   * toBigIntegerExact().
+   */
+  public void testToBigIntegerExact1() {
+    String a = "-123809648392384754573567356745735.63567890295784902768787678287E+45";
+    BigDecimal aNumber = new BigDecimal(a);
+    String res = "-123809648392384754573567356745735635678902957849027687876782870000000000000000";
+    BigInteger result = aNumber.toBigIntegerExact();
+    assertEquals("incorrect value", res, result.toString());
+  }
+
+  /**
+   * toBigIntegerExact().
+   */
+  public void testToBigIntegerExactException() {
+    String a = "-123809648392384754573567356745735.63567890295784902768787678287E-10";
+    BigDecimal aNumber = new BigDecimal(a);
+    try {
+      aNumber.toBigIntegerExact();
+      fail("java.lang.ArithmeticException has not been thrown");
+    } catch (java.lang.ArithmeticException e) {
+      return;
+    }
+  }
+
+  /**
+   * Convert a negative BigDecimal to BigInteger.
+   */
+  public void testToBigIntegerNeg1() {
+    String a = "-123809648392384754573567356745735.63567890295784902768787678287E+21";
+    BigInteger bNumber = new BigInteger(
+        "-123809648392384754573567356745735635678902957849027687");
+    BigDecimal aNumber = new BigDecimal(a);
+    BigInteger result = aNumber.toBigInteger();
+    assertTrue("incorrect value", result.equals(bNumber));
+  }
+
+  /**
+   * Convert a negative BigDecimal to BigInteger.
+   */
+  public void testToBigIntegerNeg2() {
+    String a = "-123809648392384754573567356745735.63567890295784902768787678287E+15";
+    BigInteger bNumber = new BigInteger(
+        "-123809648392384754573567356745735635678902957849");
+    BigDecimal aNumber = new BigDecimal(a);
+    BigInteger result = aNumber.toBigInteger();
+    assertTrue("incorrect value", result.equals(bNumber));
+  }
+
+  /**
+   * Convert a negative BigDecimal to BigInteger.
+   */
+  public void testToBigIntegerNeg3() {
+    String a = "-123809648392384754573567356745735.63567890295784902768787678287E+45";
+    BigInteger bNumber = new BigInteger(
+        "-123809648392384754573567356745735635678902957849027687876782870000000000000000");
+    BigDecimal aNumber = new BigDecimal(a);
+    BigInteger result = aNumber.toBigInteger();
+    assertTrue("incorrect value", result.equals(bNumber));
+  }
+
+  /**
+   * Convert a positive BigDecimal to BigInteger.
+   */
+  public void testToBigIntegerPos1() {
+    String a = "123809648392384754573567356745735.63567890295784902768787678287E+21";
+    BigInteger bNumber = new BigInteger(
+        "123809648392384754573567356745735635678902957849027687");
+    BigDecimal aNumber = new BigDecimal(a);
+    BigInteger result = aNumber.toBigInteger();
+    assertTrue("incorrect value", result.equals(bNumber));
+  }
+
+  /**
+   * Convert a positive BigDecimal to BigInteger.
+   */
+  public void testToBigIntegerPos2() {
+    String a = "123809648392384754573567356745735.63567890295784902768787678287E+15";
+    BigInteger bNumber = new BigInteger(
+        "123809648392384754573567356745735635678902957849");
+    BigDecimal aNumber = new BigDecimal(a);
+    BigInteger result = aNumber.toBigInteger();
+    assertTrue("incorrect value", result.equals(bNumber));
+  }
+
+  /**
+   * Convert a positive BigDecimal to BigInteger.
+   */
+  public void testToBigIntegerPos3() {
+    String a = "123809648392384754573567356745735.63567890295784902768787678287E+45";
+    BigInteger bNumber = new BigInteger(
+        "123809648392384754573567356745735635678902957849027687876782870000000000000000");
+    BigDecimal aNumber = new BigDecimal(a);
+    BigInteger result = aNumber.toBigInteger();
+    assertTrue("incorrect value", result.equals(bNumber));
+  }
+
+  /**
+   * Convert a small BigDecimal to BigInteger.
+   */
+  public void testToBigIntegerZero() {
+    String a = "-123809648392384754573567356745735.63567890295784902768787678287E-500";
+    BigInteger bNumber = new BigInteger("0");
+    BigDecimal aNumber = new BigDecimal(a);
+    BigInteger result = aNumber.toBigInteger();
+    assertTrue("incorrect value", result.equals(bNumber));
+  }
+
+  /**
+   * Convert a negative BigDecimal to an engineering string representation.
+   */
+  public void testToEngineeringStringNeg() {
+    String a = "-123809648392384754573567356745735.63567890295784902768787678287E-501";
+    BigDecimal aNumber = new BigDecimal(a);
+    String result = "-123.80964839238475457356735674573563567890295784902768787678287E-471";
+    assertEquals("incorrect value", result, aNumber.toEngineeringString());
+  }
+
+  /**
+   * Convert a positive BigDecimal to an engineering string representation.
+   */
+  public void testToEngineeringStringPos() {
+    String a = "123809648392384754573567356745735.63567890295784902768787678287E-501";
+    BigDecimal aNumber = new BigDecimal(a);
+    String result = "123.80964839238475457356735674573563567890295784902768787678287E-471";
+    assertEquals("incorrect value", result, aNumber.toEngineeringString());
+  }
+
+  /**
+   * Convert a negative BigDecimal to an engineering string representation.
+   */
+  public void testToEngineeringStringZeroNegExponent() {
+    String a = "0.0E-16";
+    BigDecimal aNumber = new BigDecimal(a);
+    String result = "0.00E-15";
+    assertEquals("incorrect value", result, aNumber.toEngineeringString());
+  }
+
+  /**
+   * Convert a negative BigDecimal to an engineering string representation.
+   */
+  public void testToEngineeringStringZeroPosExponent() {
+    String a = "0.0E+16";
+    BigDecimal aNumber = new BigDecimal(a);
+    String result = "0E+15";
+    assertEquals("incorrect value", result, aNumber.toEngineeringString());
+  }
+
+  /**
+   * Convert a negative BigDecimal with a negative exponent to a plain string
+   * representation; scale == 0.
+   */
+  public void testToPlainStringNegNegExp() {
+    String a = "-123809648392384754573567356745735.63567890295784902768787678287E-100";
+    BigDecimal aNumber = new BigDecimal(a);
+    String result = "-0.000000000000000000000000000000000000000000000000000000000000000000012380964839238475457356735674573563567890295784902768787678287";
+    assertTrue("incorrect value", aNumber.toPlainString().equals(result));
+  }
+
+  /**
+   * Convert a negative BigDecimal with a positive exponent to a plain string
+   * representation; scale == 0.
+   */
+  public void testToPlainStringNegPosExp() {
+    String a = "-123809648392384754573567356745735.63567890295784902768787678287E100";
+    BigDecimal aNumber = new BigDecimal(a);
+    String result = "-1238096483923847545735673567457356356789029578490276878767828700000000000000000000000000000000000000000000000000000000000000000000000";
+    assertTrue("incorrect value", aNumber.toPlainString().equals(result));
+  }
+
+  /**
+   * Convert a positive BigDecimal with a negative exponent to a plain string
+   * representation; scale == 0.
+   */
+  public void testToPlainStringPosNegExp() {
+    String a = "123809648392384754573567356745735.63567890295784902768787678287E-100";
+    BigDecimal aNumber = new BigDecimal(a);
+    String result = "0.000000000000000000000000000000000000000000000000000000000000000000012380964839238475457356735674573563567890295784902768787678287";
+    assertTrue("incorrect value", aNumber.toPlainString().equals(result));
+  }
+
+  /**
+   * Convert a negative BigDecimal with a negative exponent to a plain string
+   * representation; scale == 0.
+   */
+  public void testToPlainStringPosPosExp() {
+    String a = "123809648392384754573567356745735.63567890295784902768787678287E+100";
+    BigDecimal aNumber = new BigDecimal(a);
+    String result = "1238096483923847545735673567457356356789029578490276878767828700000000000000000000000000000000000000000000000000000000000000000000000";
+    assertTrue("incorrect value", aNumber.toPlainString().equals(result));
+  }
+
+  /**
+   * Convert a negative BigDecimal to a string representation.
+   */
+  public void testToStringNeg() {
+    String a = "-123.4564563673567380964839238475457356735674573563567890295784902768787678287E-5";
+    BigDecimal aNumber = new BigDecimal(a);
+    String result = "-0.001234564563673567380964839238475457356735674573563567890295784902768787678287";
+    assertTrue("incorrect value", aNumber.toString().equals(result));
+  }
+
+  /**
+   * Convert a positive BigDecimal to a string representation.
+   */
+  public void testToStringPos() {
+    String a = "123809648392384754573567356745735.63567890295784902768787678287E-500";
+    BigDecimal aNumber = new BigDecimal(a);
+    String result = "1.2380964839238475457356735674573563567890295784902768787678287E-468";
+    assertTrue("incorrect value", aNumber.toString().equals(result));
+  }
+
+  /**
+   * Convert a BigDecimal to a string representation; scale == 0.
+   */
+  public void testToStringZeroScale() {
+    String a = "-123809648392384754573567356745735635678902957849027687876782870";
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a));
+    String result = "-123809648392384754573567356745735635678902957849027687876782870";
+    assertTrue("incorrect value", aNumber.toString().equals(result));
+  }
+
+  /**
+   * valueOf(Double.NaN).
+   */
+  public void testValueOfDoubleNaN() {
+    double a = Double.NaN;
+    try {
+      BigDecimal.valueOf(a);
+      fail("NumberFormatException has not been thrown for Double.NaN");
+    } catch (NumberFormatException e) {
+      return;
+    }
+  }
+
+  /**
+   * Create a BigDecimal from a negative double value.
+   */
+  public void testValueOfDoubleNeg() {
+    double a = -65678765876567576.98788767;
+    BigDecimal result = BigDecimal.valueOf(a);
+    String res = "-65678765876567576";
+    int resScale = 0;
+    assertEquals("incorrect value", res, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Create a BigDecimal from a positive double value.
+   */
+  public void testValueOfDoublePos1() {
+    double a = 65678765876567576.98788767;
+    BigDecimal result = BigDecimal.valueOf(a);
+    String res = "65678765876567576";
+    int resScale = 0;
+    assertEquals("incorrect value", res, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Create a BigDecimal from a positive double value.
+   */
+  public void testValueOfDoublePos2() {
+    double a = 12321237576.98788767;
+    BigDecimal result = BigDecimal.valueOf(a);
+    String res = "12321237576.987888";
+    int resScale = 6;
+    assertEquals("incorrect value", res, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Create a BigDecimal from a positive double value.
+   */
+  public void testValueOfDoublePos3() {
+    double a = 12321237576.9878838;
+    BigDecimal result = BigDecimal.valueOf(a);
+    String res = "12321237576.98788";
+    int resScale = 6;
+    assertTrue("incorrect value", result.toString().startsWith(res));
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Create a BigDecimal from a negative long value; scale is negative.
+   */
+  public void testValueOfNegScaleNeg() {
+    long a = -98374823947823578L;
+    int scale = -12;
+    BigDecimal aNumber = BigDecimal.valueOf(a, scale);
+    String result = "-9.8374823947823578E+28";
+    assertTrue("incorrect value", aNumber.toString().equals(result));
+  }
+
+  /**
+   * Create a BigDecimal from a negative long value; scale is positive.
+   */
+  public void testValueOfNegScalePos() {
+    long a = -98374823947823578L;
+    int scale = 12;
+    BigDecimal aNumber = BigDecimal.valueOf(a, scale);
+    String result = "-98374.823947823578";
+    assertTrue("incorrect value", aNumber.toString().equals(result));
+  }
+
+  /**
+   * Create a BigDecimal from a negative long value; scale is 0.
+   */
+  public void testValueOfNegZeroScale() {
+    long a = -98374823947823578L;
+    BigDecimal aNumber = BigDecimal.valueOf(a);
+    String result = "-98374823947823578";
+    assertTrue("incorrect value", aNumber.toString().equals(result));
+  }
+
+  /**
+   * Create a BigDecimal from a negative long value; scale is negative.
+   */
+  public void testValueOfPosScaleNeg() {
+    long a = 98374823947823578L;
+    int scale = -12;
+    BigDecimal aNumber = BigDecimal.valueOf(a, scale);
+    String result = "9.8374823947823578E+28";
+    assertTrue("incorrect value", aNumber.toString().equals(result));
+  }
+
+  /**
+   * Create a BigDecimal from a negative long value; scale is positive.
+   */
+  public void testValueOfPosScalePos() {
+    long a = 98374823947823578L;
+    int scale = 12;
+    BigDecimal aNumber = BigDecimal.valueOf(a, scale);
+    String result = "98374.823947823578";
+    assertTrue("incorrect value", aNumber.toString().equals(result));
+  }
+
+  /**
+   * Create a BigDecimal from a positive long value; scale == 0.
+   */
+  public void testValueOfPosZeroScale() {
+    long a = 98374823947823578L;
+    BigDecimal aNumber = BigDecimal.valueOf(a);
+    String result = "98374823947823578";
+    assertTrue("incorrect value", aNumber.toString().equals(result));
+  }
+
+  /**
+   * Create a BigDecimal from a zero value; with a small negative scale.
+   */
+  public void testValueOfZeroScaleNeg() {
+    int scale = -2;
+    BigDecimal number = BigDecimal.valueOf(0L, scale);
+    assertEquals("incorrect value", "0E+2", number.toString());
+    assertEquals("bad scale", scale, number.scale());
+  }
+
+  /**
+   * Create a BigDecimal from a zero value; with a small positive scale.
+   */
+  public void testValueOfZeroScalePos() {
+    int scale = 1;
+    BigDecimal number = BigDecimal.valueOf(0L, scale);
+    assertEquals("incorrect value", "0.0", number.toString());
+    assertEquals("bad scale", scale, number.scale());
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/math/BigDecimalScaleOperationsTest.java b/user/test/com/google/gwt/emultest/java/math/BigDecimalScaleOperationsTest.java
new file mode 100644
index 0000000..ab9a5c7
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigDecimalScaleOperationsTest.java
@@ -0,0 +1,377 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+
+/**
+ * Class: java.math.BigDecimal Methods: movePointLeft, movePointRight, scale,
+ * setScale, unscaledValue *
+ */
+public class BigDecimalScaleOperationsTest extends EmulTestBase {
+
+  public void testScaleByPowerOfTen() {
+    BigDecimal val = BigDecimal.ONE.scaleByPowerOfTen(1);
+    assertEquals(10, val.intValue());
+  }
+
+  /**
+   * Check the default scale
+   */
+  public void testScaleDefault() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int cScale = 0;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a));
+    assertTrue("incorrect scale", aNumber.scale() == cScale);
+  }
+
+  /**
+   * Check a negative scale
+   */
+  public void testScaleNeg() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = -10;
+    int cScale = -10;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    assertTrue("incorrect scale", aNumber.scale() == cScale);
+  }
+
+  /**
+   * Check a positive scale
+   */
+  public void testScalePos() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 10;
+    int cScale = 10;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    assertTrue("incorrect scale", aNumber.scale() == cScale);
+  }
+
+  /**
+   * Check the zero scale
+   */
+  public void testScaleZero() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 0;
+    int cScale = 0;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    assertTrue("incorrect scale", aNumber.scale() == cScale);
+  }
+
+  /**
+   * Check the unscaled value
+   */
+  public void testUnscaledValue() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 100;
+    BigInteger bNumber = new BigInteger(a);
+    BigDecimal aNumber = new BigDecimal(bNumber, aScale);
+    assertTrue("incorrect unscaled value", aNumber.unscaledValue().equals(
+        bNumber));
+  }
+
+  /**
+   * Set a greater new scale
+   */
+  public void testSetScaleGreater() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 18;
+    int newScale = 28;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = aNumber.setScale(newScale);
+    assertTrue("incorrect scale", bNumber.scale() == newScale);
+    assertEquals("incorrect value", 0, bNumber.compareTo(aNumber));
+  }
+
+  /**
+   * Set a less new scale; this.scale == 8; newScale == 5.
+   */
+  public void testSetScaleLess() {
+    String a = "2.345726458768760000E+10";
+    int newScale = 5;
+    BigDecimal aNumber = new BigDecimal(a);
+    BigDecimal bNumber = aNumber.setScale(newScale);
+    assertTrue("incorrect scale", bNumber.scale() == newScale);
+    assertEquals("incorrect value", 0, bNumber.compareTo(aNumber));
+  }
+
+  /**
+   * Verify an exception when setting a new scale
+   */
+  public void testSetScaleException() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 28;
+    int newScale = 18;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    try {
+      aNumber.setScale(newScale);
+      fail("ArithmeticException has not been caught");
+    } catch (ArithmeticException e) {
+      assertEquals("Improper exception message", "Rounding necessary",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * Set the same new scale
+   */
+  public void testSetScaleSame() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 18;
+    int newScale = 18;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = aNumber.setScale(newScale);
+    assertTrue("incorrect scale", bNumber.scale() == newScale);
+    assertTrue("incorrect value", bNumber.equals(aNumber));
+  }
+
+  /**
+   * Set a new scale
+   */
+  public void testSetScaleRoundUp() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    String b = "123121247898748298842980877981045763478139";
+    int aScale = 28;
+    int newScale = 18;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = aNumber.setScale(newScale, BigDecimal.ROUND_UP);
+    assertTrue("incorrect scale", bNumber.scale() == newScale);
+    assertTrue("incorrect value", bNumber.unscaledValue().toString().equals(b));
+  }
+
+  /**
+   * Set a new scale
+   */
+  public void testSetScaleRoundDown() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    String b = "123121247898748298842980877981045763478138";
+    int aScale = 28;
+    int newScale = 18;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = aNumber.setScale(newScale, BigDecimal.ROUND_DOWN);
+    assertTrue("incorrect scale", bNumber.scale() == newScale);
+    assertTrue("incorrect value", bNumber.unscaledValue().toString().equals(b));
+  }
+
+  /**
+   * Set a new scale
+   */
+  public void testSetScaleRoundCeiling() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    String b = "123121247898748298842980877981045763478139";
+    int aScale = 28;
+    int newScale = 18;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = aNumber.setScale(newScale, BigDecimal.ROUND_CEILING);
+    assertTrue("incorrect scale", bNumber.scale() == newScale);
+    assertTrue("incorrect value", bNumber.unscaledValue().toString().equals(b));
+  }
+
+  /**
+   * Set a new scale
+   */
+  public void testSetScaleRoundFloor() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    String b = "123121247898748298842980877981045763478138";
+    int aScale = 28;
+    int newScale = 18;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = aNumber.setScale(newScale, BigDecimal.ROUND_FLOOR);
+    assertTrue("incorrect scale", bNumber.scale() == newScale);
+    assertTrue("incorrect value", bNumber.unscaledValue().toString().equals(b));
+  }
+
+  /**
+   * Set a new scale
+   */
+  public void testSetScaleRoundHalfUp() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    String b = "123121247898748298842980877981045763478138";
+    int aScale = 28;
+    int newScale = 18;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = aNumber.setScale(newScale, BigDecimal.ROUND_HALF_UP);
+    assertTrue("incorrect scale", bNumber.scale() == newScale);
+    assertTrue("incorrect value", bNumber.unscaledValue().toString().equals(b));
+  }
+
+  /**
+   * Set a new scale
+   */
+  public void testSetScaleRoundHalfDown() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    String b = "123121247898748298842980877981045763478138";
+    int aScale = 28;
+    int newScale = 18;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = aNumber.setScale(newScale, BigDecimal.ROUND_HALF_DOWN);
+    assertTrue("incorrect scale", bNumber.scale() == newScale);
+    assertTrue("incorrect value", bNumber.unscaledValue().toString().equals(b));
+  }
+
+  /**
+   * Set a new scale
+   */
+  public void testSetScaleRoundHalfEven() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    String b = "123121247898748298842980877981045763478138";
+    int aScale = 28;
+    int newScale = 18;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = aNumber.setScale(newScale, BigDecimal.ROUND_HALF_EVEN);
+    assertTrue("incorrect scale", bNumber.scale() == newScale);
+    assertTrue("incorrect value", bNumber.unscaledValue().toString().equals(b));
+  }
+
+  /**
+   * SetScale(int, RoundingMode)
+   */
+  public void testSetScaleIntRoundingMode() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 28;
+    int newScale = 18;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal result = aNumber.setScale(newScale, RoundingMode.HALF_EVEN);
+    String res = "123121247898748298842980.877981045763478138";
+    int resScale = 18;
+    assertEquals("incorrect value", res, result.toString());
+    assertEquals("incorrect scale", resScale, result.scale());
+  }
+
+  /**
+   * Move the decimal point to the left; the shift value is positive
+   */
+  public void testMovePointLeftPos() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 28;
+    int shift = 18;
+    int resScale = 46;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = aNumber.movePointLeft(shift);
+    assertTrue("incorrect scale", bNumber.scale() == resScale);
+    assertTrue("incorrect value", bNumber.unscaledValue().toString().equals(a));
+  }
+
+  /**
+   * Move the decimal point to the left; the shift value is positive
+   */
+  public void testMovePointLeftNeg() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 28;
+    int shift = -18;
+    int resScale = 10;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = aNumber.movePointLeft(shift);
+    assertTrue("incorrect scale", bNumber.scale() == resScale);
+    assertTrue("incorrect value", bNumber.unscaledValue().toString().equals(a));
+  }
+
+  /**
+   * Move the decimal point to the right; the shift value is positive
+   */
+  public void testMovePointRightPosGreater() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 28;
+    int shift = 18;
+    int resScale = 10;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = aNumber.movePointRight(shift);
+    assertTrue("incorrect scale", bNumber.scale() == resScale);
+    assertTrue("incorrect value", bNumber.unscaledValue().toString().equals(a));
+  }
+
+  /**
+   * Move the decimal point to the right; the shift value is positive
+   */
+  public void testMovePointRightPosLess() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    String b = "123121247898748298842980877981045763478138475679498700";
+    int aScale = 28;
+    int shift = 30;
+    int resScale = 0;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = aNumber.movePointRight(shift);
+    assertTrue("incorrect scale", bNumber.scale() == resScale);
+    assertTrue("incorrect value", bNumber.unscaledValue().toString().equals(b));
+  }
+
+  /**
+   * Move the decimal point to the right; the shift value is positive
+   */
+  public void testMovePointRightNeg() {
+    String a = "1231212478987482988429808779810457634781384756794987";
+    int aScale = 28;
+    int shift = -18;
+    int resScale = 46;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    BigDecimal bNumber = aNumber.movePointRight(shift);
+    assertTrue("incorrect scale", bNumber.scale() == resScale);
+    assertTrue("incorrect value", bNumber.unscaledValue().toString().equals(a));
+  }
+
+  /**
+   * Move the decimal point to the right when the scale overflows
+   */
+  public void testMovePointRightException() {
+    String a = "12312124789874829887348723648726347429808779810457634781384756794987";
+    int aScale = Integer.MAX_VALUE; // 2147483647
+    int shift = -18;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    try {
+      aNumber.movePointRight(shift);
+      fail("ArithmeticException has not been caught");
+    } catch (ArithmeticException e) {
+      assertEquals("Improper exception message", "Underflow", e.getMessage());
+    }
+  }
+
+  /**
+   * precision()
+   */
+  public void testPrecision() {
+    String a = "12312124789874829887348723648726347429808779810457634781384756794987";
+    int aScale = 14;
+    BigDecimal aNumber = new BigDecimal(new BigInteger(a), aScale);
+    int prec = aNumber.precision();
+    assertEquals(68, prec);
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerAddTest.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerAddTest.java
new file mode 100644
index 0000000..aa125d1
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerAddTest.java
@@ -0,0 +1,503 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigInteger;
+
+/**
+ * Class: java.math.BigInteger Method: add
+ */
+public class BigIntegerAddTest extends EmulTestBase {
+
+  /**
+   * Add two positive numbers of the same length
+   */
+  public void testCase1() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {11, 22, 33, 44, 55, 66, 77, 11, 22, 33};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Add two negative numbers of the same length
+   */
+  public void testCase2() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {-12, -23, -34, -45, -56, -67, -78, -12, -23, -33};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Add two numbers of the same length. The first one is positive and the
+   * second is negative. The first one is greater in absolute value.
+   */
+  public void testCase3() {
+    byte aBytes[] = {3, 4, 5, 6, 7, 8, 9};
+    byte bBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    byte rBytes[] = {2, 2, 2, 2, 2, 2, 2};
+    int aSign = 1;
+    int bSign = -1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Add two numbers of the same length. The first one is negative and the
+   * second is positive. The first one is greater in absolute value.
+   */
+  public void testCase4() {
+    byte aBytes[] = {3, 4, 5, 6, 7, 8, 9};
+    byte bBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    byte rBytes[] = {-3, -3, -3, -3, -3, -3, -2};
+    int aSign = -1;
+    int bSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Add two numbers of the same length. The first is positive and the second is
+   * negative. The first is less in absolute value.
+   */
+  public void testCase5() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    byte bBytes[] = {3, 4, 5, 6, 7, 8, 9};
+    byte rBytes[] = {-3, -3, -3, -3, -3, -3, -2};
+    int aSign = 1;
+    int bSign = -1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Add two numbers of the same length. The first one is negative and the
+   * second is positive. The first one is less in absolute value.
+   */
+  public void testCase6() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    byte bBytes[] = {3, 4, 5, 6, 7, 8, 9};
+    byte rBytes[] = {2, 2, 2, 2, 2, 2, 2};
+    int aSign = -1;
+    int bSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Add two positive numbers of different length. The first is longer.
+   */
+  public void testCase7() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {1, 2, 3, 4, 15, 26, 37, 41, 52, 63, 74, 15, 26, 37};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Add two positive numbers of different length. The second is longer.
+   */
+  public void testCase8() {
+    byte aBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    byte bBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7};
+    byte rBytes[] = {1, 2, 3, 4, 15, 26, 37, 41, 52, 63, 74, 15, 26, 37};
+    BigInteger aNumber = new BigInteger(aBytes);
+    BigInteger bNumber = new BigInteger(bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Add two negative numbers of different length. The first is longer.
+   */
+  public void testCase9() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {
+        -2, -3, -4, -5, -16, -27, -38, -42, -53, -64, -75, -16, -27, -37};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Add two negative numbers of different length. The second is longer.
+   */
+  public void testCase10() {
+    byte aBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    byte bBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {
+        -2, -3, -4, -5, -16, -27, -38, -42, -53, -64, -75, -16, -27, -37};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Add two numbers of different length and sign. The first is positive. The
+   * first is longer.
+   */
+  public void testCase11() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {1, 2, 3, 3, -6, -15, -24, -40, -49, -58, -67, -6, -15, -23};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Add two numbers of different length and sign. The first is positive. The
+   * second is longer.
+   */
+  public void testCase12() {
+    byte aBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    byte bBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Add two numbers of different length and sign. The first is negative. The
+   * first is longer.
+   */
+  public void testCase13() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Add two numbers of different length and sign. The first is negative. The
+   * second is longer.
+   */
+  public void testCase14() {
+    byte aBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    byte bBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {1, 2, 3, 3, -6, -15, -24, -40, -49, -58, -67, -6, -15, -23};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Add two equal numbers of different signs
+   */
+  public void testCase15() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    byte bBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    byte rBytes[] = {0};
+    int aSign = -1;
+    int bSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * Add zero to a number
+   */
+  public void testCase16() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    byte bBytes[] = {0};
+    byte rBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    int aSign = 1;
+    int bSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Add a number to zero
+   */
+  public void testCase17() {
+    byte aBytes[] = {0};
+    byte bBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    byte rBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    int aSign = 1;
+    int bSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Add zero to zero
+   */
+  public void testCase18() {
+    byte aBytes[] = {0};
+    byte bBytes[] = {0};
+    byte rBytes[] = {0};
+    int aSign = 1;
+    int bSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * Add ZERO to a number
+   */
+  public void testCase19() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    byte rBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    int aSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = BigInteger.ZERO;
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Add a number to zero
+   */
+  public void testCase20() {
+    byte bBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    byte rBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    int bSign = 1;
+    BigInteger aNumber = BigInteger.ZERO;
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Add ZERO to ZERO
+   */
+  public void testCase21() {
+    byte rBytes[] = {0};
+    BigInteger aNumber = BigInteger.ZERO;
+    BigInteger bNumber = BigInteger.ZERO;
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * Add ONE to ONE
+   */
+  public void testCase22() {
+    byte rBytes[] = {2};
+    BigInteger aNumber = BigInteger.ONE;
+    BigInteger bNumber = BigInteger.ONE;
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Add two numbers so that carry is 1
+   */
+  public void testCase23() {
+    byte aBytes[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+    byte bBytes[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {1, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -2};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.add(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerAndTest.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerAndTest.java
new file mode 100644
index 0000000..d1db148
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerAndTest.java
@@ -0,0 +1,475 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigInteger;
+
+/**
+ * Class: java.math.BigInteger Method: and
+ */
+public class BigIntegerAndTest extends EmulTestBase {
+
+  /**
+   * And for two negative numbers; the first is longer
+   */
+  public void testNegNegFirstLonger() {
+    byte aBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {
+        -1, 127, -10, -57, -101, 1, 2, 2, 2, -96, -16, 8, -40, -59, 68, -88,
+        -88, 16, 73};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * And for two negative numbers; the first is shorter
+   */
+  public void testNegNegFirstShorter() {
+    byte aBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    byte bBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {
+        -1, 127, -10, -57, -101, 1, 2, 2, 2, -96, -16, 8, -40, -59, 68, -88,
+        -88, 16, 73};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * And for two negative numbers of the same length
+   */
+  public void testNegNegSameLength() {
+    byte aBytes[] = {-128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {
+        -1, 1, 2, 3, 3, 0, 65, -96, -48, -124, -60, 12, -40, -31, 97};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * And for a negative number and zero
+   */
+  public void testNegPos() {
+    byte aBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    byte bBytes[] = {0};
+    int aSign = -1;
+    int bSign = 0;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * And for a negative and a positive numbers; the first is longer
+   */
+  public void testNegPosFirstLonger() {
+    byte aBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {73, -92, -48, 4, 12, 6, 4, 32, 48, 64, 0, 8, 3};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * And for a negative and a positive numbers; the first is shorter
+   */
+  public void testNegPosFirstShorter() {
+    byte aBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    byte bBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {
+        0, -128, 9, 56, 100, 0, 0, 1, 1, 90, 1, -32, 0, 10, -126, 21, 82, -31,
+        -95};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * And for two numbers of different signs and the same length
+   */
+  public void testNegPosSameLength() {
+    byte aBytes[] = {-128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {0, -2, 125, -60, -104, 1, 10, 6, 2, 32, 56, 2, 4, 4, 21};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * And for one and one
+   */
+  public void testOneOne() {
+    BigInteger aNumber = BigInteger.ONE;
+    BigInteger bNumber = BigInteger.ONE;
+    BigInteger result = aNumber.and(bNumber);
+    assertTrue(result.equals(BigInteger.ONE));
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * And for a positive and a negative numbers; the first is longer
+   */
+  public void testPosNegFirstLonger() {
+    byte aBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {
+        0, -128, 9, 56, 100, 0, 0, 1, 1, 90, 1, -32, 0, 10, -126, 21, 82, -31,
+        -95};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * And for a positive and a negative numbers; the first is shorter
+   */
+  public void testPosNegFirstShorter() {
+    byte aBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    byte bBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {73, -92, -48, 4, 12, 6, 4, 32, 48, 64, 0, 8, 3};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * And for two numbers of different signs and the same length
+   */
+  public void testPosNegSameLength() {
+    byte aBytes[] = {-128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {0, -6, -80, 72, 8, 75, 2, -79, 34, 16, -119};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * And for two positive numbers; the first is longer
+   */
+  public void testPosPosFirstLonger() {
+    byte aBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {0, -2, -76, 88, 44, 1, 2, 17, 35, 16, 9, 2, 5, 6, 21};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * And for two positive numbers; the first is shorter
+   */
+  public void testPosPosFirstShorter() {
+    byte aBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    byte bBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {0, -2, -76, 88, 44, 1, 2, 17, 35, 16, 9, 2, 5, 6, 21};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * And for two positive numbers of the same length
+   */
+  public void testPosPosSameLength() {
+    byte aBytes[] = {-128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {0, -128, 56, 100, 4, 4, 17, 37, 16, 1, 64, 1, 10, 3};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * And for a positive number and zero
+   */
+  public void testPosZero() {
+    byte aBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    byte bBytes[] = {0};
+    int aSign = 1;
+    int bSign = 0;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * Test for a special case
+   */
+  public void testSpecialCase1() {
+    byte aBytes[] = {-1, -1, -1, -1};
+    byte bBytes[] = {5, -4, -3, -2};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {-1, 0, 0, 0, 0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Test for a special case
+   */
+  public void testSpecialCase2() {
+    byte aBytes[] = {-51};
+    byte bBytes[] = {-52, -51, -50, -49, -48};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {0, -52, -51, -50, -49, 16};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * And for zero and a negative number
+   */
+  public void testZeroNeg() {
+    byte aBytes[] = {0};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = 0;
+    int bSign = -1;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * And for zero and one
+   */
+  public void testZeroOne() {
+    BigInteger aNumber = BigInteger.ZERO;
+    BigInteger bNumber = BigInteger.ONE;
+    BigInteger result = aNumber.and(bNumber);
+    assertTrue(result.equals(BigInteger.ZERO));
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * And for zero and a positive number
+   */
+  public void testZeroPos() {
+    byte aBytes[] = {0};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = 0;
+    int bSign = 1;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * And for zero and zero
+   */
+  public void testZeroZero() {
+    byte aBytes[] = {0};
+    byte bBytes[] = {0};
+    int aSign = 0;
+    int bSign = 0;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.and(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerCompareTest.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerCompareTest.java
new file mode 100644
index 0000000..8b56def
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerCompareTest.java
@@ -0,0 +1,530 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigInteger;
+
+/**
+ * Class: java.math.BigInteger Methods: abs, compareTo, equals, max, min,
+ * negate, signum
+ */
+public class BigIntegerCompareTest extends EmulTestBase {
+  /**
+   * abs() for a negative number
+   */
+  public void testAbsNegative() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    int aSign = -1;
+    byte rBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.abs();
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * abs() for a positive number
+   */
+  public void testAbsPositive() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    int aSign = 1;
+    byte rBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.abs();
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * compareTo(BigInteger a). Compare two negative numbers. The first is less in
+   * absolute value.
+   */
+  public void testCompareNegNeg2() {
+    byte aBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    byte bBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = -1;
+    int bSign = -1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    assertEquals(1, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * compareTo(BigInteger a). Compare two numbers of different signs. The first
+   * is positive.
+   */
+  public void testCompareToDiffSigns1() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = 1;
+    int bSign = -1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    assertEquals(1, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * compareTo(BigInteger a). Compare two numbers of different signs. The first
+   * is negative.
+   */
+  public void testCompareToDiffSigns2() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = -1;
+    int bSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    assertEquals(-1, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * compareTo(BigInteger a). Compare two equal negative numbers.
+   */
+  public void testCompareToEqualNeg() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    byte bBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = -1;
+    int bSign = -1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    assertEquals(0, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * compareTo(BigInteger a). Compare two equal positive numbers.
+   */
+  public void testCompareToEqualPos() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    byte bBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = 1;
+    int bSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    assertEquals(0, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * compareTo(BigInteger a). Compare two negative numbers. The first is greater
+   * in absolute value.
+   */
+  public void testCompareToNegNeg1() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = -1;
+    int bSign = -1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    assertEquals(-1, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * compareTo(BigInteger a). Compare a negative number to ZERO.
+   */
+  public void testCompareToNegZero() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = -1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = BigInteger.ZERO;
+    assertEquals(-1, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * compareTo(BigInteger a). Compare two positive numbers. The first is
+   * greater.
+   */
+  public void testCompareToPosPos1() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = 1;
+    int bSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    assertEquals(1, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * compareTo(BigInteger a). Compare two positive numbers. The first is less.
+   */
+  public void testCompareToPosPos2() {
+    byte aBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    byte bBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = 1;
+    int bSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    assertEquals(-1, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * compareTo(BigInteger a). Compare a positive number to ZERO.
+   */
+  public void testCompareToPosZero() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = BigInteger.ZERO;
+    assertEquals(1, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * compareTo(BigInteger a). Compare ZERO to a negative number.
+   */
+  public void testCompareToZeroNeg() {
+    byte bBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int bSign = -1;
+    BigInteger aNumber = BigInteger.ZERO;
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    assertEquals(1, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * compareTo(BigInteger a). Compare ZERO to a positive number.
+   */
+  public void testCompareToZeroPos() {
+    byte bBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int bSign = 1;
+    BigInteger aNumber = BigInteger.ZERO;
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    assertEquals(-1, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * compareTo(BigInteger a). Compare ZERO to ZERO.
+   */
+  public void testCompareToZeroZero() {
+    BigInteger aNumber = BigInteger.ZERO;
+    BigInteger bNumber = BigInteger.ZERO;
+    assertEquals(0, aNumber.compareTo(bNumber));
+  }
+
+  /**
+   * equals(Object obj). obj is a BigInteger. numbers are not equal.
+   */
+  public void testEqualsBigIntegerFalse() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    byte bBytes[] = {45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = 1;
+    int bSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    Object bNumber = new BigInteger(bSign, bBytes);
+    assertFalse(aNumber.equals(bNumber));
+  }
+
+  /**
+   * equals(Object obj). obj is a BigInteger. numbers are equal.
+   */
+  public void testEqualsBigIntegerTrue() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    byte bBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = 1;
+    int bSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    Object bNumber = new BigInteger(bSign, bBytes);
+    assertTrue(aNumber.equals(bNumber));
+  }
+
+  /**
+   * equals(null).
+   */
+  public void testEqualsNull() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    assertFalse(aNumber.equals(null));
+  }
+
+  /**
+   * equals(Object obj). obj is not a BigInteger
+   */
+  public void testEqualsObject() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    Object obj = new Object();
+    assertFalse(aNumber.equals(obj));
+  }
+
+  /**
+   * max(BigInteger val). numbers are equal.
+   */
+  public void testMaxEqual() {
+    byte aBytes[] = {45, 91, 3, -15, 35, 26, 3, 91};
+    byte bBytes[] = {45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {45, 91, 3, -15, 35, 26, 3, 91};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.max(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * max(BigInteger val). the first is greater.
+   */
+  public void testMaxGreater() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    byte bBytes[] = {45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.max(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertTrue("incorrect sign", result.signum() == 1);
+    result =  bNumber.max(aNumber);
+    assertEquals(aNumber, result);
+  }
+
+  /**
+   * max(BigInteger val). the first is less.
+   */
+  public void testMaxLess() {
+    byte aBytes[] = {45, 91, 3, -15, 35, 26, 3, 91};
+    byte bBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.max(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertTrue("incorrect sign", result.signum() == 1);
+  }
+
+  /**
+   * max(BigInteger val). max of negative and ZERO.
+   */
+  public void testMaxNegZero() {
+    byte aBytes[] = {45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = -1;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = BigInteger.ZERO;
+    BigInteger result = aNumber.max(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertTrue("incorrect sign", result.signum() == 0);
+  }
+
+  /**
+   * min(BigInteger val). numbers are equal.
+   */
+  public void testMinEqual() {
+    byte aBytes[] = {45, 91, 3, -15, 35, 26, 3, 91};
+    byte bBytes[] = {45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {45, 91, 3, -15, 35, 26, 3, 91};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.min(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertTrue("incorrect sign", result.signum() == 1);
+  }
+
+  /**
+   * min(BigInteger val). the first is greater.
+   */
+  public void testMinGreater() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    byte bBytes[] = {45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {45, 91, 3, -15, 35, 26, 3, 91};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.min(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * min(BigInteger val). the first is less.
+   */
+  public void testMinLess() {
+    byte aBytes[] = {45, 91, 3, -15, 35, 26, 3, 91};
+    byte bBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {45, 91, 3, -15, 35, 26, 3, 91};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.min(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * max(BigInteger val). min of positive and ZERO.
+   */
+  public void testMinPosZero() {
+    byte aBytes[] = {45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = 1;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = BigInteger.ZERO;
+    BigInteger result = aNumber.min(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertTrue("incorrect sign", result.signum() == 0);
+  }
+
+  /**
+   * negate() a negative number.
+   */
+  public void testNegateNegative() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = -1;
+    byte rBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.negate();
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+
+    assertTrue("incorrect sign", result.signum() == 1);
+  }
+
+  /**
+   * negate() a positive number.
+   */
+  public void testNegatePositive() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = 1;
+    byte rBytes[] = {
+        -13, -57, -101, 1, 75, -90, -46, -92, -4, 14, -36, -27, -4, -91};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.negate();
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertTrue("incorrect sign", result.signum() == -1);
+  }
+
+  /**
+   * negate() ZERO.
+   */
+  public void testNegateZero() {
+    byte rBytes[] = {0};
+    BigInteger aNumber = BigInteger.ZERO;
+    BigInteger result = aNumber.negate();
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * signum() of a negative number.
+   */
+  public void testSignumNegative() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = -1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    assertEquals("incorrect sign", -1, aNumber.signum());
+  }
+
+  /**
+   * signum() of a positive number.
+   */
+  public void testSignumPositive() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * signum() of ZERO.
+   */
+  public void testSignumZero() {
+    BigInteger aNumber = BigInteger.ZERO;
+    assertEquals("incorrect sign", 0, aNumber.signum());
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerConstructorsTest.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerConstructorsTest.java
new file mode 100644
index 0000000..6024e6f
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerConstructorsTest.java
@@ -0,0 +1,779 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigInteger;
+import java.util.Random;
+
+/**
+ * Class: java.math.BigInteger Constructors: BigInteger(byte[] a),
+ * BigInteger(int sign, byte[] a), BigInteger(String val, int radix)
+ */
+public class BigIntegerConstructorsTest extends EmulTestBase {
+  /**
+   * Create a number from an array of bytes. Verify an exception thrown if an
+   * array is zero bytes long
+   */
+  public void testConstructorBytesException() {
+    byte aBytes[] = {};
+    try {
+      new BigInteger(aBytes);
+      fail("NumberFormatException has not been caught");
+    } catch (NumberFormatException e) {
+      assertEquals("Improper exception message", "Zero length BigInteger",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * Create a negative number from an array of bytes. The number fits in an
+   * array of integers.
+   */
+  public void testConstructorBytesNegative1() {
+    byte aBytes[] = {-12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    byte rBytes[] = {-12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    BigInteger aNumber = new BigInteger(aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, aNumber.signum());
+  }
+
+  /**
+   * Create a negative number from an array of bytes. The number fits in an
+   * integer.
+   */
+  public void testConstructorBytesNegative2() {
+    byte aBytes[] = {-12, 56, 100};
+    byte rBytes[] = {-12, 56, 100};
+    BigInteger aNumber = new BigInteger(aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, aNumber.signum());
+  }
+
+  /**
+   * Create a negative number from an array of bytes. The number of bytes is 4.
+   */
+  public void testConstructorBytesNegative3() {
+    byte aBytes[] = {-128, -12, 56, 100};
+    byte rBytes[] = {-128, -12, 56, 100};
+    BigInteger aNumber = new BigInteger(aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, aNumber.signum());
+  }
+
+  /**
+   * Create a negative number from an array of bytes. The number of bytes is
+   * multiple of 4.
+   */
+  public void testConstructorBytesNegative4() {
+    byte aBytes[] = {-128, -12, 56, 100, -13, 56, 93, -78};
+    byte rBytes[] = {-128, -12, 56, 100, -13, 56, 93, -78};
+    BigInteger aNumber = new BigInteger(aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, aNumber.signum());
+  }
+
+  /**
+   * Create a positive number from an array of bytes. The number of bytes is
+   * multiple of 4.
+   */
+  public void testConstructorBytesPositive() {
+    byte aBytes[] = {127, 56, 100, -1, 14, 75, -24, -100};
+    byte rBytes[] = {127, 56, 100, -1, 14, 75, -24, -100};
+    BigInteger aNumber = new BigInteger(aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * Create a positive number from an array of bytes. The number fits in an
+   * array of integers.
+   */
+  public void testConstructorBytesPositive1() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    byte rBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    BigInteger aNumber = new BigInteger(aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * Create a positive number from an array of bytes. The number fits in an
+   * integer.
+   */
+  public void testConstructorBytesPositive2() {
+    byte aBytes[] = {12, 56, 100};
+    byte rBytes[] = {12, 56, 100};
+    BigInteger aNumber = new BigInteger(aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * Create a positive number from an array of bytes. The number of bytes is 4.
+   */
+  public void testConstructorBytesPositive3() {
+    byte aBytes[] = {127, 56, 100, -1};
+    byte rBytes[] = {127, 56, 100, -1};
+    BigInteger aNumber = new BigInteger(aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * Create a zero number from an array of zero bytes.
+   */
+  public void testConstructorBytesZero() {
+    byte aBytes[] = {0, 0, 0, -0, +0, 0, -0};
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, aNumber.signum());
+  }
+
+  /**
+   * Create a prime number of 25 bits length.
+   */
+  public void testConstructorPrime() {
+    int bitLen = 25;
+    Random rnd = new Random();
+    BigInteger aNumber = new BigInteger(bitLen, 80, rnd);
+    assertTrue("incorrect bitLength", aNumber.bitLength() == bitLen);
+  }
+
+  /**
+   * Create a prime number of 2 bits length.
+   */
+  public void testConstructorPrime2() {
+    int bitLen = 2;
+    Random rnd = new Random();
+    BigInteger aNumber = new BigInteger(bitLen, 80, rnd);
+    assertTrue("incorrect bitLength", aNumber.bitLength() == bitLen);
+    int num = aNumber.intValue();
+    assertTrue("incorrect value", num == 2 || num == 3);
+  }
+
+  /**
+   * Create a random number of 75 bits length.
+   */
+  public void testConstructorRandom() {
+    int bitLen = 75;
+    Random rnd = new Random();
+    BigInteger aNumber = new BigInteger(bitLen, rnd);
+    assertTrue("incorrect bitLength", aNumber.bitLength() <= bitLen);
+  }
+
+  /**
+   * Create a number from a sign and an array of bytes. Verify an exception
+   * thrown if a sign has improper value.
+   */
+  public void testConstructorSignBytesException1() {
+    byte aBytes[] = {123, 45, -3, -76};
+    int aSign = 3;
+    try {
+      new BigInteger(aSign, aBytes);
+      fail("NumberFormatException has not been caught");
+    } catch (NumberFormatException e) {
+      assertEquals("Improper exception message", "Invalid signum value",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * Create a number from a sign and an array of bytes. Verify an exception
+   * thrown if the array contains non-zero bytes while the sign is 0.
+   */
+  public void testConstructorSignBytesException2() {
+    byte aBytes[] = {123, 45, -3, -76};
+    int aSign = 0;
+    try {
+      new BigInteger(aSign, aBytes);
+      fail("NumberFormatException has not been caught");
+    } catch (NumberFormatException e) {
+      assertEquals("Improper exception message", "signum-magnitude mismatch",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * Create a negative number from a sign and an array of bytes. The number fits
+   * in an array of integers. The most significant byte is positive.
+   */
+  public void testConstructorSignBytesNegative1() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15};
+    int aSign = -1;
+    byte rBytes[] = {-13, -57, -101, 1, 75, -90, -46, -92, -4, 15};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, aNumber.signum());
+  }
+
+  /**
+   * Create a negative number from a sign and an array of bytes. The number fits
+   * in an array of integers. The most significant byte is negative.
+   */
+  public void testConstructorSignBytesNegative2() {
+    byte aBytes[] = {-12, 56, 100, -2, -76, 89, 45, 91, 3, -15};
+    int aSign = -1;
+    byte rBytes[] = {-1, 11, -57, -101, 1, 75, -90, -46, -92, -4, 15};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, aNumber.signum());
+  }
+
+  /**
+   * Create a negative number from a sign and an array of bytes. The number fits
+   * in an integer.
+   */
+  public void testConstructorSignBytesNegative3() {
+    byte aBytes[] = {-12, 56, 100};
+    int aSign = -1;
+    byte rBytes[] = {-1, 11, -57, -100};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, aNumber.signum());
+  }
+
+  /**
+   * Create a negative number from a sign and an array of bytes. The number of
+   * bytes is 4. The most significant byte is positive.
+   */
+  public void testConstructorSignBytesNegative4() {
+    byte aBytes[] = {127, 56, 100, -2};
+    int aSign = -1;
+    byte rBytes[] = {-128, -57, -101, 2};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, aNumber.signum());
+  }
+
+  /**
+   * Create a negative number from a sign and an array of bytes. The number of
+   * bytes is 4. The most significant byte is negative.
+   */
+  public void testConstructorSignBytesNegative5() {
+    byte aBytes[] = {-127, 56, 100, -2};
+    int aSign = -1;
+    byte rBytes[] = {-1, 126, -57, -101, 2};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, aNumber.signum());
+  }
+
+  /**
+   * Create a negative number from a sign and an array of bytes. The number of
+   * bytes is multiple of 4. The most significant byte is positive.
+   */
+  public void testConstructorSignBytesNegative6() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 23, -101};
+    int aSign = -1;
+    byte rBytes[] = {-13, -57, -101, 1, 75, -90, -46, -92, -4, 14, -24, 101};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, aNumber.signum());
+  }
+
+  /**
+   * Create a negative number from a sign and an array of bytes. The number of
+   * bytes is multiple of 4. The most significant byte is negative.
+   */
+  public void testConstructorSignBytesNegative7() {
+    byte aBytes[] = {-12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 23, -101};
+    int aSign = -1;
+    byte rBytes[] = {-1, 11, -57, -101, 1, 75, -90, -46, -92, -4, 14, -24, 101};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, aNumber.signum());
+  }
+
+  /**
+   * Create a positive number from a sign and an array of bytes. The number fits
+   * in an array of integers. The most significant byte is positive.
+   */
+  public void testConstructorSignBytesPositive1() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15};
+    int aSign = 1;
+    byte rBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * Create a positive number from a sign and an array of bytes. The number fits
+   * in an array of integers. The most significant byte is negative.
+   */
+  public void testConstructorSignBytesPositive2() {
+    byte aBytes[] = {-12, 56, 100, -2, -76, 89, 45, 91, 3, -15};
+    int aSign = 1;
+    byte rBytes[] = {0, -12, 56, 100, -2, -76, 89, 45, 91, 3, -15};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * Create a positive number from a sign and an array of bytes. The number fits
+   * in an integer.
+   */
+  public void testConstructorSignBytesPositive3() {
+    byte aBytes[] = {-12, 56, 100};
+    int aSign = 1;
+    byte rBytes[] = {0, -12, 56, 100};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * Create a positive number from a sign and an array of bytes. The number of
+   * bytes is 4. The most significant byte is positive.
+   */
+  public void testConstructorSignBytesPositive4() {
+    byte aBytes[] = {127, 56, 100, -2};
+    int aSign = 1;
+    byte rBytes[] = {127, 56, 100, -2};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * Create a positive number from a sign and an array of bytes. The number of
+   * bytes is 4. The most significant byte is negative.
+   */
+  public void testConstructorSignBytesPositive5() {
+    byte aBytes[] = {-127, 56, 100, -2};
+    int aSign = 1;
+    byte rBytes[] = {0, -127, 56, 100, -2};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * Create a positive number from a sign and an array of bytes. The number of
+   * bytes is multiple of 4. The most significant byte is positive.
+   */
+  public void testConstructorSignBytesPositive6() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 23, -101};
+    int aSign = 1;
+    byte rBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 23, -101};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * Create a positive number from a sign and an array of bytes. The number of
+   * bytes is multiple of 4. The most significant byte is negative.
+   */
+  public void testConstructorSignBytesPositive7() {
+    byte aBytes[] = {-12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 23, -101};
+    int aSign = 1;
+    byte rBytes[] = {0, -12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 23, -101};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * Create a zero number from a sign and an array of zero bytes. The sign is
+   * -1.
+   */
+  public void testConstructorSignBytesZero1() {
+    byte aBytes[] = {-0, 0, +0, 0, 0, 00, 000};
+    int aSign = -1;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, aNumber.signum());
+  }
+
+  /**
+   * Create a zero number from a sign and an array of zero bytes. The sign is 0.
+   */
+  public void testConstructorSignBytesZero2() {
+    byte aBytes[] = {-0, 0, +0, 0, 0, 00, 000};
+    int aSign = 0;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, aNumber.signum());
+  }
+
+  /**
+   * Create a zero number from a sign and an array of zero bytes. The sign is 1.
+   */
+  public void testConstructorSignBytesZero3() {
+    byte aBytes[] = {-0, 0, +0, 0, 0, 00, 000};
+    int aSign = 1;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, aNumber.signum());
+  }
+
+  /**
+   * Create a zero number from a sign and an array of zero length. The sign is
+   * -1.
+   */
+  public void testConstructorSignBytesZeroNull1() {
+    byte aBytes[] = {};
+    int aSign = -1;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, aNumber.signum());
+  }
+
+  /**
+   * Create a zero number from a sign and an array of zero length. The sign is
+   * 0.
+   */
+  public void testConstructorSignBytesZeroNull2() {
+    byte aBytes[] = {};
+    int aSign = 0;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, aNumber.signum());
+  }
+
+  /**
+   * Create a zero number from a sign and an array of zero length. The sign is
+   * 1.
+   */
+  public void testConstructorSignBytesZeroNull3() {
+    byte aBytes[] = {};
+    int aSign = 1;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, aNumber.signum());
+  }
+
+  /**
+   * Create a number from a string value and radix. Verify an exception thrown
+   * if a radix is out of range
+   */
+  public void testConstructorStringException1() {
+    String value = "9234853876401";
+    int radix = 45;
+    try {
+      new BigInteger(value, radix);
+      fail("NumberFormatException has not been caught");
+    } catch (NumberFormatException e) {
+      assertEquals("Improper exception message", "Radix out of range",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * Create a number from a string value and radix. Verify an exception thrown
+   * if the string starts with a space.
+   */
+  public void testConstructorStringException2() {
+    String value = "   9234853876401";
+    int radix = 10;
+    try {
+      new BigInteger(value, radix);
+      fail("NumberFormatException has not been caught");
+    } catch (NumberFormatException e) {
+    }
+  }
+
+  /**
+   * Create a number from a string value and radix. Verify an exception thrown
+   * if the string contains improper characters.
+   */
+  public void testConstructorStringException3() {
+    String value = "92348$*#78987";
+    int radix = 34;
+    try {
+      new BigInteger(value, radix);
+      fail("NumberFormatException has not been caught");
+    } catch (NumberFormatException e) {
+    }
+  }
+
+  /**
+   * Create a number from a string value and radix. Verify an exception thrown
+   * if some digits are greater than radix.
+   */
+  public void testConstructorStringException4() {
+    String value = "98zv765hdsaiy";
+    int radix = 20;
+    try {
+      new BigInteger(value, radix);
+      fail("NumberFormatException has not been caught");
+    } catch (NumberFormatException e) {
+    }
+  }
+
+  /**
+   * Create a positive number from a string value and radix 10.
+   */
+  public void testConstructorStringRadix10() {
+    String value = "987328901348934898";
+    int radix = 10;
+    byte rBytes[] = {13, -77, -78, 103, -103, 97, 68, -14};
+    BigInteger aNumber = new BigInteger(value, radix);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * Create a negative number from a string value and radix 10.
+   */
+  public void testConstructorStringRadix10Negative() {
+    String value = "-234871376037";
+    int radix = 36;
+    byte rBytes[] = {-4, 48, 71, 62, -76, 93, -105, 13};
+    BigInteger aNumber = new BigInteger(value, radix);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, aNumber.signum());
+  }
+
+  /**
+   * Create a zero number from a string value and radix 36.
+   */
+  public void testConstructorStringRadix10Zero() {
+    String value = "-00000000000000";
+    int radix = 10;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(value, radix);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, aNumber.signum());
+  }
+
+  /**
+   * Create a positive number from a string value and radix 16.
+   */
+  public void testConstructorStringRadix16() {
+    String value = "fe2340a8b5ce790";
+    int radix = 16;
+    byte rBytes[] = {15, -30, 52, 10, -117, 92, -25, -112};
+    BigInteger aNumber = new BigInteger(value, radix);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * Create a positive number from a string value and radix 2.
+   */
+  public void testConstructorStringRadix2() {
+    String value = "10101010101010101";
+    int radix = 2;
+    byte rBytes[] = {1, 85, 85};
+    BigInteger aNumber = new BigInteger(value, radix);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * Create a positive number from a string value and radix 36.
+   */
+  public void testConstructorStringRadix36() {
+    String value = "skdjgocvhdjfkl20jndjkf347ejg457";
+    int radix = 36;
+    byte rBytes[] = {
+        0, -12, -116, 112, -105, 12, -36, 66, 108, 66, -20, -37, -15, 108, -7,
+        52, -99, -109, -8, -45, -5};
+    BigInteger aNumber = new BigInteger(value, radix);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * Create a positive number from a string value and radix 8.
+   */
+  public void testConstructorStringRadix8() {
+    String value = "76356237071623450";
+    int radix = 8;
+    byte rBytes[] = {7, -50, -28, -8, -25, 39, 40};
+    BigInteger aNumber = new BigInteger(value, radix);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerConvertTest.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerConvertTest.java
new file mode 100644
index 0000000..df634f5
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerConvertTest.java
@@ -0,0 +1,811 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigInteger;
+
+/**
+ * Class: java.math.BigInteger Methods: intValue, longValue, toByteArray(),
+ * valueOf(long val), floatValue(), doubleValue()
+ */
+public class BigIntegerConvertTest extends EmulTestBase {
+  /**
+   * Convert a negative number to a double value. The number's bit length is
+   * less than 64 bits.
+   */
+  public void testDoubleValueNegative1() {
+    String a = "-27467238945";
+    double result = -2.7467238945E10;
+    double aNumber = new BigInteger(a).doubleValue();
+    assertTrue(aNumber == result);
+  }
+
+  /**
+   * Convert a negative number to a double value. The number's bit length is
+   * inside [63, 1024].
+   */
+  public void testDoubleValueNegative2() {
+    String a = "-2746723894572364578265426346273456972";
+    double result = -2.7467238945723645E36;
+    double aNumber = new BigInteger(a).doubleValue();
+    assertTrue(aNumber == result);
+  }
+
+  /**
+   * Convert a negative number to a double value. The number's bit length is
+   * greater than 1024.
+   */
+  public void testDoubleValueNegativeInfinity1() {
+    String a = "-2746723894572364578265426346273456972283746872364768676747462342342342342342342342323423423423423423426767456345745293762384756238475634563456845634568934568347586346578648576478568456457634875673845678456786587345873645767456834756745763457863485768475678465783456702897830296720476846578634576384567845678346573465786457863";
+    double aNumber = new BigInteger(a).doubleValue();
+    assertTrue(aNumber == Double.NEGATIVE_INFINITY);
+  }
+
+  /**
+   * Convert a negative number to a double value. The exponent is 1023 and the
+   * mantissa is all 0s. The rounding bit is 0. The result is
+   * Double.NEGATIVE_INFINITY.
+   */
+  public void testDoubleValueNegativeInfinity2() {
+    byte[] a = {
+        -1, -1, -1, -1, -1, -1, -1, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    int aSign = -1;
+    double aNumber = new BigInteger(aSign, a).doubleValue();
+    assertTrue(aNumber == Double.NEGATIVE_INFINITY);
+  }
+
+  /**
+   * Convert a positive number to a double value. The exponent is 1023 and the
+   * mantissa is all 0s but the 54th bit (implicit) is 1.
+   */
+  public void testDoubleValueNegMantissaIsZero() {
+    byte[] a = {
+        -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0};
+    int aSign = -1;
+    double aNumber = new BigInteger(aSign, a).doubleValue();
+    assertTrue(aNumber == -8.98846567431158E307);
+  }
+
+  /**
+   * Convert a negative number to a double value. The exponent is 1023 and the
+   * mantissa is all 1s. The result is -Double.MAX_VALUE.
+   */
+  public void testDoubleValueNegMaxValue() {
+    byte[] a = {
+        0, -1, -1, -1, -1, -1, -1, -8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1};
+    int aSign = -1;
+    double aNumber = new BigInteger(aSign, a).doubleValue();
+    assertTrue(aNumber == -Double.MAX_VALUE);
+  }
+
+  /**
+   * Convert a positive number to a double value. Rounding is NOT needed.
+   */
+  public void testDoubleValueNegNotRounded() {
+    byte[] a = {-128, 1, 2, 3, 4, 5, -128, 23, 1, -3, -5};
+    int aSign = -1;
+    double result = -1.5474726438794828E26;
+    double aNumber = new BigInteger(aSign, a).doubleValue();
+    assertTrue(aNumber == result);
+  }
+
+  /**
+   * Convert a positive number to a double value. Rounding is needed.
+   */
+  public void testDoubleValueNegRounded1() {
+    byte[] a = {-128, 1, 2, 3, 4, 5, 60, 23, 1, -3, -5};
+    int aSign = -1;
+    double result = -1.54747264387948E26;
+    double aNumber = new BigInteger(aSign, a).doubleValue();
+    assertTrue(aNumber == result);
+  }
+
+  /**
+   * Convert a positive number to a double value. Rounding is needed. The
+   * rounding bit is 1 and the next bit to the left is 0 but some of dropped
+   * bits are 1s.
+   */
+  public void testDoubleValueNegRounded2() {
+    byte[] a = {-128, 1, 2, 3, 4, 5, 36, 23, 1, -3, -5};
+    int aSign = -1;
+    double result = -1.547472643879479E26;
+    double aNumber = new BigInteger(aSign, a).doubleValue();
+    assertTrue(aNumber == result);
+  }
+
+  /**
+   * Convert a positive number to a double value. The number's length is less
+   * than 64 bits.
+   */
+  public void testDoubleValuePositive1() {
+    String a = "27467238945";
+    double result = 2.7467238945E10;
+    double aNumber = new BigInteger(a).doubleValue();
+    assertTrue(aNumber == result);
+  }
+
+  /**
+   * Convert a positive number to a double value. The number's bit length is
+   * inside [63, 1024].
+   */
+  public void testDoubleValuePositive2() {
+    String a = "2746723894572364578265426346273456972";
+    double result = 2.7467238945723645E36;
+    double aNumber = new BigInteger(a).doubleValue();
+    assertTrue(aNumber == result);
+  }
+
+  /**
+   * Convert a positive number to a double value. The exponent is 1023 and the
+   * mantissa is all 1s. The rounding bit is 1. The result is
+   * Double.POSITIVE_INFINITY.
+   */
+  public void testDoubleValuePositiveInfinity1() {
+    byte[] a = {
+        -1, -1, -1, -1, -1, -1, -1, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    int aSign = 1;
+    double aNumber = new BigInteger(aSign, a).doubleValue();
+    assertTrue(aNumber == Double.POSITIVE_INFINITY);
+  }
+
+  /**
+   * Convert a positive number to a double value. The number's bit length is
+   * greater than 1024.
+   */
+  public void testDoubleValuePositiveInfinity2() {
+    String a = "2746723894572364578265426346273456972283746872364768676747462342342342342342342342323423423423423423426767456345745293762384756238475634563456845634568934568347586346578648576478568456457634875673845678456786587345873645767456834756745763457863485768475678465783456702897830296720476846578634576384567845678346573465786457863";
+    double aNumber = new BigInteger(a).doubleValue();
+    assertTrue(aNumber == Double.POSITIVE_INFINITY);
+  }
+
+  /**
+   * Convert a positive number to a double value. The exponent is 1023 and the
+   * mantissa is all 0s but the 54th bit (implicit) is 1.
+   */
+  public void testDoubleValuePosMantissaIsZero() {
+    byte[] a = {
+        -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0};
+    int aSign = 1;
+    double result = 8.98846567431158E307;
+    double aNumber = new BigInteger(aSign, a).doubleValue();
+    assertTrue(aNumber == result);
+  }
+
+  /**
+   * Convert a positive number to a double value. The exponent is 1023 and the
+   * mantissa is all 1s. The rounding bit is 0. The result is Double.MAX_VALUE.
+   */
+  public void testDoubleValuePosMaxValue() {
+    byte[] a = {
+        0, -1, -1, -1, -1, -1, -1, -8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1};
+    int aSign = 1;
+    double aNumber = new BigInteger(aSign, a).doubleValue();
+    assertTrue(aNumber == Double.MAX_VALUE);
+  }
+
+  /**
+   * Convert a positive number to a double value. Rounding is NOT needed.
+   */
+  public void testDoubleValuePosNotRounded() {
+    byte[] a = {-128, 1, 2, 3, 4, 5, -128, 23, 1, -3, -5};
+    int aSign = 1;
+    double result = 1.5474726438794828E26;
+    double aNumber = new BigInteger(aSign, a).doubleValue();
+    assertTrue(aNumber == result);
+  }
+
+  /**
+   * Convert a positive number to a double value. Rounding is needed. The
+   * rounding bit is 1 and the next bit to the left is 1.
+   */
+  public void testDoubleValuePosRounded1() {
+    byte[] a = {-128, 1, 2, 3, 4, 5, 60, 23, 1, -3, -5};
+    int aSign = 1;
+    double result = 1.54747264387948E26;
+    double aNumber = new BigInteger(aSign, a).doubleValue();
+    assertTrue(aNumber == result);
+  }
+
+  /**
+   * Convert a positive number to a double value. Rounding is needed. The
+   * rounding bit is 1 and the next bit to the left is 0 but some of dropped
+   * bits are 1s.
+   */
+  public void testDoubleValuePosRounded2() {
+    byte[] a = {-128, 1, 2, 3, 4, 5, 36, 23, 1, -3, -5};
+    int aSign = 1;
+    double result = 1.547472643879479E26;
+    double aNumber = new BigInteger(aSign, a).doubleValue();
+    assertTrue(aNumber == result);
+  }
+
+  /**
+   * Return the double value of ZERO.
+   */
+  public void testDoubleValueZero() {
+    String a = "0";
+    double result = 0.0;
+    double aNumber = new BigInteger(a).doubleValue();
+    assertTrue(aNumber == result);
+  }
+
+  /**
+   * Convert a negative number to a float value. The number's bit length is less
+   * than 32 bits.
+   */
+  public void testFloatValueBug2482() {
+    String a = "2147483649";
+    float result = 2.14748365E9f;
+    float aNumber = new BigInteger(a).floatValue();
+    assertEquals("incorrect value", aNumber, result, 1);
+  }
+
+  /**
+   * Convert a negative number to a float value. The value is near
+   * Float.MAX_VALUE, but since all calculation in JS is done in double
+   * precision, it can't be completely accurate about passing that value
+   * through.
+   */
+  public void testFloatValueNearNegMaxValue() {
+    byte[] a = {
+        0, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    int aSign = -1;
+    float aNumber = new BigInteger(aSign, a).floatValue();
+    assertEquals(-3.4028235e38, aNumber, 1e31);
+  }
+
+  /**
+   * Convert a positive number to a float value. The value is near
+   * Float.MAX_VALUE, but since all calculation in JS is done in double
+   * precision, it can't be completely accurate about passing that value
+   * through.
+   */
+  public void testFloatValueNearPosMaxValue() {
+    byte[] a = {
+        0, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    int aSign = 1;
+    float aNumber = new BigInteger(aSign, a).floatValue();
+    assertEquals(3.4028235e38, aNumber, 1e31);
+  }
+
+  /**
+   * Convert a negative number to a float value. The number's bit length is less
+   * than 32 bits.
+   */
+  public void testFloatValueNegative1() {
+    String a = "-27467238";
+    float result = -2.7467238E7f;
+    float aNumber = new BigInteger(a).floatValue();
+    assertEquals("incorrect value", result, aNumber, 1);
+  }
+
+  /**
+   * Convert a negative number to a double value. The number's bit length
+   * is inside [63, 1024].
+   */
+  public void testFloatValueNegative2() {
+    String a = "-27467238945723645782";
+    float result = -2.7467239E19f;
+    float aNumber = new BigInteger(a).floatValue();
+    assertEquals("incorrect value", result, aNumber, 1e12);
+  }
+
+  /**
+   * Convert a negative number to a float value. The number's bit length is
+   * greater than 127.
+   */
+  public void testFloatValueNegativeInfinity1() {
+    String a = "-2746723894572364578265426346273456972283746872364768676747462342342342342342342342323423423423423423426767456345745293762384756238475634563456845634568934568347586346578648576478568456457634875673845678456786587345873645767456834756745763457863485768475678465783456702897830296720476846578634576384567845678346573465786457863";
+    float aNumber = new BigInteger(a).floatValue();
+    assertEquals("incorrect value", Float.NEGATIVE_INFINITY, aNumber);
+  }
+
+  /**
+   * Convert a negative number to a float value. The exponent is 1023 and the
+   * mantissa is all 0s. The rounding bit is 0. The result is
+   * Float.NEGATIVE_INFINITY.
+   */
+  public void testFloatValueNegativeInfinity2() {
+    byte[] a = {
+        0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+    int aSign = -1;
+    float aNumber = new BigInteger(aSign, a).floatValue();
+    assertEquals(Float.NEGATIVE_INFINITY, aNumber);
+  }
+
+  /**
+   * Convert a positive number to a double value. The exponent is 1023 and the
+   * mantissa is all 0s but the 54th bit (implicit) is 1.
+   */
+  public void testFloatValueNegMantissaIsZero() {
+    byte[] a = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    int aSign = -1;
+    float aNumber = new BigInteger(aSign, a).floatValue();
+    assertEquals(Float.NEGATIVE_INFINITY, aNumber);
+  }
+
+  /**
+   * Convert a positive number to a float value. Rounding is NOT needed.
+   */
+  public void testFloatValueNegNotRounded() {
+    byte[] a = {-128, 1, 2, 3, 4, 5, 60, 23, 1, -3, -5};
+    int aSign = -1;
+    float result = -1.5474726E26f;
+    float aNumber = new BigInteger(aSign, a).floatValue();
+    assertEquals(result, aNumber, 1e19);
+  }
+
+  /**
+   * Convert a positive number to a float value. Rounding is needed.
+   */
+  public void testFloatValueNegRounded1() {
+    byte[] a = {-128, 1, -1, -4, 4, 5, 60, 23, 1, -3, -5};
+    int aSign = -1;
+    float result = -1.5475195E26f;
+    float aNumber = new BigInteger(aSign, a).floatValue();
+    assertEquals(result, aNumber, 1e19);
+  }
+
+  /**
+   * Convert a positive number to a float value. Rounding is needed. The
+   * rounding bit is 1 and the next bit to the left is 0 but some of dropped
+   * bits are 1s.
+   */
+  public void testFloatValueNegRounded2() {
+    byte[] a = {-128, 1, 2, -128, 4, 5, 60, 23, 1, -3, -5};
+    int aSign = -1;
+    float result = -1.5474728E26f;
+    float aNumber = new BigInteger(aSign, a).floatValue();
+    assertEquals(result, aNumber, 1e19);
+  }
+
+  /**
+   * Convert a negative number beyond Float.MAX_VALUE, ensuring that it is
+   * converted to Float.NEGATIVE_INFINITY.
+   */
+  public void testFloatValuePastNegMaxValue() {
+    byte[] a = {
+        0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+    int aSign = -1;
+    float aNumber = new BigInteger(aSign, a).floatValue();
+    assertEquals(Float.NEGATIVE_INFINITY, aNumber);
+  }
+
+  /**
+   * Convert a positive number beyond Float.MAX_VALUE, ensuring that it is
+   * converted to Float.POSITIVE_INFINITY.
+   */
+  public void testFloatValuePastPosMaxValue() {
+    byte[] a = {
+        0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+    int aSign = 1;
+    float aNumber = new BigInteger(aSign, a).floatValue();
+    assertEquals(Float.POSITIVE_INFINITY, aNumber);
+  }
+
+  /**
+   * Convert a positive number to a float value. The number's length is less
+   * than 32 bits.
+   */
+  public void testFloatValuePositive1() {
+    String a = "27467238";
+    float result = 2.7467238E7f;
+    float aNumber = new BigInteger(a).floatValue();
+    assertEquals(result, aNumber);
+  }
+
+  /**
+   * Convert a positive number to a float value. The number's bit length is
+   * inside [32, 127].
+   */
+  public void testFloatValuePositive2() {
+    String a = "27467238945723645782";
+    float result = 2.7467239E19f;
+    float aNumber = new BigInteger(a).floatValue();
+    assertEquals(result, aNumber, 1e12);
+  }
+
+  /**
+   * Convert a positive number to a float value. The exponent is 1023 and the
+   * mantissa is all 1s. The rounding bit is 1. The result is
+   * Float.POSITIVE_INFINITY.
+   */
+  public void testFloatValuePositiveInfinity1() {
+    byte[] a = {
+        0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+    int aSign = 1;
+    float aNumber = new BigInteger(aSign, a).floatValue();
+    assertEquals(Float.POSITIVE_INFINITY, aNumber);
+  }
+
+  /**
+   * Convert a positive number to a float value. The number's bit length is
+   * greater than 127.
+   */
+  public void testFloatValuePositiveInfinity2() {
+    String a = "274672389457236457826542634627345697228374687236476867674746234"
+        + "23423423423423423423234234234234234234267674563457452937623847562384"
+        + "75634563456845634568934568347586346578648576478568456457634875673845"
+        + "67845678658734587364576745683475674576345786348576847567846578345670"
+        + "2897830296720476846578634576384567845678346573465786457863";
+    float aNumber = new BigInteger(a).floatValue();
+    assertEquals(Float.POSITIVE_INFINITY, aNumber);
+  }
+
+  /**
+   * Convert a positive number to a float value. The exponent is 1023 and the
+   * mantissa is all 0s but the 54th bit (implicit) is 1.
+   */
+  public void testFloatValuePosMantissaIsZero() {
+    byte[] a = {-128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    int aSign = 1;
+    float result = 1.7014118E38f;
+    float aNumber = new BigInteger(aSign, a).floatValue();
+    assertEquals(result, aNumber, 1e31);
+  }
+
+  /**
+   * Convert a positive number to a float value. Rounding is NOT needed.
+   */
+  public void testFloatValuePosNotRounded() {
+    byte[] a = {-128, 1, 2, 3, 4, 5, 60, 23, 1, -3, -5};
+    int aSign = 1;
+    float result = 1.5474726E26f;
+    float aNumber = new BigInteger(aSign, a).floatValue();
+    assertEquals(result, aNumber, 1e19);
+  }
+
+  /**
+   * Convert a positive number to a float value. Rounding is needed. The
+   * rounding bit is 1 and the next bit to the left is 1.
+   */
+  public void testFloatValuePosRounded1() {
+    byte[] a = {-128, 1, -1, -4, 4, 5, 60, 23, 1, -3, -5};
+    int aSign = 1;
+    float result = 1.5475195E26f;
+    float aNumber = new BigInteger(aSign, a).floatValue();
+    assertEquals(result, aNumber, 1e19);
+  }
+
+  /**
+   * Convert a positive number to a float value. Rounding is needed. The
+   * rounding bit is 1 and the next bit to the left is 0 but some of dropped
+   * bits are 1s.
+   */
+  public void testFloatValuePosRounded2() {
+    byte[] a = {-128, 1, 2, -128, 4, 5, 60, 23, 1, -3, -5};
+    int aSign = 1;
+    float result = 1.5474728E26f;
+    float aNumber = new BigInteger(aSign, a).floatValue();
+    assertEquals(result, aNumber, 1e19);
+  }
+
+  /**
+   * Return the float value of ZERO.
+   */
+  public void testFloatValueZero() {
+    String a = "0";
+    float result = 0.0f;
+    float aNumber = new BigInteger(a).floatValue();
+    assertEquals(result, aNumber);
+  }
+
+  /**
+   * Convert a negative BigInteger to an integer value. The low digit is
+   * negative.
+   */
+  public void testIntValueNegative1() {
+    byte aBytes[] = {12, 56, 100, -2, -76, -128, 45, 91, 3};
+    int sign = -1;
+    int resInt = 2144511229;
+    int aNumber = new BigInteger(sign, aBytes).intValue();
+    assertEquals(resInt, aNumber);
+  }
+
+  /**
+   * Convert a negative BigInteger to an integer value. The low digit is
+   * negative.
+   */
+  public void testIntValueNegative2() {
+    byte aBytes[] = {-12, 56, 100};
+    int result = -771996;
+    int aNumber = new BigInteger(aBytes).intValue();
+    assertEquals(result, aNumber);
+  }
+
+  /**
+   * Convert a negative BigInteger to an integer value. The low digit is
+   * positive.
+   */
+  public void testIntValueNegative3() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 127, 45, 91, 3};
+    int sign = -1;
+    int resInt = -2133678851;
+    int aNumber = new BigInteger(sign, aBytes).intValue();
+    assertEquals(resInt, aNumber);
+  }
+
+  /**
+   * Convert a positive BigInteger to an integer value. The low digit is
+   * positive
+   */
+  public void testIntValuePositive1() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3};
+    int resInt = 1496144643;
+    int aNumber = new BigInteger(aBytes).intValue();
+    assertEquals(resInt, aNumber);
+  }
+
+  /**
+   * Convert a positive BigInteger to an integer value. The low digit is
+   * positive
+   */
+  public void testIntValuePositive2() {
+    byte aBytes[] = {12, 56, 100};
+    int resInt = 800868;
+    int aNumber = new BigInteger(aBytes).intValue();
+    assertEquals(resInt, aNumber);
+  }
+
+  /**
+   * Convert a positive BigInteger to an integer value. The low digit is
+   * negative.
+   */
+  public void testIntValuePositive3() {
+    byte aBytes[] = {56, 13, 78, -12, -5, 56, 100};
+    int sign = 1;
+    int resInt = -184862620;
+    int aNumber = new BigInteger(sign, aBytes).intValue();
+    assertEquals(resInt, aNumber);
+  }
+
+  /**
+   * Convert a number to a negative long value The BigInteger is longer than
+   * int.
+   */
+  public void testLongValueNegative1() {
+    byte aBytes[] = {12, -1, 100, -2, -76, -128, 45, 91, 3};
+    long result = -43630045168837885L;
+    long aNumber = new BigInteger(aBytes).longValue();
+    assertEquals(result, aNumber);
+  }
+
+  /**
+   * Convert a number to a negative long value The number fits in a long.
+   */
+  public void testLongValueNegative2() {
+    byte aBytes[] = {-12, 56, 100, 45, -101, 45, 98};
+    long result = -3315696807498398L;
+    long aNumber = new BigInteger(aBytes).longValue();
+    assertEquals(result, aNumber);
+  }
+
+  /**
+   * Convert a BigInteger to a positive long value The BigInteger is longer than
+   * int.
+   */
+  public void testLongValuePositive1() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, 120, -34, -12, 45, 98};
+    long result = 3268209772258930018L;
+    long aNumber = new BigInteger(aBytes).longValue();
+    assertEquals(result, aNumber);
+  }
+
+  /**
+   * Convert a number to a positive long value The number fits in a long.
+   */
+  public void testLongValuePositive2() {
+    byte aBytes[] = {12, 56, 100, 18, -105, 34, -18, 45};
+    long result = 880563758158769709L;
+    long aNumber = new BigInteger(aBytes).longValue();
+    assertEquals(result, aNumber);
+  }
+
+  /**
+   * valueOf (long val): convert Integer.MAX_VALUE to a BigInteger.
+   */
+  public void testValueOfIntegerMax() {
+    long longVal = Integer.MAX_VALUE;
+    BigInteger aNumber = BigInteger.valueOf(longVal);
+    byte rBytes[] = {127, -1, -1, -1};
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * valueOf (long val): convert Integer.MIN_VALUE to a BigInteger.
+   */
+  public void testValueOfIntegerMin() {
+    long longVal = Integer.MIN_VALUE;
+    BigInteger aNumber = BigInteger.valueOf(longVal);
+    byte rBytes[] = {-128, 0, 0, 0};
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, aNumber.signum());
+  }
+
+  /**
+   * valueOf (long val): convert Long.MAX_VALUE to a BigInteger.
+   */
+  public void testValueOfLongMax() {
+    long longVal = Long.MAX_VALUE;
+    BigInteger aNumber = BigInteger.valueOf(longVal);
+    byte rBytes[] = {127, -1, -1, -1, -1, -1, -1, -1};
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * valueOf (long val): convert Long.MIN_VALUE to a BigInteger.
+   */
+  public void testValueOfLongMin() {
+    long longVal = Long.MIN_VALUE;
+    BigInteger aNumber = BigInteger.valueOf(longVal);
+    byte rBytes[] = {-128, 0, 0, 0, 0, 0, 0, 0};
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, aNumber.signum());
+  }
+
+  /**
+   * valueOf (long val): convert a negative long value to a BigInteger.
+   */
+  public void testValueOfLongNegative1() {
+    long longVal = -268209772258930018L;
+    BigInteger aNumber = BigInteger.valueOf(longVal);
+    byte rBytes[] = {-4, 71, 32, -94, 23, 55, -46, -98};
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, aNumber.signum());
+  }
+
+  /**
+   * valueOf (long val): convert a negative long value to a BigInteger. The long
+   * value fits in integer.
+   */
+  public void testValueOfLongNegative2() {
+    long longVal = -58930018L;
+    BigInteger aNumber = BigInteger.valueOf(longVal);
+    byte rBytes[] = {-4, 124, -52, -98};
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, aNumber.signum());
+  }
+
+  /**
+   * valueOf (long val): convert a positive long value to a BigInteger.
+   */
+  public void testValueOfLongPositive1() {
+    long longVal = 268209772258930018L;
+    BigInteger aNumber = BigInteger.valueOf(longVal);
+    byte rBytes[] = {3, -72, -33, 93, -24, -56, 45, 98};
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * valueOf (long val): convert a positive long value to a BigInteger. The long
+   * value fits in integer.
+   */
+  public void testValueOfLongPositive2() {
+    long longVal = 58930018L;
+    BigInteger aNumber = BigInteger.valueOf(longVal);
+    byte rBytes[] = {3, -125, 51, 98};
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, aNumber.signum());
+  }
+
+  /**
+   * valueOf (long val): convert a zero long value to a BigInteger.
+   */
+  public void testValueOfLongZero() {
+    long longVal = 0L;
+    BigInteger aNumber = BigInteger.valueOf(longVal);
+    byte rBytes[] = {0};
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = aNumber.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, aNumber.signum());
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerDivideTest.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerDivideTest.java
new file mode 100644
index 0000000..5975a2b
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerDivideTest.java
@@ -0,0 +1,687 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigInteger;
+
+/**
+ * Class: java.math.BigInteger Methods: divide, remainder, mod, and
+ * divideAndRemainder
+ */
+public class BigIntegerDivideTest extends EmulTestBase {
+  /**
+   * Divide by zero
+   */
+  public void testCase1() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    byte bBytes[] = {0};
+    int aSign = 1;
+    int bSign = 0;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    try {
+      aNumber.divide(bNumber);
+      fail("ArithmeticException has not been caught");
+    } catch (ArithmeticException e) {
+      assertEquals("Improper exception message", "BigInteger divide by zero",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * Divide two negative numbers.
+   */
+  public void testCase10() {
+    byte aBytes[] = {1, 100, 56, 7, 98, -1, 39, -128, 127, 5, 6, 7, 8, 9};
+    byte bBytes[] = {15, 48, -29, 7, 98, -1, 39, -128};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {23, 115, 11, 78, 35, -11};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.divide(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Divide zero by a negative number.
+   */
+  public void testCase11() {
+    byte aBytes[] = {0};
+    byte bBytes[] = {15, 48, -29, 7, 98, -1, 39, -128};
+    int aSign = 0;
+    int bSign = -1;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.divide(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * Divide ZERO by a negative number.
+   */
+  public void testCase12() {
+    byte bBytes[] = {15, 48, -29, 7, 98, -1, 39, -128};
+    int bSign = -1;
+    byte rBytes[] = {0};
+    BigInteger aNumber = BigInteger.ZERO;
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.divide(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * Divide a positive number by ONE.
+   */
+  public void testCase13() {
+    byte aBytes[] = {15, 48, -29, 7, 98, -1, 39, -128};
+    int aSign = 1;
+    byte rBytes[] = {15, 48, -29, 7, 98, -1, 39, -128};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = BigInteger.ONE;
+    BigInteger result = aNumber.divide(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Divide ONE by ONE.
+   */
+  public void testCase14() {
+    byte rBytes[] = {1};
+    BigInteger aNumber = BigInteger.ONE;
+    BigInteger bNumber = BigInteger.ONE;
+    BigInteger result = aNumber.divide(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Remainder of division by zero
+   */
+  public void testCase15() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    byte bBytes[] = {0};
+    int aSign = 1;
+    int bSign = 0;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    try {
+      aNumber.remainder(bNumber);
+      fail("ArithmeticException has not been caught");
+    } catch (ArithmeticException e) {
+      assertEquals("Improper exception message", "BigInteger divide by zero",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * Remainder of division of equal numbers
+   */
+  public void testCase16() {
+    byte aBytes[] = {-127, 100, 56, 7, 98, -1, 39, -128, 127};
+    byte bBytes[] = {-127, 100, 56, 7, 98, -1, 39, -128, 127};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.remainder(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * Remainder of division of two positive numbers
+   */
+  public void testCase17() {
+    byte aBytes[] = {-127, 100, 56, 7, 98, -1, 39, -128, 127, 75};
+    byte bBytes[] = {27, -15, 65, 39, 100};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {12, -21, 73, 56, 27};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.remainder(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Remainder of division of two negative numbers
+   */
+  public void testCase18() {
+    byte aBytes[] = {-127, 100, 56, 7, 98, -1, 39, -128, 127, 75};
+    byte bBytes[] = {27, -15, 65, 39, 100};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {-13, 20, -74, -57, -27};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.remainder(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Remainder of division of two numbers of different signs. The first is
+   * positive.
+   */
+  public void testCase19() {
+    byte aBytes[] = {-127, 100, 56, 7, 98, -1, 39, -128, 127, 75};
+    byte bBytes[] = {27, -15, 65, 39, 100};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {12, -21, 73, 56, 27};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.remainder(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Divide by ZERO
+   */
+  public void testCase2() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    int aSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = BigInteger.ZERO;
+    try {
+      aNumber.divide(bNumber);
+      fail("ArithmeticException has not been caught");
+    } catch (ArithmeticException e) {
+      assertEquals("Improper exception message", "BigInteger divide by zero",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * Remainder of division of two numbers of different signs. The first is
+   * negative.
+   */
+  public void testCase20() {
+    byte aBytes[] = {-127, 100, 56, 7, 98, -1, 39, -128, 127, 75};
+    byte bBytes[] = {27, -15, 65, 39, 100};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {-13, 20, -74, -57, -27};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.remainder(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * divideAndRemainder of two numbers of different signs. The first is
+   * negative.
+   */
+  public void testCase21() {
+    byte aBytes[] = {-127, 100, 56, 7, 98, -1, 39, -128, 127, 75};
+    byte bBytes[] = {27, -15, 65, 39, 100};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[][] = { {-5, 94, -115, -74, -85, 84}, {-13, 20, -74, -57, -27}};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result[] = aNumber.divideAndRemainder(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result[0].toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      if (resBytes[i] != rBytes[0][i]) {
+        fail("Incorrect quotation");
+      }
+    }
+    assertEquals(-1, result[0].signum());
+    resBytes = result[1].toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      if (resBytes[i] != rBytes[1][i]) {
+        fail("Incorrect remainder");
+      }
+      assertEquals(-1, result[1].signum());
+    }
+  }
+
+  /**
+   * mod when modulus is negative
+   */
+  public void testCase22() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    byte bBytes[] = {1, 30, 40, 56, -1, 45};
+    int aSign = 1;
+    int bSign = -1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    try {
+      aNumber.mod(bNumber);
+      fail("ArithmeticException has not been caught");
+    } catch (ArithmeticException e) {
+      assertEquals("Improper exception message",
+          "BigInteger: modulus not positive", e.getMessage());
+    }
+  }
+
+  /**
+   * mod when a divisor is positive
+   */
+  public void testCase23() {
+    byte aBytes[] = {-127, 100, 56, 7, 98, -1, 39, -128, 127, 75};
+    byte bBytes[] = {27, -15, 65, 39, 100};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {12, -21, 73, 56, 27};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.mod(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * mod when a divisor is negative
+   */
+  public void testCase24() {
+    byte aBytes[] = {-127, 100, 56, 7, 98, -1, 39, -128, 127, 75};
+    byte bBytes[] = {27, -15, 65, 39, 100};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {15, 5, -9, -17, 73};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.mod(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Divide two equal positive numbers
+   */
+  public void testCase3() {
+    byte aBytes[] = {-127, 100, 56, 7, 98, -1, 39, -128, 127};
+    byte bBytes[] = {-127, 100, 56, 7, 98, -1, 39, -128, 127};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {1};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.divide(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Divide two equal in absolute value numbers of different signs.
+   */
+  public void testCase4() {
+    byte aBytes[] = {-127, 100, 56, 7, 98, -1, 39, -128, 127};
+    byte bBytes[] = {-127, 100, 56, 7, 98, -1, 39, -128, 127};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {-1};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.divide(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Divide two numbers of different length and different signs. The second is
+   * longer.
+   */
+  public void testCase5() {
+    byte aBytes[] = {-127, 100, 56, 7, 98, -1, 39, -128, 127};
+    byte bBytes[] = {-127, 100, 56, 7, 98, -1, 39, -128, 127, 1, 2, 3, 4, 5};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.divide(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * Divide two positive numbers of the same length. The second is greater.
+   */
+  public void testCase6() {
+    byte aBytes[] = {1, 100, 56, 7, 98, -1, 39, -128, 127};
+    byte bBytes[] = {15, 100, 56, 7, 98, -1, 39, -128, 127};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.divide(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * Divide two positive numbers.
+   */
+  public void testCase7() {
+    byte aBytes[] = {1, 100, 56, 7, 98, -1, 39, -128, 127, 5, 6, 7, 8, 9};
+    byte bBytes[] = {15, 48, -29, 7, 98, -1, 39, -128};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {23, 115, 11, 78, 35, -11};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.divide(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Divide a positive number by a negative one.
+   */
+  public void testCase8() {
+    byte aBytes[] = {1, 100, 56, 7, 98, -1, 39, -128, 127, 5, 6, 7, 8, 9};
+    byte bBytes[] = {15, 48, -29, 7, 98, -1, 39, -128};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {-24, -116, -12, -79, -36, 11};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.divide(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Divide a negative number by a positive one.
+   */
+  public void testCase9() {
+    byte aBytes[] = {1, 100, 56, 7, 98, -1, 39, -128, 127, 5, 6, 7, 8, 9};
+    byte bBytes[] = {15, 48, -29, 7, 98, -1, 39, -128};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {-24, -116, -12, -79, -36, 11};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.divide(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Verifies the case when borrow != 0 in the private divide method.
+   */
+  public void testDivisionKnuth1() {
+    byte aBytes[] = {-7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7};
+    byte bBytes[] = {-3, -3, -3, -3};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {0, -5, -12, -33, -96, -36, -105, -56, 92, 15, 48, -109};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.divide(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Verifies the case when the first digits of the dividend and divisor equal.
+   */
+  public void testDivisionKnuthFirstDigitsEqual() {
+    byte aBytes[] = {2, -3, -4, -5, -1, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5};
+    byte bBytes[] = {2, -3, -4, -5, -1, -1, -1, -1};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {0, -1, -1, -1, -1, -2, -88, -60, 41};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.divide(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Verifies the case when the divisor is already normalized.
+   */
+  public void testDivisionKnuthIsNormalized() {
+    byte aBytes[] = {-9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5};
+    byte bBytes[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {0, -9, -8, -7, -6, -5, -4, -3};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.divide(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Divide the number of multi digits by the number of one digit
+   */
+  public void testDivisionKnuthMultiDigitsByOneDigit() {
+    byte aBytes[] = {113, -83, 123, -5, 18, -34, 67, 39, -29};
+    byte bBytes[] = {2, -3, -4, -5};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {-38, 2, 7, 30, 109, -43};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.divide(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Divide the number of one digit by the number of one digit
+   */
+  public void testDivisionKnuthOneDigitByOneDigit() {
+    byte aBytes[] = {113, -83, 123, -5};
+    byte bBytes[] = {2, -3, -4, -5};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {-37};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.divide(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Tests the step D6 from the Knuth algorithm
+   */
+  public void testRemainderKnuth1() {
+    byte aBytes[] = {-9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1};
+    byte bBytes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {1, 2, 3, 4, 5, 6, 7, 7, 18, -89};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.remainder(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Divide the number of multi digits by the number of one digit
+   */
+  public void testRemainderKnuthMultiDigitsByOneDigit() {
+    byte aBytes[] = {113, -83, 123, -5, 18, -34, 67, 39, -29};
+    byte bBytes[] = {2, -3, -4, -50};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {2, -37, -60, 59};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.remainder(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Divide the number of one digit by the number of one digit
+   */
+  public void testRemainderKnuthOneDigitByOneDigit() {
+    byte aBytes[] = {113, -83, 123, -5};
+    byte bBytes[] = {2, -3, -4, -50};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {2, -9, -14, 53};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.remainder(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerHashCodeTest.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerHashCodeTest.java
new file mode 100644
index 0000000..1e311c0
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerHashCodeTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigInteger;
+
+/**
+ * Class: java.math.BigInteger Method: hashCode()
+ */
+public class BigIntegerHashCodeTest extends EmulTestBase {
+  /**
+   * Test hash codes for equal objects.
+   */
+  public void testEqualObjects() {
+    String value1 = "12378246728727834290276457386374882976782849";
+    String value2 = "12378246728727834290276457386374882976782849";
+    BigInteger aNumber1 = new BigInteger(value1);
+    BigInteger aNumber2 = new BigInteger(value2);
+    int code1 = aNumber1.hashCode();
+    int code2 = aNumber2.hashCode();
+    if (aNumber1.equals(aNumber2)) {
+      assertTrue("hash codes for equal objects are unequal", code1 == code2);
+    }
+  }
+
+  /**
+   * Test hash codes for the same object
+   */
+  public void testSameObject() {
+    String value1 = "12378246728727834290276457386374882976782849";
+    String value2 = "-5634562095872038262928728727834290276457386374882976782849";
+    BigInteger aNumber1 = new BigInteger(value1);
+    BigInteger aNumber2 = new BigInteger(value2);
+    int code1 = aNumber1.hashCode();
+    aNumber1.add(aNumber2).shiftLeft(125);
+    aNumber1.subtract(aNumber2).shiftRight(125);
+    aNumber1.multiply(aNumber2).toByteArray();
+    aNumber1.divide(aNumber2).bitLength();
+    aNumber1.gcd(aNumber2).pow(7);
+    int code2 = aNumber1.hashCode();
+    assertTrue("hash codes for the same object differ", code1 == code2);
+  }
+
+  /**
+   * Test hash codes for unequal objects. The codes are unequal.
+   */
+  public void testUnequalObjectsUnequal() {
+    String value1 = "12378246728727834290276457386374882976782849";
+    String value2 = "-5634562095872038262928728727834290276457386374882976782849";
+    BigInteger aNumber1 = new BigInteger(value1);
+    BigInteger aNumber2 = new BigInteger(value2);
+    int code1 = aNumber1.hashCode();
+    int code2 = aNumber2.hashCode();
+    if (!aNumber1.equals(aNumber2)) {
+      assertTrue("hash codes for unequal objects are equal", code1 != code2);
+    }
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerModPowTest.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerModPowTest.java
new file mode 100644
index 0000000..c3bb24f
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerModPowTest.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigInteger;
+
+/**
+ * Class: java.math.BigInteger Methods: modPow, modInverse, and gcd
+ */
+public class BigIntegerModPowTest extends EmulTestBase {
+  /**
+   * gcd: both numbers are zeros
+   */
+  public void testGcdBothZeros() {
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger("0");
+    BigInteger bNumber = BigInteger.valueOf(0L);
+    BigInteger result = aNumber.gcd(bNumber);
+    byte resBytes[] = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * gcd: the first number is longer
+   */
+  public void testGcdFirstLonger() {
+    byte aBytes[] = {
+        -15, 24, 123, 56, -11, -112, -34, -98, 8, 10, 12, 14, 25, 125, -15, 28,
+        -127};
+    byte bBytes[] = {-12, 1, 0, 0, 0, 23, 44, 55, 66};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {7};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.gcd(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * gcd: the first number is zero
+   */
+  public void testGcdFirstZero() {
+    byte aBytes[] = {0};
+    byte bBytes[] = {15, 24, 123, 57, -15, 24, 123, 57, -15, 24, 123, 57};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {15, 24, 123, 57, -15, 24, 123, 57, -15, 24, 123, 57};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.gcd(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * gcd: the first number is ZERO
+   */
+  public void testGcdFirstZERO() {
+    byte bBytes[] = {15, 24, 123, 57, -15, 24, 123, 57, -15, 24, 123, 57};
+    int bSign = 1;
+    byte rBytes[] = {15, 24, 123, 57, -15, 24, 123, 57, -15, 24, 123, 57};
+    BigInteger aNumber = BigInteger.ZERO;
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.gcd(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * gcd: the second number is longer
+   */
+  public void testGcdSecondLonger() {
+    byte aBytes[] = {-12, 1, 0, 0, 0, 23, 44, 55, 66};
+    byte bBytes[] = {
+        -15, 24, 123, 56, -11, -112, -34, -98, 8, 10, 12, 14, 25, 125, -15, 28,
+        -127};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {7};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.gcd(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * gcd: the second number is zero
+   */
+  public void testGcdSecondZero() {
+    byte aBytes[] = {15, 24, 123, 57, -15, 24, 123, 57, -15, 24, 123, 57};
+    byte bBytes[] = {0};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {15, 24, 123, 57, -15, 24, 123, 57, -15, 24, 123, 57};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.gcd(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * modInverse: non-positive modulus
+   */
+  public void testmodInverseException() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    byte mBytes[] = {1, 2, 3};
+    int aSign = 1;
+    int mSign = -1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger modulus = new BigInteger(mSign, mBytes);
+    try {
+      aNumber.modInverse(modulus);
+      fail("ArithmeticException has not been caught");
+    } catch (ArithmeticException e) {
+      assertEquals("Improper exception message",
+          "BigInteger: modulus not positive", e.getMessage());
+    }
+  }
+
+  /**
+   * modInverse: negative number
+   */
+  public void testmodInverseNeg1() {
+    byte aBytes[] = {
+        15, 24, 123, 56, -11, -112, -34, -98, 8, 10, 12, 14, 25, 125, -15, 28,
+        -127};
+    byte mBytes[] = {2, 122, 45, 36, 100};
+    int aSign = -1;
+    int mSign = 1;
+    byte rBytes[] = {0, -41, 4, -91, 27};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger modulus = new BigInteger(mSign, mBytes);
+    BigInteger result = aNumber.modInverse(modulus);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * modInverse: negative number (another case: x < 0)
+   */
+  public void testmodInverseNeg2() {
+    byte aBytes[] = {-15, 24, 123, 57, -15, 24, 123, 57, -15, 24, 123, 57};
+    byte mBytes[] = {122, 2, 4, 122, 2, 4};
+    byte rBytes[] = {85, 47, 127, 4, -128, 45};
+    BigInteger aNumber = new BigInteger(aBytes);
+    BigInteger modulus = new BigInteger(mBytes);
+    BigInteger result = aNumber.modInverse(modulus);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * modInverse: non-invertible number
+   */
+  public void testmodInverseNonInvertible() {
+    byte aBytes[] = {
+        -15, 24, 123, 56, -11, -112, -34, -98, 8, 10, 12, 14, 25, 125, -15, 28,
+        -127};
+    byte mBytes[] = {-12, 1, 0, 0, 0, 23, 44, 55, 66};
+    int aSign = 1;
+    int mSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger modulus = new BigInteger(mSign, mBytes);
+    try {
+      aNumber.modInverse(modulus);
+      fail("ArithmeticException has not been caught");
+    } catch (ArithmeticException e) {
+      assertEquals("Improper exception message", "BigInteger not invertible.",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * modInverse: positive number
+   */
+  public void testmodInversePos1() {
+    byte aBytes[] = {
+        24, 123, 56, -11, -112, -34, -98, 8, 10, 12, 14, 25, 125, -15, 28, -127};
+    byte mBytes[] = {122, 45, 36, 100, 122, 45};
+    int aSign = 1;
+    int mSign = 1;
+    byte rBytes[] = {47, 3, 96, 62, 87, 19};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger modulus = new BigInteger(mSign, mBytes);
+    BigInteger result = aNumber.modInverse(modulus);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * modInverse: positive number (another case: a < 0)
+   */
+  public void testmodInversePos2() {
+    byte aBytes[] = {
+        15, 24, 123, 56, -11, -112, -34, -98, 8, 10, 12, 14, 25, 125, -15, 28,
+        -127};
+    byte mBytes[] = {2, 122, 45, 36, 100};
+    int aSign = 1;
+    int mSign = 1;
+    byte rBytes[] = {1, -93, 40, 127, 73};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger modulus = new BigInteger(mSign, mBytes);
+    BigInteger result = aNumber.modInverse(modulus);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * modPow: non-positive modulus
+   */
+  public void testModPowException() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    byte eBytes[] = {1, 2, 3, 4, 5};
+    byte mBytes[] = {1, 2, 3};
+    int aSign = 1;
+    int eSign = 1;
+    int mSign = -1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger exp = new BigInteger(eSign, eBytes);
+    BigInteger modulus = new BigInteger(mSign, mBytes);
+    try {
+      aNumber.modPow(exp, modulus);
+      fail("ArithmeticException has not been caught");
+    } catch (ArithmeticException e) {
+      assertEquals("Improper exception message",
+          "BigInteger: modulus not positive", e.getMessage());
+    }
+  }
+
+  /**
+   * modPow: negative exponent
+   */
+  public void testModPowNegExp() {
+    byte aBytes[] = {-127, 100, 56, 7, 98, -1, 39, -128, 127, 75, 48, -7};
+    byte eBytes[] = {27, -15, 65, 39};
+    byte mBytes[] = {-128, 2, 3, 4, 5};
+    int aSign = 1;
+    int eSign = -1;
+    int mSign = 1;
+    byte rBytes[] = {12, 118, 46, 86, 92};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger exp = new BigInteger(eSign, eBytes);
+    BigInteger modulus = new BigInteger(mSign, mBytes);
+    BigInteger result = aNumber.modPow(exp, modulus);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * modPow: positive exponent.
+   */
+  public void testModPowPosExp() {
+    byte aBytes[] = {-127, 100, 56, 7, 98, -1, 39, -128, 127, 75, 48, -7};
+    byte eBytes[] = {27, -15, 65, 39};
+    byte mBytes[] = {-128, 2, 3, 4, 5};
+    int aSign = 1;
+    int eSign = 1;
+    int mSign = 1;
+    byte rBytes[] = {113, 100, -84, -28, -85};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger exp = new BigInteger(eSign, eBytes);
+    BigInteger modulus = new BigInteger(mSign, mBytes);
+    BigInteger result = aNumber.modPow(exp, modulus);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertEquals("Byte " + i, rBytes[i], resBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerMultiplyTest.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerMultiplyTest.java
new file mode 100644
index 0000000..5b24a50
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerMultiplyTest.java
@@ -0,0 +1,414 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigInteger;
+
+/**
+ * Class: java.math.BigInteger Method: multiply
+ */
+public class BigIntegerMultiplyTest extends EmulTestBase {
+  /**
+   * Multiply two negative numbers of the same length
+   */
+  public void testCase1() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {
+        10, 40, 100, -55, 96, 51, 76, 40, -45, 85, 105, 4, 28, -86, -117, -52,
+        100, 120, 90};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.multiply(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Multiply a negative number by ONE.
+   */
+  public void testCase10() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 1, 2, 3, 4, 5};
+    int aSign = -1;
+    byte rBytes[] = {-2, -3, -4, -5, -6, -7, -8, -2, -3, -4, -2, -3, -4, -5, -5};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = BigInteger.ONE;
+    BigInteger result = aNumber.multiply(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Multiply two numbers of the same length and different signs. The first is
+   * negative.
+   */
+  public void testCase2() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {
+        -11, -41, -101, 54, -97, -52, -77, -41, 44, -86, -106, -5, -29, 85,
+        116, 51, -101, -121, -90};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.multiply(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Multiply two positive numbers of different length. The first is longer.
+   */
+  public void testCase3() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 1, 2, 3, 4, 5};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {
+        10, 40, 100, -55, 96, 51, 76, 40, -45, 85, 115, 44, -127, 115, -21,
+        -62, -15, 85, 64, -87, -2, -36, -36, -106};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.multiply(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Multiply two positive numbers of different length. The second is longer.
+   */
+  public void testCase4() {
+    byte aBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    byte bBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 1, 2, 3, 4, 5};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {
+        10, 40, 100, -55, 96, 51, 76, 40, -45, 85, 115, 44, -127, 115, -21,
+        -62, -15, 85, 64, -87, -2, -36, -36, -106};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.multiply(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Multiply two numbers of different length and different signs. The first is
+   * positive. The first is longer.
+   */
+  public void testCase5() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 1, 2, 3, 4, 5};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {
+        -11, -41, -101, 54, -97, -52, -77, -41, 44, -86, -116, -45, 126, -116,
+        20, 61, 14, -86, -65, 86, 1, 35, 35, 106};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.multiply(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Multiply two numbers of different length and different signs. The first is
+   * positive. The second is longer.
+   */
+  public void testCase6() {
+    byte aBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    byte bBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 1, 2, 3, 4, 5};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {
+        -11, -41, -101, 54, -97, -52, -77, -41, 44, -86, -116, -45, 126, -116,
+        20, 61, 14, -86, -65, 86, 1, 35, 35, 106};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.multiply(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Multiply a number by zero.
+   */
+  public void testCase7() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 1, 2, 3, 4, 5};
+    byte bBytes[] = {0};
+    int aSign = 1;
+    int bSign = 0;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.multiply(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * Multiply a number by ZERO.
+   */
+  public void testCase8() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 1, 2, 3, 4, 5};
+    int aSign = 1;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = BigInteger.ZERO;
+    BigInteger result = aNumber.multiply(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * Multiply a positive number by ONE.
+   */
+  public void testCase9() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 1, 2, 3, 4, 5};
+    int aSign = 1;
+    byte rBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 1, 2, 3, 4, 5};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = BigInteger.ONE;
+    BigInteger result = aNumber.multiply(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Multiply two numbers of 4 bytes length.
+   */
+  public void testIntbyInt1() {
+    byte aBytes[] = {10, 20, 30, 40};
+    byte bBytes[] = {1, 2, 3, 4};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {-11, -41, -101, 55, 5, 15, 96};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.multiply(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Multiply two numbers of 4 bytes length.
+   */
+  public void testIntbyInt2() {
+    byte aBytes[] = {-1, -1, -1, -1};
+    byte bBytes[] = {-1, -1, -1, -1};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {0, -1, -1, -1, -2, 0, 0, 0, 1};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.multiply(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Negative exponent.
+   */
+  public void testPowException() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7};
+    int aSign = 1;
+    int exp = -5;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    try {
+      aNumber.pow(exp);
+      fail("ArithmeticException has not been caught");
+    } catch (ArithmeticException e) {
+      assertEquals("Improper exception message", "Negative exponent",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * Exponentiation of a negative number to an even exponent.
+   */
+  public void testPowNegativeNumToEvenExp() {
+    byte aBytes[] = {50, -26, 90, 69, 120, 32, 63, -103, -14, 35};
+    int aSign = -1;
+    int exp = 4;
+    byte rBytes[] = {
+        102, 107, -122, -43, -52, -20, -27, 25, -9, 88, -13, 75, 78, 81, -33,
+        -77, 39, 27, -37, 106, 121, -73, 108, -47, -101, 80, -25, 71, 13, 94,
+        -7, -33, 1, -17, -65, -70, -61, -3, -47};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.pow(exp);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Exponentiation of a negative number to an odd exponent.
+   */
+  public void testPowNegativeNumToOddExp() {
+    byte aBytes[] = {50, -26, 90, 69, 120, 32, 63, -103, -14, 35};
+    int aSign = -1;
+    int exp = 5;
+    byte rBytes[] = {
+        -21, -94, -42, -15, -127, 113, -50, -88, 115, -35, 3, 59, -92, 111,
+        -75, 103, -42, 41, 34, -114, 99, -32, 105, -59, 127, 45, 108, 74, -93,
+        105, 33, 12, -5, -20, 17, -21, -119, -127, -115, 27, -122, 26, -67,
+        109, -125, 16, 91, -70, 109};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.pow(exp);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Exponentiation of a negative number to zero exponent.
+   */
+  public void testPowNegativeNumToZeroExp() {
+    byte aBytes[] = {50, -26, 90, 69, 120, 32, 63, -103, -14, 35};
+    int aSign = -1;
+    int exp = 0;
+    byte rBytes[] = {1};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.pow(exp);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Exponentiation of a positive number.
+   */
+  public void testPowPositiveNum() {
+    byte aBytes[] = {50, -26, 90, 69, 120, 32, 63, -103, -14, 35};
+    int aSign = 1;
+    int exp = 5;
+    byte rBytes[] = {
+        20, 93, 41, 14, 126, -114, 49, 87, -116, 34, -4, -60, 91, -112, 74,
+        -104, 41, -42, -35, 113, -100, 31, -106, 58, -128, -46, -109, -75, 92,
+        -106, -34, -13, 4, 19, -18, 20, 118, 126, 114, -28, 121, -27, 66, -110,
+        124, -17, -92, 69, -109};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.pow(exp);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Exponentiation of a negative number to zero exponent.
+   */
+  public void testPowPositiveNumToZeroExp() {
+    byte aBytes[] = {50, -26, 90, 69, 120, 32, 63, -103, -14, 35};
+    int aSign = 1;
+    int exp = 0;
+    byte rBytes[] = {1};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.pow(exp);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerNotTest.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerNotTest.java
new file mode 100644
index 0000000..9a1b4f7
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerNotTest.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigInteger;
+
+/**
+ * Class: java.math.BigInteger Methods: and, andNot
+ */
+public class BigIntegerNotTest extends EmulTestBase {
+  /**
+   * andNot for two negative numbers; the first is longer
+   */
+  public void testAndNotNegNegFirstLonger() {
+    byte aBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {73, -92, -48, 4, 12, 6, 4, 32, 48, 64, 0, 8, 2};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.andNot(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * andNot for two positive numbers; the first is longer
+   */
+  public void testAndNotPosPosFirstLonger() {
+    byte aBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {
+        0, -128, 9, 56, 100, 0, 0, 1, 1, 90, 1, -32, 0, 10, -126, 21, 82, -31,
+        -96};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.andNot(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * andNot for two positive numbers; the first is shorter
+   */
+  public void testAndNotPosPosFirstShorter() {
+    byte aBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    byte bBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {73, -92, -48, 4, 12, 6, 4, 32, 48, 64, 0, 8, 2};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.andNot(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * andNot for a negative and a positive numbers; the first is longer
+   */
+  public void testNegPosFirstLonger() {
+    byte aBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {
+        -1, 127, -10, -57, -101, 1, 2, 2, 2, -96, -16, 8, -40, -59, 68, -88,
+        -88, 16, 72};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.andNot(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Not for a negative number
+   */
+  public void testNotNeg() {
+    byte aBytes[] = {-128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117};
+    int aSign = -1;
+    byte rBytes[] = {
+        0, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -118};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.not();
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Not for ONE
+   */
+  public void testNotOne() {
+    byte rBytes[] = {-2};
+    BigInteger aNumber = BigInteger.ONE;
+    BigInteger result = aNumber.not();
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Not for a positive number
+   */
+  public void testNotPos() {
+    byte aBytes[] = {-128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117};
+    int aSign = 1;
+    byte rBytes[] = {
+        -1, 127, -57, -101, 1, 75, -90, -46, -92, -4, 14, -36, -27, 116};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.not();
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Not for a negative number
+   */
+
+  public void testNotSpecialCase() {
+    byte aBytes[] = {-1, -1, -1, -1};
+    int aSign = 1;
+    byte rBytes[] = {-1, 0, 0, 0, 0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.not();
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Not for ZERO
+   */
+  public void testNotZero() {
+    byte rBytes[] = {-1};
+    BigInteger aNumber = BigInteger.ZERO;
+    BigInteger result = aNumber.not();
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+}
\ No newline at end of file
diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerOperateBitsTest.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerOperateBitsTest.java
new file mode 100644
index 0000000..3e62f59
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerOperateBitsTest.java
@@ -0,0 +1,1418 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigInteger;
+
+/**
+ * Class: java.math.BigInteger Methods: bitLength, shiftLeft, shiftRight,
+ * clearBit, flipBit, setBit, testBit
+ */
+public class BigIntegerOperateBitsTest extends EmulTestBase {
+  /**
+   * bitCount() of a negative number.
+   */
+  public void testBitCountNeg() {
+    BigInteger aNumber = new BigInteger(
+        "-12378634756382937873487638746283767238657872368748726875");
+    assertEquals(87, aNumber.bitCount());
+  }
+
+  /**
+   * bitCount() of a negative number.
+   */
+  public void testBitCountPos() {
+    BigInteger aNumber = new BigInteger(
+        "12378634756343564757582937873487638746283767238657872368748726875");
+    assertEquals(107, aNumber.bitCount());
+  }
+
+  /**
+   * bitCount() of zero.
+   */
+  public void testBitCountZero() {
+    BigInteger aNumber = new BigInteger("0");
+    assertEquals(0, aNumber.bitCount());
+  }
+
+  /**
+   * bitLength() of a negative number.
+   */
+  public void testBitLengthNegative1() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = -1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    assertEquals(108, aNumber.bitLength());
+  }
+
+  /**
+   * bitLength() of a negative number with the leftmost bit set
+   */
+  public void testBitLengthNegative2() {
+    byte aBytes[] = {-128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = -1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    assertEquals(96, aNumber.bitLength());
+  }
+
+  /**
+   * bitLength() of a negative number which is a power of 2
+   */
+  public void testBitLengthNegative3() {
+    byte aBytes[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    int aSign = -1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    assertEquals(80, aNumber.bitLength());
+  }
+
+  /**
+   * bitLength() of a positive number.
+   */
+  public void testBitLengthPositive1() {
+    byte aBytes[] = {12, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, 3, 91};
+    int aSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    assertEquals(108, aNumber.bitLength());
+  }
+
+  /**
+   * bitLength() of a positive number with the leftmost bit set
+   */
+  public void testBitLengthPositive2() {
+    byte aBytes[] = {-128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    assertEquals(96, aNumber.bitLength());
+  }
+
+  /**
+   * bitLength() of a positive number which is a power of 2
+   */
+  public void testBitLengthPositive3() {
+    byte aBytes[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    int aSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    assertEquals(81, aNumber.bitLength());
+  }
+
+  /**
+   * bitLength() of zero.
+   */
+  public void testBitLengthZero() {
+    BigInteger aNumber = new BigInteger("0");
+    assertEquals(0, aNumber.bitLength());
+  }
+
+  /**
+   * clearBit(int n) of a negative n
+   */
+  public void testClearBitException() {
+    byte aBytes[] = {-1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = -7;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    try {
+      aNumber.clearBit(number);
+      fail("ArithmeticException has not been caught");
+    } catch (ArithmeticException e) {
+      assertEquals("Improper exception message", "Negative bit address",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * clearBit(int n) inside a negative number
+   */
+  public void testClearBitNegativeInside1() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = -1;
+    int number = 15;
+    byte rBytes[] = {-2, 127, -57, -101, 1, 75, -90, -46, -92, -4, 14, 92, -26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.clearBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * clearBit(int n) inside a negative number
+   */
+  public void testClearBitNegativeInside2() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = -1;
+    int number = 44;
+    byte rBytes[] = {-2, 127, -57, -101, 1, 75, -90, -62, -92, -4, 14, -36, -26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.clearBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * clearBit(2) in the negative number with all ones in bit representation
+   */
+  public void testClearBitNegativeInside3() {
+    String as = "-18446744073709551615";
+    int number = 2;
+    BigInteger aNumber = new BigInteger(as);
+    BigInteger result = aNumber.clearBit(number);
+    assertEquals(as, result.toString());
+  }
+
+  /**
+   * clearBit(0) in the negative number of length 1 with all ones in bit
+   * representation. the resulting number's length is 2.
+   */
+  public void testClearBitNegativeInside4() {
+    String as = "-4294967295";
+    String res = "-4294967296";
+    int number = 0;
+    BigInteger aNumber = new BigInteger(as);
+    BigInteger result = aNumber.clearBit(number);
+    assertEquals(res, result.toString());
+  }
+
+  /**
+   * clearBit(0) in the negative number of length 2 with all ones in bit
+   * representation. the resulting number's length is 3.
+   */
+  public void testClearBitNegativeInside5() {
+    String as = "-18446744073709551615";
+    String res = "-18446744073709551616";
+    int number = 0;
+    BigInteger aNumber = new BigInteger(as);
+    BigInteger result = aNumber.clearBit(number);
+    assertEquals(res, result.toString());
+  }
+
+  /**
+   * clearBit(int n) outside a negative number
+   */
+  public void testClearBitNegativeOutside1() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = -1;
+    int number = 150;
+    byte rBytes[] = {
+        -65, -1, -1, -1, -1, -1, -2, 127, -57, -101, 1, 75, -90, -46, -92, -4,
+        14, -36, -26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.clearBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * clearBit(int n) outside a negative number
+   */
+  public void testClearBitNegativeOutside2() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = -1;
+    int number = 165;
+    byte rBytes[] = {
+        -33, -1, -1, -1, -1, -1, -1, -1, -2, 127, -57, -101, 1, 75, -90, -46,
+        -92, -4, 14, -36, -26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.clearBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * clearBit(int n) inside a positive number
+   */
+  public void testClearBitPositiveInside1() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 20;
+    byte rBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -31, 35, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.clearBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * clearBit(int n) inside a positive number
+   */
+  public void testClearBitPositiveInside2() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 17;
+    byte rBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.clearBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * clearBit(int n) inside a positive number
+   */
+  public void testClearBitPositiveInside3() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 45;
+    byte rBytes[] = {1, -128, 56, 100, -2, -76, 89, 13, 91, 3, -15, 35, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.clearBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * clearBit(int n) inside a positive number
+   */
+  public void testClearBitPositiveInside4() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 50;
+    byte rBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.clearBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * clearBit(int n) inside a positive number
+   */
+  public void testClearBitPositiveInside5() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 63;
+    byte rBytes[] = {1, -128, 56, 100, -2, 52, 89, 45, 91, 3, -15, 35, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.clearBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * clearBit(int n) outside a positive number
+   */
+  public void testClearBitPositiveOutside1() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 150;
+    byte rBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.clearBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * clearBit(int n) outside a positive number
+   */
+  public void testClearBitPositiveOutside2() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 191;
+    byte rBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.clearBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * clearBit(int n) the leftmost bit in a negative number
+   */
+  public void testClearBitTopNegative() {
+    byte aBytes[] = {1, -128, 56, 100, -15, 35, 26};
+    int aSign = -1;
+    int number = 63;
+    byte rBytes[] = {-1, 127, -2, 127, -57, -101, 14, -36, -26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.clearBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * clearBit(int n) outside zero
+   */
+  public void testClearBitZero() {
+    byte aBytes[] = {0};
+    int aSign = 0;
+    int number = 0;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.clearBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * clearBit(int n) outside zero
+   */
+  public void testClearBitZeroOutside1() {
+    byte aBytes[] = {0};
+    int aSign = 0;
+    int number = 95;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.clearBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * flipBit(int n) of a negative n
+   */
+  public void testFlipBitException() {
+    byte aBytes[] = {-1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = -7;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    try {
+      aNumber.flipBit(number);
+      fail("ArithmeticException has not been caught");
+    } catch (ArithmeticException e) {
+      assertEquals("Improper exception message", "Negative bit address",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * flipBit(int n) the leftmost bit in a negative number
+   */
+  public void testFlipBitLeftmostNegative() {
+    byte aBytes[] = {1, -128, 56, 100, -15, 35, 26};
+    int aSign = -1;
+    int number = 48;
+    byte rBytes[] = {-1, 127, -57, -101, 14, -36, -26, 49};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.flipBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * flipBit(int n) the leftmost bit in a positive number
+   */
+  public void testFlipBitLeftmostPositive() {
+    byte aBytes[] = {1, -128, 56, 100, -15, 35, 26};
+    int aSign = 1;
+    int number = 48;
+    byte rBytes[] = {0, -128, 56, 100, -15, 35, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.flipBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * flipBit(int n) inside a negative number
+   */
+  public void testFlipBitNegativeInside1() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = -1;
+    int number = 15;
+    byte rBytes[] = {-2, 127, -57, -101, 1, 75, -90, -46, -92, -4, 14, 92, -26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.flipBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * flipBit(int n) inside a negative number
+   */
+  public void testFlipBitNegativeInside2() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = -1;
+    int number = 45;
+    byte rBytes[] = {-2, 127, -57, -101, 1, 75, -90, -14, -92, -4, 14, -36, -26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.flipBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * flipBit(int n) inside a negative number with all ones in bit representation
+   */
+  public void testFlipBitNegativeInside3() {
+    String as = "-18446744073709551615";
+    String res = "-18446744073709551611";
+    int number = 2;
+    BigInteger aNumber = new BigInteger(as);
+    BigInteger result = aNumber.flipBit(number);
+    assertEquals(res, result.toString());
+  }
+
+  /**
+   * flipBit(0) in the negative number of length 1 with all ones in bit
+   * representation. the resulting number's length is 2.
+   */
+  public void testFlipBitNegativeInside4() {
+    String as = "-4294967295";
+    String res = "-4294967296";
+    int number = 0;
+    BigInteger aNumber = new BigInteger(as);
+    BigInteger result = aNumber.flipBit(number);
+    assertEquals(res, result.toString());
+  }
+
+  /**
+   * flipBit(0) in the negative number of length 2 with all ones in bit
+   * representation. the resulting number's length is 3.
+   */
+  public void testFlipBitNegativeInside5() {
+    String as = "-18446744073709551615";
+    String res = "-18446744073709551616";
+    int number = 0;
+    BigInteger aNumber = new BigInteger(as);
+    BigInteger result = aNumber.flipBit(number);
+    assertEquals(res, result.toString());
+  }
+
+  /**
+   * flipBit(int n) outside a negative number
+   */
+  public void testFlipBitNegativeOutside1() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = -1;
+    int number = 150;
+    byte rBytes[] = {
+        -65, -1, -1, -1, -1, -1, -2, 127, -57, -101, 1, 75, -90, -46, -92, -4,
+        14, -36, -26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.flipBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * flipBit(int n) outside a negative number
+   */
+  public void testFlipBitNegativeOutside2() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = -1;
+    int number = 191;
+    byte rBytes[] = {
+        -1, 127, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, 127, -57, -101, 1,
+        75, -90, -46, -92, -4, 14, -36, -26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.flipBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * flipBit(int n) inside a positive number
+   */
+  public void testFlipBitPositiveInside1() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 15;
+    byte rBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, -93, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.flipBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * flipBit(int n) inside a positive number
+   */
+  public void testFlipBitPositiveInside2() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 45;
+    byte rBytes[] = {1, -128, 56, 100, -2, -76, 89, 13, 91, 3, -15, 35, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.flipBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * flipBit(int n) outside a positive number
+   */
+  public void testFlipBitPositiveOutside1() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 150;
+    byte rBytes[] = {
+        64, 0, 0, 0, 0, 0, 1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35,
+        26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.flipBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * flipBit(int n) outside a positive number
+   */
+  public void testFlipBitPositiveOutside2() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 191;
+    byte rBytes[] = {
+        0, -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -128, 56, 100, -2, -76, 89,
+        45, 91, 3, -15, 35, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.flipBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * flipBit(int n) zero
+   */
+  public void testFlipBitZero() {
+    byte aBytes[] = {0};
+    int aSign = 0;
+    int number = 0;
+    byte rBytes[] = {1};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.flipBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * flipBit(int n) outside zero
+   */
+  public void testFlipBitZeroOutside1() {
+    byte aBytes[] = {0};
+    int aSign = 0;
+    int number = 62;
+    byte rBytes[] = {64, 0, 0, 0, 0, 0, 0, 0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.flipBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue("incorrect value", resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * flipBit(int n) outside zero
+   */
+  public void testFlipBitZeroOutside2() {
+    byte aBytes[] = {0};
+    int aSign = 0;
+    int number = 63;
+    byte rBytes[] = {0, -128, 0, 0, 0, 0, 0, 0, 0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.flipBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue("incorrect value", resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * setBit: check the case when the number of bit to be set can be represented
+   * as n * 32 + 31, where n is an arbitrary integer. Here 191 = 5 * 32 + 31
+   */
+  public void testSetBitBug1331() {
+    BigInteger result = BigInteger.valueOf(0L).setBit(191);
+    assertEquals("incorrect value",
+        "3138550867693340381917894711603833208051177722232017256448",
+        result.toString());
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * setBit(int n) of a negative n
+   */
+  public void testSetBitException() {
+    byte aBytes[] = {-1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = -7;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    try {
+      aNumber.setBit(number);
+      fail("ArithmeticException has not been caught");
+    } catch (ArithmeticException e) {
+      assertEquals("Improper exception message", "Negative bit address",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * setBit(int n) the leftmost bit in a negative number
+   */
+  public void testSetBitLeftmostNegative() {
+    byte aBytes[] = {1, -128, 56, 100, -15, 35, 26};
+    int aSign = -1;
+    int number = 48;
+    byte rBytes[] = {-1, 127, -57, -101, 14, -36, -26, 49};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.setBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * setBit(int n) inside a negative number
+   */
+  public void testSetBitNegativeInside1() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = -1;
+    int number = 15;
+    byte rBytes[] = {-2, 127, -57, -101, 1, 75, -90, -46, -92, -4, 14, -36, -26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.setBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * setBit(int n) inside a negative number
+   */
+  public void testSetBitNegativeInside2() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = -1;
+    int number = 44;
+    byte rBytes[] = {-2, 127, -57, -101, 1, 75, -90, -46, -92, -4, 14, -36, -26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.setBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * setBit(int n) inside a negative number with all ones in bit representation
+   */
+  public void testSetBitNegativeInside3() {
+    String as = "-18446744073709551615";
+    String res = "-18446744073709551611";
+    int number = 2;
+    BigInteger aNumber = new BigInteger(as);
+    BigInteger result = aNumber.setBit(number);
+    assertEquals(res, result.toString());
+  }
+
+  /**
+   * setBit(0) in the negative number of length 1 with all ones in bit
+   * representation. the resulting number's length is 2.
+   */
+  public void testSetBitNegativeInside4() {
+    String as = "-4294967295";
+    int number = 0;
+    BigInteger aNumber = new BigInteger(as);
+    BigInteger result = aNumber.setBit(number);
+    assertEquals(as, result.toString());
+  }
+
+  /**
+   * setBit(0) in the negative number of length 2 with all ones in bit
+   * representation. the resulting number's length is 3.
+   */
+  public void testSetBitNegativeInside5() {
+    String as = "-18446744073709551615";
+    int number = 0;
+    BigInteger aNumber = new BigInteger(as);
+    BigInteger result = aNumber.setBit(number);
+    assertEquals(as, result.toString());
+  }
+
+  /**
+   * setBit(int n) outside a negative number
+   */
+  public void testSetBitNegativeOutside1() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = -1;
+    int number = 150;
+    byte rBytes[] = {-2, 127, -57, -101, 1, 75, -90, -46, -92, -4, 14, -36, -26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.setBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * setBit(int n) outside a negative number
+   */
+  public void testSetBitNegativeOutside2() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = -1;
+    int number = 191;
+    byte rBytes[] = {-2, 127, -57, -101, 1, 75, -90, -46, -92, -4, 14, -36, -26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.setBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * setBit(int n) inside a positive number
+   */
+  public void testSetBitPositiveInside1() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 20;
+    byte rBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.setBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * setBit(int n) inside a positive number
+   */
+  public void testSetBitPositiveInside2() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 17;
+    byte rBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -13, 35, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.setBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * setBit(int n) inside a positive number
+   */
+  public void testSetBitPositiveInside3() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 45;
+    byte rBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.setBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * setBit(int n) inside a positive number
+   */
+  public void testSetBitPositiveInside4() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 50;
+    byte rBytes[] = {1, -128, 56, 100, -2, -76, 93, 45, 91, 3, -15, 35, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.setBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * setBit(int n) outside a positive number
+   */
+  public void testSetBitPositiveOutside1() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 150;
+    byte rBytes[] = {
+        64, 0, 0, 0, 0, 0, 1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35,
+        26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.setBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * setBit(int n) outside a positive number
+   */
+  public void testSetBitPositiveOutside2() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 223;
+    byte rBytes[] = {
+        0, -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -128, 56, 100,
+        -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.setBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * setBit(int n) the leftmost bit in a positive number
+   */
+  public void testSetBitTopPositive() {
+    byte aBytes[] = {1, -128, 56, 100, -15, 35, 26};
+    int aSign = 1;
+    int number = 63;
+    byte rBytes[] = {0, -128, 1, -128, 56, 100, -15, 35, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.setBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * setBit(int n) outside zero
+   */
+  public void testSetBitZero() {
+    byte aBytes[] = {0};
+    int aSign = 0;
+    int number = 0;
+    byte rBytes[] = {1};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.setBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * setBit(int n) outside zero
+   */
+  public void testSetBitZeroOutside1() {
+    byte aBytes[] = {0};
+    int aSign = 0;
+    int number = 95;
+    byte rBytes[] = {0, -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.setBit(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * shiftLeft(int n), n = 0
+   */
+  public void testShiftLeft1() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 0;
+    byte rBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.shiftLeft(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * shiftLeft(int n), n < 0
+   */
+  public void testShiftLeft2() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = -27;
+    byte rBytes[] = {48, 7, 12, -97, -42, -117, 37, -85, 96};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.shiftLeft(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * shiftLeft(int n) a positive number, n > 0
+   */
+  public void testShiftLeft3() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 27;
+    byte rBytes[] = {
+        12, 1, -61, 39, -11, -94, -55, 106, -40, 31, -119, 24, -48, 0, 0, 0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.shiftLeft(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * shiftLeft(int n) a positive number, n > 0
+   */
+  public void testShiftLeft4() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 45;
+    byte rBytes[] = {
+        48, 7, 12, -97, -42, -117, 37, -85, 96, 126, 36, 99, 64, 0, 0, 0, 0, 0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.shiftLeft(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * shiftLeft(int n) a negative number, n > 0
+   */
+  public void testShiftLeft5() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = -1;
+    int number = 45;
+    byte rBytes[] = {
+        -49, -8, -13, 96, 41, 116, -38, 84, -97, -127, -37, -100, -64, 0, 0, 0,
+        0, 0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.shiftLeft(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * shiftRight(int n), n = 0
+   */
+  public void testShiftRight1() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 0;
+    byte rBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.shiftRight(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * shiftRight(int n), n < 0
+   */
+  public void testShiftRight2() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = -27;
+    byte rBytes[] = {
+        12, 1, -61, 39, -11, -94, -55, 106, -40, 31, -119, 24, -48, 0, 0, 0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.shiftRight(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * shiftRight(int n), 0 < n < 32
+   */
+  public void testShiftRight3() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 27;
+    byte rBytes[] = {48, 7, 12, -97, -42, -117, 37, -85, 96};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.shiftRight(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * shiftRight(int n), n > 32
+   */
+  public void testShiftRight4() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 45;
+    byte rBytes[] = {12, 1, -61, 39, -11, -94, -55};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.shiftRight(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * shiftRight(int n), n is greater than bitLength()
+   */
+  public void testShiftRight5() {
+    byte aBytes[] = {1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 300;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.shiftRight(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+
+  /**
+   * shiftRight a negative number; shift distance is NOT multiple of 32; shifted
+   * bits are NOT zeroes.
+   */
+  public void testShiftRightNegNonZeroes() {
+    byte aBytes[] = {
+        1, -128, 56, 100, -2, -76, 89, 45, 91, 0, 0, 0, 0, 0, 0, 0, 0};
+    int aSign = -1;
+    int number = 68;
+    byte rBytes[] = {-25, -4, 121, -80, 20, -70, 109, 42};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.shiftRight(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * shiftRight a negative number; shift distance is multiple of 32; shifted
+   * bits are NOT zeroes.
+   */
+  public void testShiftRightNegNonZeroesMul32() {
+    byte aBytes[] = {
+        1, -128, 56, 100, -2, -76, 89, 45, 91, 1, 0, 0, 0, 0, 0, 0, 0};
+    int aSign = -1;
+    int number = 64;
+    byte rBytes[] = {-2, 127, -57, -101, 1, 75, -90, -46, -92};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.shiftRight(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * shiftRight a negative number; shift distance is NOT multiple of 32; shifted
+   * bits are zeroes.
+   */
+  public void testShiftRightNegZeroes() {
+    byte aBytes[] = {
+        1, -128, 56, 100, -2, -76, 89, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    int aSign = -1;
+    int number = 68;
+    byte rBytes[] = {-25, -4, 121, -80, 20, -70, 109, 48};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.shiftRight(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * shiftRight a negative number; shift distance is multiple of 32; shifted
+   * bits are zeroes.
+   */
+  public void testShiftRightNegZeroesMul32() {
+    byte aBytes[] = {
+        1, -128, 56, 100, -2, -76, 89, 45, 91, 0, 0, 0, 0, 0, 0, 0, 0};
+    int aSign = -1;
+    int number = 64;
+    byte rBytes[] = {-2, 127, -57, -101, 1, 75, -90, -46, -91};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger result = aNumber.shiftRight(number);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * testBit(int n) of a negative n
+   */
+  public void testTestBitException() {
+    byte aBytes[] = {-1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = -7;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    try {
+      aNumber.testBit(number);
+      fail("ArithmeticException has not been caught");
+    } catch (ArithmeticException e) {
+      assertEquals("Improper exception message", "Negative bit address",
+          e.getMessage());
+    }
+  }
+
+  /**
+   * testBit(int n) of a negative number
+   */
+  public void testTestBitNegative1() {
+    byte aBytes[] = {-1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = -1;
+    int number = 7;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    assertTrue(aNumber.testBit(number));
+  }
+
+  /**
+   * testBit(int n) of a positive n
+   */
+  public void testTestBitNegative2() {
+    byte aBytes[] = {-1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = -1;
+    int number = 45;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    assertTrue(!aNumber.testBit(number));
+  }
+
+  /**
+   * testBit(int n) of a positive n, n > bitLength()
+   */
+  public void testTestBitNegative3() {
+    byte aBytes[] = {-1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = -1;
+    int number = 300;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    assertTrue(aNumber.testBit(number));
+  }
+
+  /**
+   * testBit(int n) of a positive number
+   */
+  public void testTestBitPositive1() {
+    byte aBytes[] = {-1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 7;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    assertTrue(!aNumber.testBit(number));
+  }
+
+  /**
+   * testBit(int n) of a positive number
+   */
+  public void testTestBitPositive2() {
+    byte aBytes[] = {-1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 45;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    assertTrue(aNumber.testBit(number));
+  }
+
+  /**
+   * testBit(int n) of a positive number, n > bitLength()
+   */
+  public void testTestBitPositive3() {
+    byte aBytes[] = {-1, -128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26};
+    int aSign = 1;
+    int number = 300;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    assertTrue(!aNumber.testBit(number));
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerOrTest.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerOrTest.java
new file mode 100644
index 0000000..e67cb2e
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerOrTest.java
@@ -0,0 +1,467 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigInteger;
+
+/**
+ * Class: java.math.BigInteger Method: or
+ */
+public class BigIntegerOrTest extends EmulTestBase {
+  /**
+   * Or for two negative numbers; the first is longer
+   */
+  public void testNegNegFirstLonger() {
+    byte aBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {
+        -1, 1, 75, -89, -45, -2, -3, -18, -36, -17, -10, -3, -6, -7, -21};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Or for two negative numbers; the first is shorter
+   */
+  public void testNegNegFirstShorter() {
+    byte aBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    byte bBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {
+        -1, 1, 75, -89, -45, -2, -3, -18, -36, -17, -10, -3, -6, -7, -21};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Or for two negative numbers of the same length
+   */
+  public void testNegNegSameLength() {
+    byte aBytes[] = {-128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {
+        -1, 127, -57, -101, -5, -5, -18, -38, -17, -2, -65, -2, -11, -3};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Or for a negative number and zero
+   */
+  public void testNegPos() {
+    byte aBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    byte bBytes[] = {0};
+    int aSign = -1;
+    int bSign = 0;
+    byte rBytes[] = {
+        -1, 1, 2, 3, 3, -6, -15, -24, -40, -49, -58, -67, -6, -15, -23};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Or for a negative and a positive numbers; the first is longer
+   */
+  public void testNegPosFirstLonger() {
+    byte aBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {
+        -1, 127, -10, -57, -101, -1, -1, -2, -2, -91, -2, 31, -1, -11, 125,
+        -22, -83, 30, 95};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Or for two negative numbers; the first is shorter
+   */
+  public void testNegPosFirstShorter() {
+    byte aBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    byte bBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {-74, 91, 47, -5, -13, -7, -5, -33, -49, -65, -1, -9, -3};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Or for two numbers of different signs and the same length
+   */
+  public void testNegPosSameLength() {
+    byte aBytes[] = {-128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {-1, 5, 79, -73, -9, -76, -3, 78, -35, -17, 119};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Or for one and one
+   */
+  public void testOneOne() {
+    byte aBytes[] = {1};
+    byte bBytes[] = {1};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {1};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Or for a positive and a negative numbers; the first is longer
+   */
+  public void testPosNegFirstLonger() {
+    byte aBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {-74, 91, 47, -5, -13, -7, -5, -33, -49, -65, -1, -9, -3};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Or for a positive and a negative number; the first is shorter
+   */
+  public void testPosNegFirstShorter() {
+    byte aBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    byte bBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {
+        -1, 127, -10, -57, -101, -1, -1, -2, -2, -91, -2, 31, -1, -11, 125,
+        -22, -83, 30, 95};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Or for two numbers of different signs and the same length
+   */
+  public void testPosNegSameLength() {
+    byte aBytes[] = {-128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {
+        -1, 1, -126, 59, 103, -2, -11, -7, -3, -33, -57, -3, -5, -5, -21};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Or for two positive numbers; the first is longer
+   */
+  public void testPosPosFirstLonger() {
+    byte aBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {
+        0, -128, 9, 56, 100, -2, -3, -3, -3, 95, 15, -9, 39, 58, -69, 87, 87,
+        -17, -73};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Or for two positive numbers; the first is shorter
+   */
+  public void testPosPosFirstShorter() {
+    byte aBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    byte bBytes[] = {
+        -128, 9, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117, 23, 87,
+        -25, -75};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {
+        0, -128, 9, 56, 100, -2, -3, -3, -3, 95, 15, -9, 39, 58, -69, 87, 87,
+        -17, -73};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Or for two positive numbers of the same length
+   */
+  public void testPosPosSameLength() {
+    byte aBytes[] = {-128, 56, 100, -2, -76, 89, 45, 91, 3, -15, 35, 26, -117};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {
+        0, -2, -3, -4, -4, -1, -66, 95, 47, 123, 59, -13, 39, 30, -97};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Or for a positive number and zero
+   */
+  public void testPosZero() {
+    byte aBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    byte bBytes[] = {0};
+    int aSign = 1;
+    int bSign = 0;
+    byte rBytes[] = {0, -2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  public void testRegression() {
+    // Regression test for HARMONY-1996
+    BigInteger x = new BigInteger("-1023");
+    BigInteger r1 = x.and((BigInteger.ZERO.not()).shiftLeft(32));
+    BigInteger r3 = x.and((BigInteger.ZERO.not().shiftLeft(32)).not());
+    BigInteger result = r1.or(r3);
+    assertEquals(x, result);
+  }
+
+  /**
+   * Or for zero and a negative number
+   */
+  public void testZeroNeg() {
+    byte aBytes[] = {0};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = 0;
+    int bSign = -1;
+    byte rBytes[] = {
+        -1, 1, 2, 3, 3, -6, -15, -24, -40, -49, -58, -67, -6, -15, -23};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", -1, result.signum());
+  }
+
+  /**
+   * Or for zero and one
+   */
+  public void testZeroOne() {
+    byte aBytes[] = {0};
+    byte bBytes[] = {1};
+    int aSign = 0;
+    int bSign = 1;
+    byte rBytes[] = {1};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Or for zero and a positive number
+   */
+  public void testZeroPos() {
+    byte aBytes[] = {0};
+    byte bBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    int aSign = 0;
+    int bSign = 1;
+    byte rBytes[] = {0, -2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 1, result.signum());
+  }
+
+  /**
+   * Or for zero and zero
+   */
+  public void testZeroZero() {
+    byte aBytes[] = {0};
+    byte bBytes[] = {0};
+    int aSign = 0;
+    int bSign = 0;
+    byte rBytes[] = {0};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.or(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals("incorrect sign", 0, result.signum());
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerSubtractTest.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerSubtractTest.java
new file mode 100644
index 0000000..8e6290a
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerSubtractTest.java
@@ -0,0 +1,547 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigInteger;
+
+/**
+ * Class: java.math.BigInteger Method: subtract
+ */
+public class BigIntegerSubtractTest extends EmulTestBase {
+  /**
+   * Subtract two positive numbers of the same length. The first is greater.
+   */
+  public void testCase1() {
+    byte aBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    byte bBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {9, 18, 27, 36, 45, 54, 63, 9, 18, 27};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(1, result.signum());
+  }
+
+  /**
+   * Subtract two positive numbers of different length. The second is longer.
+   */
+  public void testCase10() {
+    byte aBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    byte bBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(-1, result.signum());
+  }
+
+  /**
+   * Subtract two numbers of different length and different signs. The first is
+   * positive. The first is greater in absolute value.
+   */
+  public void testCase11() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {1, 2, 3, 4, 15, 26, 37, 41, 52, 63, 74, 15, 26, 37};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(1, result.signum());
+  }
+
+  /**
+   * Subtract two numbers of the same length and different signs. The first is
+   * positive. The second is greater in absolute value.
+   */
+  public void testCase12() {
+    byte aBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    byte bBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {1, 2, 3, 4, 15, 26, 37, 41, 52, 63, 74, 15, 26, 37};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(1, result.signum());
+  }
+
+  /**
+   * Subtract two numbers of different length and different signs. The first is
+   * negative. The first is longer.
+   */
+  public void testCase13() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {
+        -2, -3, -4, -5, -16, -27, -38, -42, -53, -64, -75, -16, -27, -37};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(-1, result.signum());
+  }
+
+  /**
+   * Subtract two numbers of the same length and different signs. The first is
+   * negative. The second is longer.
+   */
+  public void testCase14() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {
+        -2, -3, -4, -5, -16, -27, -38, -42, -53, -64, -75, -16, -27, -37};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(-1, result.signum());
+  }
+
+  /**
+   * Subtract two negative numbers of different length. The first is longer.
+   */
+  public void testCase15() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {-2, -3, -4, -4, 5, 14, 23, 39, 48, 57, 66, 5, 14, 23};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(-1, result.signum());
+  }
+
+  /**
+   * Subtract two negative numbers of different length. The second is longer.
+   */
+  public void testCase16() {
+    byte aBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    byte bBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {1, 2, 3, 3, -6, -15, -24, -40, -49, -58, -67, -6, -15, -23};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(1, result.signum());
+  }
+
+  /**
+   * Subtract two positive equal in absolute value numbers.
+   */
+  public void testCase17() {
+    byte aBytes[] = {-120, 34, 78, -23, -111, 45, 127, 23, 45, -3};
+    byte bBytes[] = {-120, 34, 78, -23, -111, 45, 127, 23, 45, -3};
+    byte rBytes[] = {0};
+    int aSign = 1;
+    int bSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(0, result.signum());
+  }
+
+  /**
+   * Subtract zero from a number. The number is positive.
+   */
+  public void testCase18() {
+    byte aBytes[] = {120, 34, 78, -23, -111, 45, 127, 23, 45, -3};
+    byte bBytes[] = {0};
+    byte rBytes[] = {120, 34, 78, -23, -111, 45, 127, 23, 45, -3};
+    int aSign = 1;
+    int bSign = 0;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(1, result.signum());
+  }
+
+  /**
+   * Subtract a number from zero. The number is negative.
+   */
+  public void testCase19() {
+    byte aBytes[] = {0};
+    byte bBytes[] = {120, 34, 78, -23, -111, 45, 127, 23, 45, -3};
+    byte rBytes[] = {120, 34, 78, -23, -111, 45, 127, 23, 45, -3};
+    int aSign = 0;
+    int bSign = -1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(1, result.signum());
+  }
+
+  /**
+   * Subtract two positive numbers of the same length. The second is greater.
+   */
+  public void testCase2() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {-10, -19, -28, -37, -46, -55, -64, -10, -19, -27};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(-1, result.signum());
+  }
+
+  /**
+   * Subtract zero from zero.
+   */
+  public void testCase20() {
+    byte aBytes[] = {0};
+    byte bBytes[] = {0};
+    byte rBytes[] = {0};
+    int aSign = 0;
+    int bSign = 0;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(0, result.signum());
+  }
+
+  /**
+   * Subtract ZERO from a number. The number is positive.
+   */
+  public void testCase21() {
+    byte aBytes[] = {120, 34, 78, -23, -111, 45, 127, 23, 45, -3};
+    byte rBytes[] = {120, 34, 78, -23, -111, 45, 127, 23, 45, -3};
+    int aSign = 1;
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = BigInteger.ZERO;
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(1, result.signum());
+  }
+
+  /**
+   * Subtract a number from ZERO. The number is negative.
+   */
+  public void testCase22() {
+    byte bBytes[] = {120, 34, 78, -23, -111, 45, 127, 23, 45, -3};
+    byte rBytes[] = {120, 34, 78, -23, -111, 45, 127, 23, 45, -3};
+    int bSign = -1;
+    BigInteger aNumber = BigInteger.ZERO;
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(1, result.signum());
+  }
+
+  /**
+   * Subtract ZERO from ZERO.
+   */
+  public void testCase23() {
+    byte rBytes[] = {0};
+    BigInteger aNumber = BigInteger.ZERO;
+    BigInteger bNumber = BigInteger.ZERO;
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(0, result.signum());
+  }
+
+  /**
+   * Subtract ONE from ONE.
+   */
+  public void testCase24() {
+    byte rBytes[] = {0};
+    BigInteger aNumber = BigInteger.ONE;
+    BigInteger bNumber = BigInteger.ONE;
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(0, result.signum());
+  }
+
+  /**
+   * Subtract two numbers so that borrow is 1.
+   */
+  public void testCase25() {
+    byte aBytes[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+    byte bBytes[] = {-128, -128, -128, -128, -128, -128, -128, -128, -128};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {-128, 127, 127, 127, 127, 127, 127, 127, 127};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(-1, result.signum());
+  }
+
+  /**
+   * Subtract two numbers of the same length and different signs. The first is
+   * positive. The first is greater in absolute value.
+   */
+  public void testCase3() {
+    byte aBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    byte bBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {11, 22, 33, 44, 55, 66, 77, 11, 22, 33};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(1, result.signum());
+  }
+
+  /**
+   * Subtract two numbers of the same length and different signs. The first is
+   * positive. The second is greater in absolute value.
+   */
+  public void testCase4() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = 1;
+    int bSign = -1;
+    byte rBytes[] = {11, 22, 33, 44, 55, 66, 77, 11, 22, 33};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(1, result.signum());
+  }
+
+  /**
+   * Subtract two negative numbers of the same length. The first is greater in
+   * absolute value.
+   */
+  public void testCase5() {
+    byte aBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    byte bBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {-10, -19, -28, -37, -46, -55, -64, -10, -19, -27};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(-1, result.signum());
+  }
+
+  /**
+   * Subtract two negative numbers of the same length. The second is greater in
+   * absolute value.
+   */
+  public void testCase6() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = -1;
+    int bSign = -1;
+    byte rBytes[] = {9, 18, 27, 36, 45, 54, 63, 9, 18, 27};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(1, result.signum());
+  }
+
+  /**
+   * Subtract two numbers of the same length and different signs. The first is
+   * negative. The first is greater in absolute value.
+   */
+  public void testCase7() {
+    byte aBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    byte bBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {-12, -23, -34, -45, -56, -67, -78, -12, -23, -33};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(-1, result.signum());
+  }
+
+  /**
+   * Subtract two numbers of the same length and different signs. The first is
+   * negative. The second is greater in absolute value.
+   */
+  public void testCase8() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = -1;
+    int bSign = 1;
+    byte rBytes[] = {-12, -23, -34, -45, -56, -67, -78, -12, -23, -33};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(-1, result.signum());
+  }
+
+  /**
+   * Subtract two positive numbers of different length. The first is longer.
+   */
+  public void testCase9() {
+    byte aBytes[] = {1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7};
+    byte bBytes[] = {10, 20, 30, 40, 50, 60, 70, 10, 20, 30};
+    int aSign = 1;
+    int bSign = 1;
+    byte rBytes[] = {1, 2, 3, 3, -6, -15, -24, -40, -49, -58, -67, -6, -15, -23};
+    BigInteger aNumber = new BigInteger(aSign, aBytes);
+    BigInteger bNumber = new BigInteger(bSign, bBytes);
+    BigInteger result = aNumber.subtract(bNumber);
+    byte resBytes[] = new byte[rBytes.length];
+    resBytes = result.toByteArray();
+    for (int i = 0; i < resBytes.length; i++) {
+      assertTrue(resBytes[i] == rBytes[i]);
+    }
+    assertEquals(1, result.signum());
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerToStringTest.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerToStringTest.java
new file mode 100644
index 0000000..958025c
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerToStringTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigInteger;
+
+/**
+ * Class: java.math.BigInteger Method: toString(int radix)
+ */
+public class BigIntegerToStringTest extends EmulTestBase {
+  /**
+   * test negative number of radix 10
+   */
+  public void testRadix10Neg() {
+    String value = "-2489756308572364789878394872984";
+    int radix = 16;
+    BigInteger aNumber = new BigInteger(value, radix);
+    String result = aNumber.toString(radix);
+    assertTrue(result.equals(value));
+  }
+
+  /**
+   * test positive number of radix 10
+   */
+  public void testRadix10Pos() {
+    String value = "2387627892347567398736473476";
+    int radix = 16;
+    BigInteger aNumber = new BigInteger(value, radix);
+    String result = aNumber.toString(radix);
+    assertTrue(result.equals(value));
+  }
+
+  /**
+   * test negative number of radix 16
+   */
+  public void testRadix16Neg() {
+    String value = "-287628a883451b800865c67e8d7ff20";
+    int radix = 16;
+    BigInteger aNumber = new BigInteger(value, radix);
+    String result = aNumber.toString(radix);
+    assertTrue(result.equals(value));
+  }
+
+  /**
+   * test positive number of radix 16
+   */
+  public void testRadix16Pos() {
+    String value = "287628a883451b800865c67e8d7ff20";
+    int radix = 16;
+    BigInteger aNumber = new BigInteger(value, radix);
+    String result = aNumber.toString(radix);
+    assertTrue(result.equals(value));
+  }
+
+  /**
+   * test negative number of radix 24
+   */
+  public void testRadix24Neg() {
+    String value = "-287628a88gmn3451b8ijk00865c67e8d7ff20";
+    int radix = 24;
+    BigInteger aNumber = new BigInteger(value, radix);
+    String result = aNumber.toString(radix);
+    assertTrue(result.equals(value));
+  }
+
+  /**
+   * test positive number of radix 24
+   */
+  public void testRadix24Pos() {
+    String value = "287628a883451bg80ijhk0865c67e8d7ff20";
+    int radix = 24;
+    BigInteger aNumber = new BigInteger(value, radix);
+    String result = aNumber.toString(radix);
+    assertTrue(result.equals(value));
+  }
+
+  /**
+   * test negative number of radix 2
+   */
+  public void testRadix2Neg() {
+    String value = "-101001100010010001001010101110000101010110001010010101010101010101010101010101010101010101010010101";
+    int radix = 2;
+    BigInteger aNumber = new BigInteger(value, radix);
+    String result = aNumber.toString(radix);
+    assertTrue(result.equals(value));
+  }
+
+  /**
+   * test positive number of radix 2
+   */
+  public void testRadix2Pos() {
+    String value = "101000011111000000110101010101010101010001001010101010101010010101010101010000100010010";
+    int radix = 2;
+    BigInteger aNumber = new BigInteger(value, radix);
+    String result = aNumber.toString(radix);
+    assertTrue(result.equals(value));
+  }
+
+  /**
+   * test negative number of radix 24
+   */
+  public void testRadix36Neg() {
+    String value = "-uhguweut98iu4h3478tq3985pq98yeiuth33485yq4aiuhalai485yiaehasdkr8tywi5uhslei8";
+    int radix = 36;
+    BigInteger aNumber = new BigInteger(value, radix);
+    String result = aNumber.toString(radix);
+    assertTrue(result.equals(value));
+  }
+
+  /**
+   * test positive number of radix 24
+   */
+  public void testRadix36Pos() {
+    String value = "23895lt45y6vhgliuwhgi45y845htsuerhsi4586ysuerhtsio5y68peruhgsil4568ypeorihtse48y6";
+    int radix = 36;
+    BigInteger aNumber = new BigInteger(value, radix);
+    String result = aNumber.toString(radix);
+    assertTrue(result.equals(value));
+  }
+
+  /**
+   * If 36 < radix < 2 it should be set to 10
+   */
+  public void testRadixOutOfRange() {
+    String value = "442429234853876401";
+    int radix = 10;
+    BigInteger aNumber = new BigInteger(value, radix);
+    String result = aNumber.toString(45);
+    assertTrue(result.equals(value));
+  }
+}
diff --git a/user/test/com/google/gwt/emultest/java/math/BigIntegerXorTest.java b/user/test/com/google/gwt/emultest/java/math/BigIntegerXorTest.java
new file mode 100644
index 0000000..028fdfa
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/math/BigIntegerXorTest.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.
+ * 
+ * INCLUDES MODIFICATIONS BY GOOGLE.
+ */
+/**
+ * author Elena Semukhina
+ */
+package com.google.gwt.emultest.java.math;
+
+import com.google.gwt.emultest.java.util.EmulTestBase;
+
+import java.math.BigInteger;
+
+/**
+ * Class: java.math.BigInteger Method: xor
+ */
+public class BigIntegerXorTest extends EmulTestBase {
+  /**
+   * Xor for two negative numbers; the first is longer
+   */
+  public void testNegNegFirstLonger() {
+    String numA = "-2837462783428374767845648748973847593874837948575684767";
+    String numB = "-293478573489347658763745839457637";
+    String res = "2837462783428374767845615168483972194300564226167553530";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+
+  /**
+   * Xor for two negative numbers; the first is shorter
+   */
+  public void testNegNegFirstShorter() {
+    String numA = "293478573489347658763745839457637";
+    String numB = "2837462783428374767845648748973847593874837948575684767";
+    String res = "2837462783428374767845615168483972194300564226167553530";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+
+  /**
+   * Xor for two negative numbers of the same length
+   */
+  public void testNegNegSameLength() {
+    String numA = "-283746278342837476784564875684767";
+    String numB = "-293478573489347658763745839457637";
+    String res = "71412358434940908477702819237626";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+
+  /**
+   * Xor for a negative number and zero
+   */
+  public void testNegPos() {
+    String numA = "-27384627835298756289327365";
+    String numB = "0";
+    String res = "-27384627835298756289327365";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+
+  /**
+   * Xor for a negative and a positive numbers; the first is longer
+   */
+  public void testNegPosFirstLonger() {
+    String numA = "-2837462783428374767845648748973847593874837948575684767";
+    String numB = "293478573489347658763745839457637";
+    String res = "-2837462783428374767845615168483972194300564226167553532";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+
+  /**
+   * Xor for two negative numbers; the first is shorter
+   */
+  public void testNegPosFirstShorter() {
+    String numA = "-293478573489347658763745839457637";
+    String numB = "2837462783428374767845648748973847593874837948575684767";
+    String res = "-2837462783428374767845615168483972194300564226167553532";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+
+  /**
+   * Xor for two numbers of different signs and the same length
+   */
+  public void testNegPosSameLength() {
+    String numA = "-283746278342837476784564875684767";
+    String numB = "293478573489347658763745839457637";
+    String res = "-71412358434940908477702819237628";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+
+  /**
+   * Xor for one and one
+   */
+  public void testOneOne() {
+    String numA = "1";
+    String numB = "1";
+    String res = "0";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+
+  /**
+   * Xor for a positive and a negative numbers; the first is longer
+   */
+  public void testPosNegFirstLonger() {
+    String numA = "2837462783428374767845648748973847593874837948575684767";
+    String numB = "-293478573489347658763745839457637";
+    String res = "-2837462783428374767845615168483972194300564226167553532";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+
+  /**
+   * Xor for a positive and a negative number; the first is shorter
+   */
+  public void testPosNegFirstShorter() {
+    String numA = "293478573489347658763745839457637";
+    String numB = "-2837462783428374767845648748973847593874837948575684767";
+    String res = "-2837462783428374767845615168483972194300564226167553532";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+
+  /**
+   * Xor for two numbers of different signs and the same length
+   */
+  public void testPosNegSameLength() {
+    String numA = "283746278342837476784564875684767";
+    String numB = "-293478573489347658763745839457637";
+    String res = "-71412358434940908477702819237628";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+
+  /**
+   * Xor for two positive numbers; the first is longer
+   */
+  public void testPosPosFirstLonger() {
+    String numA = "2837462783428374767845648748973847593874837948575684767";
+    String numB = "293478573489347658763745839457637";
+    String res = "2837462783428374767845615168483972194300564226167553530";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+
+  /**
+   * Xor for two positive numbers; the first is shorter
+   */
+  public void testPosPosFirstShorter() {
+    String numA = "293478573489347658763745839457637";
+    String numB = "2837462783428374767845648748973847593874837948575684767";
+    String res = "2837462783428374767845615168483972194300564226167553530";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+
+  /**
+   * Xor for two positive numbers of the same length
+   */
+  public void testPosPosSameLength() {
+    String numA = "283746278342837476784564875684767";
+    String numB = "293478573489347658763745839457637";
+    String res = "71412358434940908477702819237626";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+
+  /**
+   * Xor for a positive number and zero
+   */
+  public void testPosZero() {
+    String numA = "27384627835298756289327365";
+    String numB = "0";
+    String res = "27384627835298756289327365";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+
+  /**
+   * Xor for zero and a negative number
+   */
+  public void testZeroNeg() {
+    String numA = "0";
+    String numB = "-27384627835298756289327365";
+    String res = "-27384627835298756289327365";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+
+  /**
+   * Xor for zero and one
+   */
+  public void testZeroOne() {
+    String numA = "0";
+    String numB = "1";
+    String res = "1";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+
+  /**
+   * Xor for zero and a positive number
+   */
+  public void testZeroPos() {
+    String numA = "0";
+    String numB = "27384627835298756289327365";
+    String res = "27384627835298756289327365";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+
+  /**
+   * Xor for zero and zero
+   */
+  public void testZeroZero() {
+    String numA = "0";
+    String numB = "0";
+    String res = "0";
+    BigInteger aNumber = new BigInteger(numA);
+    BigInteger bNumber = new BigInteger(numB);
+    BigInteger result = aNumber.xor(bNumber);
+    assertTrue(res.equals(result.toString()));
+  }
+}
diff --git a/user/test/com/google/gwt/i18n/client/I18NTest.java b/user/test/com/google/gwt/i18n/client/I18NTest.java
index 48d6f3a..51a10ec 100644
--- a/user/test/com/google/gwt/i18n/client/I18NTest.java
+++ b/user/test/com/google/gwt/i18n/client/I18NTest.java
@@ -33,6 +33,8 @@
 import com.google.gwt.i18n.client.resolutiontest.Inners.InnerClass.LocalizableInnerInner;
 import com.google.gwt.junit.client.GWTTestCase;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
@@ -559,6 +561,21 @@
     assertEquals("estednay underscoray", m.nestedUnderscore());
   }
 
+  /**
+   * Test that messages works with Number subclasses.
+   */
+  public void testNumber() {
+    TestAnnotatedMessages m = GWT.create(TestAnnotatedMessages.class);
+    BigInteger intVal = new BigInteger("1000000000000000000");
+    assertEquals("Total is US$1,000,000,000,000,000,000.00",
+        m.withNumberCurrency(intVal));
+    BigDecimal decVal = new BigDecimal("1000000000000000000.01");
+    assertEquals("Total is US$1,000,000,000,000,000,000.01",
+        m.withNumberCurrency(decVal));
+    assertEquals("Distance is 1.0E18", m.withNumberExponent(intVal));
+    assertEquals("Distance is 100.0E6", m.withNumberExponent(1e8f));
+  }
+
   public void testShapesFamily() {
     Shapes shapes = GWT.create(Shapes.class);
     // test overload
diff --git a/user/test/com/google/gwt/i18n/client/NumberFormat_en_Test.java b/user/test/com/google/gwt/i18n/client/NumberFormat_en_Test.java
index b729c16..d3b7f30 100644
--- a/user/test/com/google/gwt/i18n/client/NumberFormat_en_Test.java
+++ b/user/test/com/google/gwt/i18n/client/NumberFormat_en_Test.java
@@ -13,13 +13,15 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-
 package com.google.gwt.i18n.client;
 
 import com.google.gwt.junit.client.GWTTestCase;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
 /**
- * GWT JUnit tests must extend GWTTestCase.
+ * Test {@link NumberFormat} in the {@code en} locale.
  */
 public class NumberFormat_en_Test extends GWTTestCase {
 
@@ -52,16 +54,39 @@
     assertEquals("R$123,456.79", str);
   }
 
-  /**
-   * Add as many tests as you like.
-   */
   public void testBasicFormat() {
     String str = NumberFormat.getFormat("0.0000").format(123.45789179565757f);
     assertEquals("123.4579", str);
-    
+
     // tests for overflow of mantissa bits during formatting
-    str = NumberFormat.getFormat("#,##0.000").format(112589990684262.5);
-    assertEquals("112,589,990,684,262.500", str);
+    // Low bits are not dependable across browsers, so use .41 instead of
+    // .5 and only one decimal digits.
+    str = NumberFormat.getFormat("#,##0.0").format(112589990684262.41);
+    assertEquals("112,589,990,684,262.4", str);
+  }
+
+  public void testBigDecimal() {
+    BigDecimal decVal = new BigDecimal("1000000000000000000000000");
+    String str = NumberFormat.getFormat("0.000").format(decVal);
+    assertEquals("1000000000000000000000000.000", str);
+
+    decVal = decVal.add(new BigDecimal(".1"));
+    str = NumberFormat.getFormat("#,##0.000").format(decVal);
+    assertEquals("1,000,000,000,000,000,000,000,000.100", str);
+
+    decVal = new BigDecimal(".1499999999999999999999");
+    str = NumberFormat.getFormat(".0").format(decVal);
+    assertEquals(".1", str);
+}
+
+  public void testBigInteger() {
+    BigInteger intVal = new BigInteger("1000000000000000000000000");
+    String str = NumberFormat.getFormat("#,##0").format(intVal);
+    assertEquals("1,000,000,000,000,000,000,000,000", str);
+
+    intVal = intVal.add(BigInteger.ONE);
+    str = NumberFormat.getFormat("#,##0").format(intVal);
+    assertEquals("1,000,000,000,000,000,000,000,001", str);
   }
 
   public void testCurrency() {
@@ -94,7 +119,7 @@
     assertEquals("BRL 1,234.56", str);
     str = formatter.format(-1234.56);
     assertEquals("(BRL 1,234.56)", str);
-    
+
     // Test using a deprecated currency.
     formatter = NumberFormat.getCurrencyFormat("ITL");
     str = formatter.format(1234.556);
@@ -238,18 +263,6 @@
     assertTrue(value == 12345.0);
   }
 
-  public void testGrouping() {
-    String str;
-
-    str = NumberFormat.getFormat("#,###").format(1234567890);
-    assertEquals("1,234,567,890", str);
-    str = NumberFormat.getFormat("#,####").format(1234567890);
-    assertEquals("12,3456,7890", str);
-
-    str = NumberFormat.getFormat("#").format(1234567890);
-    assertEquals("1234567890", str);
-  }
-
   public void testForceLatin() {
     assertFalse(NumberFormat.forcedLatinDigits());
     NumberFormat.setForcedLatinDigits(true);
@@ -263,10 +276,51 @@
     NumberFormat unforced = NumberFormat.getDecimalFormat();
     assertEquals("3.14", unforced.format(3.14));
   }
-  
+
+  public void testGrouping() {
+    String str;
+
+    str = NumberFormat.getFormat("#,###").format(1234567890);
+    assertEquals("1,234,567,890", str);
+    str = NumberFormat.getFormat("#,####").format(1234567890);
+    assertEquals("12,3456,7890", str);
+
+    str = NumberFormat.getFormat("#").format(1234567890);
+    assertEquals("1234567890", str);
+  }
+
+  // See external issue 3140
+  public void testLeadingZeros() {
+    String str;
+
+    str = NumberFormat.getFormat("0,000,000,000.#").format(123456789.489123);
+    assertEquals("0,123,456,789.5", str);
+
+    str = NumberFormat.getFormat("#,###.####").format(0.414014);
+    assertEquals("0.414", str); // why leading 0?
+
+    str = NumberFormat.getFormat("#.####").format(0.414014);
+    assertEquals("0.414", str); // why leading 0?
+
+    str = NumberFormat.getFormat("#.0###").format(0.414014);
+    assertEquals(".414", str);
+
+    str = NumberFormat.getFormat("0.0###").format(0.414014);
+    assertEquals("0.414", str);
+
+    str = NumberFormat.getFormat("0.####").format(0.414014);
+    assertEquals("0.414", str);
+
+    str = NumberFormat.getFormat("0.0000").format(0.414014);
+    assertEquals("0.4140", str);
+
+    str = NumberFormat.getFormat("#.0000").format(0.414014);
+    assertEquals(".4140", str);
+  }
+
   public void testNegative() {
     String str;
-    
+
     // verify default negative pattern
     str = NumberFormat.getFormat("#,##0.0").format(-0.15);
     assertEquals("-0.2", str);
@@ -274,7 +328,7 @@
     assertEquals("-15.3%", str);
     str = NumberFormat.getFormat("X #,##0.0%").format(-0.1534);
     assertEquals("-X 15.3%", str);
-    
+
     // verify we can specify percent/permille suffixes in both parts
     str = NumberFormat.getFormat("#,##0.0%;#,##0.0%-").format(-0.152);
     assertEquals("15.2%-", str);
@@ -288,7 +342,7 @@
 
   public void testParseNotANumber() {
     try {
-      double d = NumberFormat.getDecimalFormat().parse("blue");
+      NumberFormat.getDecimalFormat().parse("blue");
       fail("Expected a NumberFormatException");
     } catch (NumberFormatException e) {
       assertEquals("blue", e.getMessage());
@@ -323,6 +377,67 @@
     assertEquals("a'b123", str);
   }
 
+  public void testRounding() {
+    String str;
+
+    str = NumberFormat.getFormat("#0.##").format(0.555);
+    assertEquals("0.56", str);
+
+    str = NumberFormat.getFormat("#.##").format(30.555);
+    assertEquals("30.56", str);
+
+    str = NumberFormat.getFormat("#.00").format(0.997);
+    assertEquals("1.00", str);
+
+    str = NumberFormat.getFormat("#.00").format(-0.997);
+    assertEquals("-1.00", str);
+
+    str = NumberFormat.getFormat("#.00").format(27.997);
+    assertEquals("28.00", str);
+
+    str = NumberFormat.getFormat("#.00").format(-27.997);
+    assertEquals("-28.00", str);
+
+    str = NumberFormat.getFormat("#0.00000").format(1.23456789E-03);
+    assertEquals("0.00123", str);
+
+    str = NumberFormat.getFormat("#0.0000000").format(1.23456789E-03);
+    assertEquals("0.0012346", str);
+
+    str = NumberFormat.getFormat("#0.0000").format(1.2E-03);
+    assertEquals("0.0012", str);
+
+    str = NumberFormat.getFormat("#0.000").format(1.2E-03);
+    assertEquals("0.001", str);
+
+    str = NumberFormat.getFormat("#0.00").format(1.2E-03);
+    assertEquals("0.00", str);
+
+    str = NumberFormat.getFormat("#0.0").format(1.2E-03);
+    assertEquals("0.0", str);
+
+    str = NumberFormat.getFormat("#0.00").format(11.2E-03);
+    assertEquals("0.01", str);
+
+    str = NumberFormat.getFormat("#0.00").format(111.2E-03);
+    assertEquals("0.11", str);
+
+    str = NumberFormat.getFormat("#0.00").format(1111.2E-03);
+    assertEquals("1.11", str);
+
+    str = NumberFormat.getFormat("#0.00000").format(1.23456789E-05);
+    assertEquals("0.00001", str);
+
+    str = NumberFormat.getFormat("#0.0000000").format(1.23456789E-05);
+    assertEquals("0.0000123", str);
+
+    str = NumberFormat.getFormat("#0.0000000").format(1.23756789E-05);
+    assertEquals("0.0000124", str);
+
+    str = NumberFormat.getFormat("#,##,###,##0.00000000000").format(111.18);
+    assertEquals("111.18000000000", str);
+  }
+
   public void testStandardFormat() {
     String str;
 
@@ -336,6 +451,19 @@
     assertEquals("1E3", str);
   }
 
+  public void testToScaledString() {
+    StringBuilder buf = new StringBuilder();
+    int scale = NumberFormat.toScaledString(buf, .1);
+    String str = buf.toString();
+    assertStartsWith("100", str.substring(str.length() + scale));
+    assertAllZeros(str, str.length() + scale);
+    buf = new StringBuilder();
+    scale = NumberFormat.toScaledString(buf, 12345e38);
+    str = buf.toString();
+    assertStartsWith("12345", str);
+    assertEquals(43, scale + str.length());
+  }
+
   public void testZeros() {
     String str;
 
@@ -357,62 +485,17 @@
     str = NumberFormat.getFormat("#").format(0);
     assertEquals("0", str);
   }
-  
-  public void testRounding() {
-    String str;
-    
-    str = NumberFormat.getFormat("#0.##").format(0.555);
-    assertEquals("0.56", str);
-    
-    str = NumberFormat.getFormat("#.##").format(30.555);
-    assertEquals("30.56", str);
-    
-    str = NumberFormat.getFormat("#.00").format(0.997);
-    assertEquals("1.00", str);
-    
-    str = NumberFormat.getFormat("#.00").format(-0.997);
-    assertEquals("-1.00", str);
-    
-    str = NumberFormat.getFormat("#.00").format(27.997);
-    assertEquals("28.00", str);
-    
-    str = NumberFormat.getFormat("#.00").format(-27.997);
-    assertEquals("-28.00", str);
-    
-    str = NumberFormat.getFormat("#0.00000").format(1.23456789E-03);
-    assertEquals("0.00123", str);
-    
-    str = NumberFormat.getFormat("#0.0000000").format(1.23456789E-03);
-    assertEquals("0.0012346", str);
-    
-    str = NumberFormat.getFormat("#0.0000").format(1.2E-03);
-    assertEquals("0.0012", str);
-    
-    str = NumberFormat.getFormat("#0.000").format(1.2E-03);
-    assertEquals("0.001", str);
-    
-    str = NumberFormat.getFormat("#0.00").format(1.2E-03);
-    assertEquals("0.00", str);
-    
-    str = NumberFormat.getFormat("#0.0").format(1.2E-03);
-    assertEquals("0.0", str);
-    
-    str = NumberFormat.getFormat("#0.00").format(11.2E-03);
-    assertEquals("0.01", str);
-    
-    str = NumberFormat.getFormat("#0.00").format(111.2E-03);
-    assertEquals("0.11", str);
-    
-    str = NumberFormat.getFormat("#0.00").format(1111.2E-03);
-    assertEquals("1.11", str);
-    
-    str = NumberFormat.getFormat("#0.00000").format(1.23456789E-05);
-    assertEquals("0.00001", str);
-    
-    str = NumberFormat.getFormat("#0.0000000").format(1.23456789E-05);
-    assertEquals("0.0000123", str);
-    
-    str = NumberFormat.getFormat("#0.0000000").format(1.23756789E-05);
-    assertEquals("0.0000124", str);
+
+  private void assertAllZeros(String str, int prefixLen) {
+    if (prefixLen > str.length()) {
+      prefixLen = str.length();
+    }
+    for (int i = 0; i < prefixLen; ++i) {
+      assertEquals('0', str.charAt(i));
+    }
+  }
+
+  private void assertStartsWith(String prefix, String str) {
+    assertTrue(str + " does not start with " + prefix, str.startsWith(prefix));
   }
 }
diff --git a/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages.java b/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages.java
index 55210ce..0892190 100644
--- a/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages.java
+++ b/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages.java
@@ -88,4 +88,10 @@
   @PluralText({"one", "A {0}"})
   String twoParamPlural(String name, @PluralCount
   int count);
+  
+  @DefaultMessage("Total is {0,number,currency}")
+  String withNumberCurrency(Number value);
+  
+  @DefaultMessage("Distance is {0,number,##0.0##E0}")
+  String withNumberExponent(Number value);
 }
diff --git a/user/test/com/google/gwt/user/client/rpc/ValueTypesTest.java b/user/test/com/google/gwt/user/client/rpc/ValueTypesTest.java
index aad328b..d650250 100644
--- a/user/test/com/google/gwt/user/client/rpc/ValueTypesTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/ValueTypesTest.java
@@ -17,25 +17,60 @@
 
 import com.google.gwt.core.client.GWT;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
 /**
- * TODO: document me.
+ * Test transfer of value types over RPC.
  */
 public class ValueTypesTest extends RpcTestBase {
 
   private ValueTypesTestServiceAsync primitiveTypeTestService;
 
+  public void testBigDecimal_base() {
+    assertEcho(new BigDecimal("42"));
+  }
+
+  public void testBigDecimal_exponential() {
+    assertEcho(new BigDecimal("0.00000000000000000001"));
+  }
+
+  public void testBigDecimal_negative() {
+    assertEcho(new BigDecimal("-42"));
+  }
+
+  public void testBigDecimal_zero() {
+    assertEcho(new BigDecimal("0.0"));
+  }
+
+  public void testBigInteger_base() {
+    assertEcho(new BigInteger("42"));
+  }
+
+  public void testBigInteger_exponential() {
+    assertEcho(new BigInteger("100000000000000000000"));
+  }
+
+  public void testBigInteger_negative() {
+    assertEcho(new BigInteger("-42"));
+  }
+
+  public void testBigInteger_zero() {
+    assertEcho(new BigInteger("0"));
+  }
+
   public void testBoolean_FALSE() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo_FALSE(false, new AsyncCallback() {
+    service.echo_FALSE(false, new AsyncCallback<Boolean>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Boolean result) {
         assertNotNull("Was null", result);
-        assertFalse("Should have been false", ((Boolean) result).booleanValue());
+        assertFalse("Should have been false", result.booleanValue());
         finishTest();
       }
     });
@@ -44,15 +79,15 @@
   public void testBoolean_TRUE() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo_TRUE(true, new AsyncCallback() {
+    service.echo_TRUE(true, new AsyncCallback<Boolean>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Boolean result) {
         assertNotNull(result);
-        assertTrue(((Boolean) result).booleanValue());
+        assertTrue(result.booleanValue());
         finishTest();
       }
     });
@@ -61,15 +96,15 @@
   public void testByte() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo((byte) (Byte.MAX_VALUE / (byte) 2), new AsyncCallback() {
+    service.echo((byte) (Byte.MAX_VALUE / (byte) 2), new AsyncCallback<Byte>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Byte result) {
         assertNotNull(result);
-        assertEquals(Byte.MAX_VALUE / 2, ((Byte) result).byteValue());
+        assertEquals(Byte.MAX_VALUE / 2, result.byteValue());
         finishTest();
       }
     });
@@ -78,15 +113,15 @@
   public void testByte_MAX_VALUE() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo_MAX_VALUE(Byte.MAX_VALUE, new AsyncCallback() {
+    service.echo_MAX_VALUE(Byte.MAX_VALUE, new AsyncCallback<Byte>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Byte result) {
         assertNotNull(result);
-        assertEquals(Byte.MAX_VALUE, ((Byte) result).byteValue());
+        assertEquals(Byte.MAX_VALUE, result.byteValue());
         finishTest();
       }
     });
@@ -95,15 +130,15 @@
   public void testByte_MIN_VALUE() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo_MIN_VALUE(Byte.MIN_VALUE, new AsyncCallback() {
+    service.echo_MIN_VALUE(Byte.MIN_VALUE, new AsyncCallback<Byte>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Byte result) {
         assertNotNull(result);
-        assertEquals(Byte.MIN_VALUE, ((Byte) result).byteValue());
+        assertEquals(Byte.MIN_VALUE, result.byteValue());
         finishTest();
       }
     });
@@ -112,16 +147,16 @@
   public void testChar() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo((char) (Character.MAX_VALUE / (char) 2), new AsyncCallback() {
+    final char value = (char) (Character.MAX_VALUE / (char) 2);
+    service.echo(value, new AsyncCallback<Character>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Character result) {
         assertNotNull(result);
-        assertEquals((char) (Character.MAX_VALUE / (char) 2),
-            ((Character) result).charValue());
+        assertEquals(value, result.charValue());
         finishTest();
       }
     });
@@ -130,15 +165,15 @@
   public void testChar_MAX_VALUE() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo_MAX_VALUE(Character.MAX_VALUE, new AsyncCallback() {
+    service.echo_MAX_VALUE(Character.MAX_VALUE, new AsyncCallback<Character>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Character result) {
         assertNotNull(result);
-        assertEquals(Character.MAX_VALUE, ((Character) result).charValue());
+        assertEquals(Character.MAX_VALUE, result.charValue());
         finishTest();
       }
     });
@@ -147,15 +182,15 @@
   public void testChar_MIN_VALUE() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo_MIN_VALUE(Character.MIN_VALUE, new AsyncCallback() {
+    service.echo_MIN_VALUE(Character.MIN_VALUE, new AsyncCallback<Character>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Character result) {
         assertNotNull(result);
-        assertEquals(Character.MIN_VALUE, ((Character) result).charValue());
+        assertEquals(Character.MIN_VALUE, result.charValue());
         finishTest();
       }
     });
@@ -164,15 +199,15 @@
   public void testDouble() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo(Double.MAX_VALUE / 2, new AsyncCallback() {
+    service.echo(Double.MAX_VALUE / 2, new AsyncCallback<Double>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Double result) {
         assertNotNull(result);
-        assertEquals(Double.MAX_VALUE / 2, ((Double) result).doubleValue(), 0.0);
+        assertEquals(Double.MAX_VALUE / 2, result.doubleValue(), 0.0);
         finishTest();
       }
     });
@@ -181,15 +216,15 @@
   public void testDouble_MAX_VALUE() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo_MAX_VALUE(Double.MAX_VALUE, new AsyncCallback() {
+    service.echo_MAX_VALUE(Double.MAX_VALUE, new AsyncCallback<Double>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Double result) {
         assertNotNull(result);
-        assertEquals(Double.MAX_VALUE, ((Double) result).doubleValue(), 0.0);
+        assertEquals(Double.MAX_VALUE, result.doubleValue(), 0.0);
         finishTest();
       }
     });
@@ -198,15 +233,15 @@
   public void testDouble_MIN_VALUE() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo_MIN_VALUE(Double.MIN_VALUE, new AsyncCallback() {
+    service.echo_MIN_VALUE(Double.MIN_VALUE, new AsyncCallback<Double>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Double result) {
         assertNotNull(result);
-        assertEquals(Double.MIN_VALUE, ((Double) result).doubleValue(), 0.0);
+        assertEquals(Double.MIN_VALUE, result.doubleValue(), 0.0);
         finishTest();
       }
     });
@@ -218,15 +253,15 @@
   public void testDouble_NaN() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo(Double.NaN, new AsyncCallback() {
+    service.echo(Double.NaN, new AsyncCallback<Double>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Double result) {
         assertNotNull(result);
-        assertTrue(Double.isNaN(((Double) result).doubleValue()));
+        assertTrue(Double.isNaN(result.doubleValue()));
         finishTest();
       }
     });
@@ -238,15 +273,15 @@
   public void testDouble_NegInfinity() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo(Double.NEGATIVE_INFINITY, new AsyncCallback() {
+    service.echo(Double.NEGATIVE_INFINITY, new AsyncCallback<Double>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Double result) {
         assertNotNull(result);
-        double doubleValue = ((Double) result).doubleValue();
+        double doubleValue = result.doubleValue();
         assertTrue(Double.isInfinite(doubleValue) && doubleValue < 0);
         finishTest();
       }
@@ -259,15 +294,15 @@
   public void testDouble_PosInfinity() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo(Double.POSITIVE_INFINITY, new AsyncCallback() {
+    service.echo(Double.POSITIVE_INFINITY, new AsyncCallback<Double>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Double result) {
         assertNotNull(result);
-        double doubleValue = ((Double) result).doubleValue();
+        double doubleValue = result.doubleValue();
         assertTrue(Double.isInfinite(doubleValue) && doubleValue > 0);
         finishTest();
       }
@@ -277,15 +312,15 @@
   public void testFloat() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo(Float.MAX_VALUE / 2, new AsyncCallback() {
+    service.echo(Float.MAX_VALUE / 2, new AsyncCallback<Float>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Float result) {
         assertNotNull(result);
-        assertEquals(Float.MAX_VALUE / 2, ((Float) result).floatValue(), 0.0);
+        assertEquals(Float.MAX_VALUE / 2, result.floatValue(), 0.0);
         finishTest();
       }
     });
@@ -294,15 +329,15 @@
   public void testFloat_MAX_VALUE() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo_MAX_VALUE(Float.MAX_VALUE, new AsyncCallback() {
+    service.echo_MAX_VALUE(Float.MAX_VALUE, new AsyncCallback<Float>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Float result) {
         assertNotNull(result);
-        assertEquals(Float.MAX_VALUE, ((Float) result).floatValue(), 0.0);
+        assertEquals(Float.MAX_VALUE, result.floatValue(), 0.0);
         finishTest();
       }
     });
@@ -311,15 +346,15 @@
   public void testFloat_MIN_VALUE() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo_MIN_VALUE(Float.MIN_VALUE, new AsyncCallback() {
+    service.echo_MIN_VALUE(Float.MIN_VALUE, new AsyncCallback<Float>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Float result) {
         assertNotNull(result);
-        assertEquals(Float.MIN_VALUE, ((Float) result).floatValue(), 0.0);
+        assertEquals(Float.MIN_VALUE, result.floatValue(), 0.0);
         finishTest();
       }
     });
@@ -331,15 +366,15 @@
   public void testFloat_NaN() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo(Float.NaN, new AsyncCallback() {
+    service.echo(Float.NaN, new AsyncCallback<Float>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Float result) {
         assertNotNull(result);
-        assertTrue(Float.isNaN(((Float) result).floatValue()));
+        assertTrue(Float.isNaN(result.floatValue()));
         finishTest();
       }
     });
@@ -351,15 +386,15 @@
   public void testFloat_NegInfinity() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo(Float.NEGATIVE_INFINITY, new AsyncCallback() {
+    service.echo(Float.NEGATIVE_INFINITY, new AsyncCallback<Float>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Float result) {
         assertNotNull(result);
-        float floatValue = ((Float) result).floatValue();
+        float floatValue = result.floatValue();
         assertTrue(Float.isInfinite(floatValue) && floatValue < 0);
         finishTest();
       }
@@ -372,15 +407,15 @@
   public void testFloat_PosInfinity() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo(Float.POSITIVE_INFINITY, new AsyncCallback() {
+    service.echo(Float.POSITIVE_INFINITY, new AsyncCallback<Float>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Float result) {
         assertNotNull(result);
-        float floatValue = ((Float) result).floatValue();
+        float floatValue = result.floatValue();
         assertTrue(Float.isInfinite(floatValue) && floatValue > 0);
         finishTest();
       }
@@ -390,15 +425,15 @@
   public void testInteger() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo(Integer.MAX_VALUE / 2, new AsyncCallback() {
+    service.echo(Integer.MAX_VALUE / 2, new AsyncCallback<Integer>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Integer result) {
         assertNotNull(result);
-        assertEquals(Integer.MAX_VALUE / 2, ((Integer) result).intValue());
+        assertEquals(Integer.MAX_VALUE / 2, result.intValue());
         finishTest();
       }
     });
@@ -407,15 +442,15 @@
   public void testInteger_MAX_VALUE() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo_MAX_VALUE(Integer.MAX_VALUE, new AsyncCallback() {
+    service.echo_MAX_VALUE(Integer.MAX_VALUE, new AsyncCallback<Integer>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Integer result) {
         assertNotNull(result);
-        assertEquals(Integer.MAX_VALUE, ((Integer) result).intValue());
+        assertEquals(Integer.MAX_VALUE, result.intValue());
         finishTest();
       }
     });
@@ -424,15 +459,15 @@
   public void testInteger_MIN_VALUE() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo_MIN_VALUE(Integer.MIN_VALUE, new AsyncCallback() {
+    service.echo_MIN_VALUE(Integer.MIN_VALUE, new AsyncCallback<Integer>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Integer result) {
         assertNotNull(result);
-        assertEquals(Integer.MIN_VALUE, ((Integer) result).intValue());
+        assertEquals(Integer.MIN_VALUE, result.intValue());
         finishTest();
       }
     });
@@ -441,16 +476,16 @@
   public void testLong() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo(Long.MAX_VALUE / 2, new AsyncCallback() {
+    service.echo(Long.MAX_VALUE / 2, new AsyncCallback<Long>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Long result) {
         assertNotNull(result);
         long expected = Long.MAX_VALUE / 2;
-        assertEquals(expected, ((Long) result).longValue());
+        assertEquals(expected, result.longValue());
         finishTest();
       }
     });
@@ -459,15 +494,15 @@
   public void testLong_MAX_VALUE() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo_MAX_VALUE(Long.MAX_VALUE, new AsyncCallback() {
+    service.echo_MAX_VALUE(Long.MAX_VALUE, new AsyncCallback<Long>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Long result) {
         assertNotNull(result);
-        assertEquals(Long.MAX_VALUE, ((Long) result).longValue());
+        assertEquals(Long.MAX_VALUE, result.longValue());
         finishTest();
       }
     });
@@ -476,15 +511,15 @@
   public void testLong_MIN_VALUE() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo_MIN_VALUE(Long.MIN_VALUE, new AsyncCallback() {
+    service.echo_MIN_VALUE(Long.MIN_VALUE, new AsyncCallback<Long>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Long result) {
         assertNotNull(result);
-        assertEquals(Long.MIN_VALUE, ((Long) result).longValue());
+        assertEquals(Long.MIN_VALUE, result.longValue());
         finishTest();
       }
     });
@@ -493,15 +528,16 @@
   public void testShort() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo((short) (Short.MAX_VALUE / (short) 2), new AsyncCallback() {
+    final short value = (short) (Short.MAX_VALUE / 2);
+    service.echo(value , new AsyncCallback<Short>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Short result) {
         assertNotNull(result);
-        assertEquals(Short.MAX_VALUE / 2, ((Short) result).shortValue());
+        assertEquals(value, result.shortValue());
         finishTest();
       }
     });
@@ -510,15 +546,15 @@
   public void testShort_MAX_VALUE() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo_MAX_VALUE(Short.MAX_VALUE, new AsyncCallback() {
+    service.echo_MAX_VALUE(Short.MAX_VALUE, new AsyncCallback<Short>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Short result) {
         assertNotNull(result);
-        assertEquals(Short.MAX_VALUE, ((Short) result).shortValue());
+        assertEquals(Short.MAX_VALUE, result.shortValue());
         finishTest();
       }
     });
@@ -527,15 +563,45 @@
   public void testShort_MIN_VALUE() {
     ValueTypesTestServiceAsync service = getServiceAsync();
     delayTestFinishForRpc();
-    service.echo_MIN_VALUE(Short.MIN_VALUE, new AsyncCallback() {
+    service.echo_MIN_VALUE(Short.MIN_VALUE, new AsyncCallback<Short>() {
 
       public void onFailure(Throwable caught) {
         TestSetValidator.rethrowException(caught);
       }
 
-      public void onSuccess(Object result) {
+      public void onSuccess(Short result) {
         assertNotNull(result);
-        assertEquals(Short.MIN_VALUE, ((Short) result).shortValue());
+        assertEquals(Short.MIN_VALUE, result.shortValue());
+        finishTest();
+      }
+    });
+  }
+
+  private void assertEcho(final BigDecimal value) {
+    ValueTypesTestServiceAsync service = getServiceAsync();
+    delayTestFinishForRpc();
+    service.echo(value, new AsyncCallback<BigDecimal>() {
+      public void onFailure(Throwable caught) {
+        TestSetValidator.rethrowException(caught);
+      }
+
+      public void onSuccess(BigDecimal result) {
+        assertEquals(value, result);
+        finishTest();
+      }
+    });
+  }
+
+  private void assertEcho(final BigInteger value) {
+    ValueTypesTestServiceAsync service = getServiceAsync();
+    delayTestFinishForRpc();
+    service.echo(value, new AsyncCallback<BigInteger>() {
+      public void onFailure(Throwable caught) {
+        TestSetValidator.rethrowException(caught);
+      }
+
+      public void onSuccess(BigInteger result) {
+        assertEquals(value, result);
         finishTest();
       }
     });
diff --git a/user/test/com/google/gwt/user/client/rpc/ValueTypesTestService.java b/user/test/com/google/gwt/user/client/rpc/ValueTypesTestService.java
index 85868f1..18f3537 100644
--- a/user/test/com/google/gwt/user/client/rpc/ValueTypesTestService.java
+++ b/user/test/com/google/gwt/user/client/rpc/ValueTypesTestService.java
@@ -15,8 +15,11 @@
  */
 package com.google.gwt.user.client.rpc;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
 /**
- * TODO: document me.
+ * Test sending value types via RPC.
  */
 public interface ValueTypesTestService extends RemoteService {
   byte echo(byte value);
@@ -33,6 +36,10 @@
 
   short echo(short value);
 
+  BigDecimal echo(BigDecimal value);
+
+  BigInteger echo(BigInteger value);
+
   boolean echo_FALSE(boolean value);
 
   byte echo_MAX_VALUE(byte value);
diff --git a/user/test/com/google/gwt/user/client/rpc/ValueTypesTestServiceAsync.java b/user/test/com/google/gwt/user/client/rpc/ValueTypesTestServiceAsync.java
index 28d2fb2..74eaa72 100644
--- a/user/test/com/google/gwt/user/client/rpc/ValueTypesTestServiceAsync.java
+++ b/user/test/com/google/gwt/user/client/rpc/ValueTypesTestServiceAsync.java
@@ -15,53 +15,61 @@
  */
 package com.google.gwt.user.client.rpc;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
 /**
- * TODO: document me.
+ * Async version of {@link ValueTypesTestService}.
  */
 public interface ValueTypesTestServiceAsync {
-  void echo(byte value, AsyncCallback callback);
 
-  void echo(char value, AsyncCallback callback);
+  void echo(byte value, AsyncCallback<Byte> callback);
 
-  void echo(double value, AsyncCallback callback);
+  void echo(char value, AsyncCallback<Character> callback);
 
-  void echo(float value, AsyncCallback callback);
+  void echo(double value, AsyncCallback<Double> callback);
 
-  void echo(int value, AsyncCallback callback);
+  void echo(float value, AsyncCallback<Float> callback);
 
-  void echo(long value, AsyncCallback callback);
+  void echo(int value, AsyncCallback<Integer> callback);
 
-  void echo(short value, AsyncCallback callback);
+  void echo(long value, AsyncCallback<Long> callback);
 
-  void echo_FALSE(boolean value, AsyncCallback callback);
+  void echo(short value, AsyncCallback<Short> callback);
 
-  void echo_MAX_VALUE(byte value, AsyncCallback callback);
+  void echo(BigDecimal value, AsyncCallback<BigDecimal> callback);
 
-  void echo_MAX_VALUE(char value, AsyncCallback callback);
+  void echo(BigInteger value, AsyncCallback<BigInteger> callback);
 
-  void echo_MAX_VALUE(double value, AsyncCallback callback);
+  void echo_FALSE(boolean value, AsyncCallback<Boolean> callback);
 
-  void echo_MAX_VALUE(float value, AsyncCallback callback);
+  void echo_MAX_VALUE(byte value, AsyncCallback<Byte> callback);
 
-  void echo_MAX_VALUE(int value, AsyncCallback callback);
+  void echo_MAX_VALUE(char value, AsyncCallback<Character> callback);
 
-  void echo_MAX_VALUE(long value, AsyncCallback callback);
+  void echo_MAX_VALUE(double value, AsyncCallback<Double> callback);
 
-  void echo_MAX_VALUE(short value, AsyncCallback callback);
+  void echo_MAX_VALUE(float value, AsyncCallback<Float> callback);
 
-  void echo_MIN_VALUE(byte value, AsyncCallback callback);
+  void echo_MAX_VALUE(int value, AsyncCallback<Integer> callback);
 
-  void echo_MIN_VALUE(char value, AsyncCallback callback);
+  void echo_MAX_VALUE(long value, AsyncCallback<Long> callback);
 
-  void echo_MIN_VALUE(double value, AsyncCallback callback);
+  void echo_MAX_VALUE(short value, AsyncCallback<Short> callback);
 
-  void echo_MIN_VALUE(float value, AsyncCallback callback);
+  void echo_MIN_VALUE(byte value, AsyncCallback<Byte> callback);
 
-  void echo_MIN_VALUE(int value, AsyncCallback callback);
+  void echo_MIN_VALUE(char value, AsyncCallback<Character> callback);
 
-  void echo_MIN_VALUE(long value, AsyncCallback callback);
+  void echo_MIN_VALUE(double value, AsyncCallback<Double> callback);
 
-  void echo_MIN_VALUE(short value, AsyncCallback callback);
+  void echo_MIN_VALUE(float value, AsyncCallback<Float> callback);
 
-  void echo_TRUE(boolean value, AsyncCallback callback);
+  void echo_MIN_VALUE(int value, AsyncCallback<Integer> callback);
+
+  void echo_MIN_VALUE(long value, AsyncCallback<Long> callback);
+
+  void echo_MIN_VALUE(short value, AsyncCallback<Short> callback);
+
+  void echo_TRUE(boolean value, AsyncCallback<Boolean> callback);
 }
diff --git a/user/test/com/google/gwt/user/server/rpc/ValueTypesTestServiceImpl.java b/user/test/com/google/gwt/user/server/rpc/ValueTypesTestServiceImpl.java
index b52f27e..4ce0e7f 100644
--- a/user/test/com/google/gwt/user/server/rpc/ValueTypesTestServiceImpl.java
+++ b/user/test/com/google/gwt/user/server/rpc/ValueTypesTestServiceImpl.java
@@ -17,6 +17,9 @@
 
 import com.google.gwt.user.client.rpc.ValueTypesTestService;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
 /**
  * Server-side code for ValueTypesTest. Mostly just echoes back the values
  * received from the client, but some methods verify the value received to make
@@ -54,6 +57,14 @@
     return value;
   }
 
+  public BigDecimal echo(BigDecimal value) {
+    return value;
+  }
+
+  public BigInteger echo(BigInteger value) {
+    return value;
+  }
+
   public boolean echo_FALSE(boolean value) {
     if (value != false) {
       throw new RuntimeException();