changeset 4922:71200c517524

4504839: Java libraries should provide support for unsigned integer arithmetic 4215269: Some Integer.toHexString(int) results cannot be decoded back to an int 6322074: Converting integers to string as if unsigned Reviewed-by: mduigou, emcmanus, flar
author darcy
date Fri, 20 Jan 2012 17:56:31 -0800
parents 313da5d059bf
children d383b5d128e3
files src/share/classes/java/lang/Byte.java src/share/classes/java/lang/Integer.java src/share/classes/java/lang/Long.java src/share/classes/java/lang/Short.java test/java/lang/Integer/Unsigned.java test/java/lang/Long/Unsigned.java
diffstat 6 files changed, 1474 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/lang/Byte.java	Thu Jan 19 12:01:57 2012 -0800
+++ b/src/share/classes/java/lang/Byte.java	Fri Jan 20 17:56:31 2012 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -446,6 +446,47 @@
     }
 
     /**
+     * Converts the argument to an {@code int} by an unsigned
+     * conversion.  In an unsigned conversion to an {@code int}, the
+     * high-order 24 bits of the {@code int} are zero and the
+     * low-order 8 bits are equal to the bits of the {@code byte} argument.
+     *
+     * Consequently, zero and positive {@code byte} values are mapped
+     * to a numerically equal {@code int} value and negative {@code
+     * byte} values are mapped to an {@code int} value equal to the
+     * input plus 2<sup>8</sup>.
+     *
+     * @param  x the value to convert to an unsigned {@code int}
+     * @return the argument converted to {@code int} by an unsigned
+     *         conversion
+     * @since 1.8
+     */
+    public static int toUnsignedInt(byte x) {
+        return ((int) x) & 0xff;
+    }
+
+    /**
+     * Converts the argument to a {@code long} by an unsigned
+     * conversion.  In an unsigned conversion to a {@code long}, the
+     * high-order 56 bits of the {@code long} are zero and the
+     * low-order 8 bits are equal to the bits of the {@code byte} argument.
+     *
+     * Consequently, zero and positive {@code byte} values are mapped
+     * to a numerically equal {@code long} value and negative {@code
+     * byte} values are mapped to a {@code long} value equal to the
+     * input plus 2<sup>8</sup>.
+     *
+     * @param  x the value to convert to an unsigned {@code long}
+     * @return the argument converted to {@code long} by an unsigned
+     *         conversion
+     * @since 1.8
+     */
+    public static long toUnsignedLong(byte x) {
+        return ((long) x) & 0xffL;
+    }
+
+
+    /**
      * The number of bits used to represent a {@code byte} value in two's
      * complement binary form.
      *
--- a/src/share/classes/java/lang/Integer.java	Thu Jan 19 12:01:57 2012 -0800
+++ b/src/share/classes/java/lang/Integer.java	Fri Jan 20 17:56:31 2012 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -128,7 +128,6 @@
      * @see     java.lang.Character#MIN_RADIX
      */
     public static String toString(int i, int radix) {
-
         if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
             radix = 10;
 
@@ -159,6 +158,36 @@
     }
 
     /**
+     * Returns a string representation of the first argument as an
+     * unsigned integer value in the radix specified by the second
+     * argument.
+     *
+     * <p>If the radix is smaller than {@code Character.MIN_RADIX}
+     * or larger than {@code Character.MAX_RADIX}, then the radix
+     * {@code 10} is used instead.
+     *
+     * <p>Note that since the first argument is treated as an unsigned
+     * value, no leading sign character is printed.
+     *
+     * <p>If the magnitude is zero, it is represented by a single zero
+     * character {@code '0'} (<code>'&#92;u0030'</code>); otherwise,
+     * the first character of the representation of the magnitude will
+     * not be the zero character.
+     *
+     * <p>The behavior of radixes and the characters used as digits
+     * are the same as {@link #toString(int, int) toString}.
+     *
+     * @param   i       an integer to be converted to an unsigned string.
+     * @param   radix   the radix to use in the string representation.
+     * @return  an unsigned string representation of the argument in the specified radix.
+     * @see     #toString(int, int)
+     * @since 1.8
+     */
+    public static String toUnsignedString(int i, int radix) {
+        return Long.toString(toUnsignedLong(i), radix);
+    }
+
+    /**
      * Returns a string representation of the integer argument as an
      * unsigned integer in base&nbsp;16.
      *
@@ -166,12 +195,18 @@
      * if the argument is negative; otherwise, it is equal to the
      * argument.  This value is converted to a string of ASCII digits
      * in hexadecimal (base&nbsp;16) with no extra leading
-     * {@code 0}s. If the unsigned magnitude is zero, it is
-     * represented by a single zero character {@code '0'}
-     * (<code>'&#92;u0030'</code>); otherwise, the first character of
-     * the representation of the unsigned magnitude will not be the
-     * zero character. The following characters are used as
-     * hexadecimal digits:
+     * {@code 0}s.
+     *
+     * <p>The value of the argument can be recovered from the returned
+     * string {@code s} by calling {@link
+     * Integer#parseUnsignedInt(String, int)
+     * Integer.parseUnsignedInt(s, 16)}.
+     *
+     * <p>If the unsigned magnitude is zero, it is represented by a
+     * single zero character {@code '0'} (<code>'&#92;u0030'</code>);
+     * otherwise, the first character of the representation of the
+     * unsigned magnitude will not be the zero character. The
+     * following characters are used as hexadecimal digits:
      *
      * <blockquote>
      *  {@code 0123456789abcdef}
@@ -190,10 +225,12 @@
      * @param   i   an integer to be converted to a string.
      * @return  the string representation of the unsigned integer value
      *          represented by the argument in hexadecimal (base&nbsp;16).
+     * @see #parseUnsignedInt(String, int)
+     * @see #toUnsignedString(int, int)
      * @since   JDK1.0.2
      */
     public static String toHexString(int i) {
-        return toUnsignedString(i, 4);
+        return toUnsignedString0(i, 4);
     }
 
     /**
@@ -205,12 +242,16 @@
      * argument.  This value is converted to a string of ASCII digits
      * in octal (base&nbsp;8) with no extra leading {@code 0}s.
      *
+     * <p>The value of the argument can be recovered from the returned
+     * string {@code s} by calling {@link
+     * Integer#parseUnsignedInt(String, int)
+     * Integer.parseUnsignedInt(s, 8)}.
+     *
      * <p>If the unsigned magnitude is zero, it is represented by a
-     * single zero character {@code '0'}
-     * (<code>'&#92;u0030'</code>); otherwise, the first character of
-     * the representation of the unsigned magnitude will not be the
-     * zero character. The following characters are used as octal
-     * digits:
+     * single zero character {@code '0'} (<code>'&#92;u0030'</code>);
+     * otherwise, the first character of the representation of the
+     * unsigned magnitude will not be the zero character. The
+     * following characters are used as octal digits:
      *
      * <blockquote>
      * {@code 01234567}
@@ -222,10 +263,12 @@
      * @param   i   an integer to be converted to a string.
      * @return  the string representation of the unsigned integer value
      *          represented by the argument in octal (base&nbsp;8).
+     * @see #parseUnsignedInt(String, int)
+     * @see #toUnsignedString(int, int)
      * @since   JDK1.0.2
      */
     public static String toOctalString(int i) {
-        return toUnsignedString(i, 3);
+        return toUnsignedString0(i, 3);
     }
 
     /**
@@ -236,27 +279,34 @@
      * if the argument is negative; otherwise it is equal to the
      * argument.  This value is converted to a string of ASCII digits
      * in binary (base&nbsp;2) with no extra leading {@code 0}s.
-     * If the unsigned magnitude is zero, it is represented by a
-     * single zero character {@code '0'}
-     * (<code>'&#92;u0030'</code>); otherwise, the first character of
-     * the representation of the unsigned magnitude will not be the
-     * zero character. The characters {@code '0'}
-     * (<code>'&#92;u0030'</code>) and {@code '1'}
-     * (<code>'&#92;u0031'</code>) are used as binary digits.
+     *
+     * <p>The value of the argument can be recovered from the returned
+     * string {@code s} by calling {@link
+     * Integer#parseUnsignedInt(String, int)
+     * Integer.parseUnsignedInt(s, 2)}.
+     *
+     * <p>If the unsigned magnitude is zero, it is represented by a
+     * single zero character {@code '0'} (<code>'&#92;u0030'</code>);
+     * otherwise, the first character of the representation of the
+     * unsigned magnitude will not be the zero character. The
+     * characters {@code '0'} (<code>'&#92;u0030'</code>) and {@code
+     * '1'} (<code>'&#92;u0031'</code>) are used as binary digits.
      *
      * @param   i   an integer to be converted to a string.
      * @return  the string representation of the unsigned integer value
      *          represented by the argument in binary (base&nbsp;2).
+     * @see #parseUnsignedInt(String, int)
+     * @see #toUnsignedString(int, int)
      * @since   JDK1.0.2
      */
     public static String toBinaryString(int i) {
-        return toUnsignedString(i, 1);
+        return toUnsignedString0(i, 1);
     }
 
     /**
      * Convert the integer to an unsigned number.
      */
-    private static String toUnsignedString(int i, int shift) {
+    private static String toUnsignedString0(int i, int shift) {
         char[] buf = new char[32];
         int charPos = 32;
         int radix = 1 << shift;
@@ -335,6 +385,24 @@
     }
 
     /**
+     * Returns a string representation of the argument as an unsigned
+     * decimal value.
+     *
+     * The argument is converted to unsigned decimal representation
+     * and returned as a string exactly as if the argument and radix
+     * 10 were given as arguments to the {@link #toUnsignedString(int,
+     * int)} method.
+     *
+     * @param   i  an integer to be converted to an unsigned string.
+     * @return  an unsigned string representation of the argument.
+     * @see     #toUnsignedString(int, int)
+     * @since 1.8
+     */
+    public static String toUnsignedString(int i) {
+        return Long.toString(toUnsignedLong(i));
+    }
+
+    /**
      * Places characters representing the integer i into the
      * character array buf. The characters are placed into
      * the buffer backwards starting with the least significant
@@ -529,6 +597,102 @@
     }
 
     /**
+     * Parses the string argument as an unsigned integer in the radix
+     * specified by the second argument.  An unsigned integer maps the
+     * values usually associated with negative numbers to positive
+     * numbers larger than {@code MAX_VALUE}.
+     *
+     * The characters in the string must all be digits of the
+     * specified radix (as determined by whether {@link
+     * java.lang.Character#digit(char, int)} returns a nonnegative
+     * value), except that the first character may be an ASCII plus
+     * sign {@code '+'} (<code>'&#92;u002B'</code>). The resulting
+     * integer value is returned.
+     *
+     * <p>An exception of type {@code NumberFormatException} is
+     * thrown if any of the following situations occurs:
+     * <ul>
+     * <li>The first argument is {@code null} or is a string of
+     * length zero.
+     *
+     * <li>The radix is either smaller than
+     * {@link java.lang.Character#MIN_RADIX} or
+     * larger than {@link java.lang.Character#MAX_RADIX}.
+     *
+     * <li>Any character of the string is not a digit of the specified
+     * radix, except that the first character may be a plus sign
+     * {@code '+'} (<code>'&#92;u002B'</code>) provided that the
+     * string is longer than length 1.
+     *
+     * <li>The value represented by the string is larger than the
+     * largest unsigned {@code int}, 2<sup>32</sup>-1.
+     *
+     * </ul>
+     *
+     *
+     * @param      s   the {@code String} containing the unsigned integer
+     *                  representation to be parsed
+     * @param      radix   the radix to be used while parsing {@code s}.
+     * @return     the integer represented by the string argument in the
+     *             specified radix.
+     * @throws     NumberFormatException if the {@code String}
+     *             does not contain a parsable {@code int}.
+     * @since 1.8
+     */
+    public static int parseUnsignedInt(String s, int radix)
+                throws NumberFormatException {
+        if (s == null)  {
+            throw new NumberFormatException("null");
+        }
+
+        int len = s.length();
+        if (len > 0) {
+            char firstChar = s.charAt(0);
+            if (firstChar == '-') {
+                throw new
+                    NumberFormatException(String.format("Illegal leading minus sign " +
+                                                       "on unsigned string %s.", s));
+            } else {
+                if (len <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits
+                    (radix == 10 && len <= 9) ) { // Integer.MAX_VALUE in base 10 is 10 digits
+                    return parseInt(s, radix);
+                } else {
+                    long ell = Long.parseLong(s, radix);
+                    if ((ell & 0xffff_ffff_0000_0000L) == 0) {
+                        return (int) ell;
+                    } else {
+                        throw new
+                            NumberFormatException(String.format("String value %s exceeds " +
+                                                                "range of unsigned int.", s));
+                    }
+                }
+            }
+        } else {
+            throw NumberFormatException.forInputString(s);
+        }
+    }
+
+    /**
+     * Parses the string argument as an unsigned decimal integer. The
+     * characters in the string must all be decimal digits, except
+     * that the first character may be an an ASCII plus sign {@code
+     * '+'} (<code>'&#92;u002B'</code>). The resulting integer value
+     * is returned, exactly as if the argument and the radix 10 were
+     * given as arguments to the {@link
+     * #parseUnsignedInt(java.lang.String, int)} method.
+     *
+     * @param s   a {@code String} containing the unsigned {@code int}
+     *            representation to be parsed
+     * @return    the unsigned integer value represented by the argument in decimal.
+     * @throws    NumberFormatException  if the string does not contain a
+     *            parsable unsigned integer.
+     * @since 1.8
+     */
+    public static int parseUnsignedInt(String s) throws NumberFormatException {
+        return parseUnsignedInt(s, 10);
+    }
+
+    /**
      * Returns an {@code Integer} object holding the value
      * extracted from the specified {@code String} when parsed
      * with the radix given by the second argument. The first argument
@@ -1030,6 +1194,83 @@
         return (x < y) ? -1 : ((x == y) ? 0 : 1);
     }
 
+    /**
+     * Compares two {@code int} values numerically treating the values
+     * as unsigned.
+     *
+     * @param  x the first {@code int} to compare
+     * @param  y the second {@code int} to compare
+     * @return the value {@code 0} if {@code x == y}; a value less
+     *         than {@code 0} if {@code x < y} as unsigned values; and
+     *         a value greater than {@code 0} if {@code x > y} as
+     *         unsigned values
+     * @since 1.8
+     */
+    public static int compareUnsigned(int x, int y) {
+        return compare(x + MIN_VALUE, y + MIN_VALUE);
+    }
+
+    /**
+     * Converts the argument to a {@code long} by an unsigned
+     * conversion.  In an unsigned conversion to a {@code long}, the
+     * high-order 32 bits of the {@code long} are zero and the
+     * low-order 32 bits are equal to the bits of the integer
+     * argument.
+     *
+     * Consequently, zero and positive {@code int} values are mapped
+     * to a numerically equal {@code long} value and negative {@code
+     * int} values are mapped to a {@code long} value equal to the
+     * input plus 2<sup>32</sup>.
+     *
+     * @param  x the value to convert to an unsigned {@code long}
+     * @return the argument converted to {@code long} by an unsigned
+     *         conversion
+     * @since 1.8
+     */
+    public static long toUnsignedLong(int x) {
+        return ((long) x) & 0xffffffffL;
+    }
+
+    /**
+     * Returns the unsigned quotient of dividing the first argument by
+     * the second where each argument and the result is interpreted as
+     * an unsigned value.
+     *
+     * <p>Note that in two's complement arithmetic, the three other
+     * basic arithmetic operations of add, subtract, and multiply are
+     * bit-wise identical if the two operands are regarded as both
+     * being signed or both being unsigned.  Therefore separate {@code
+     * addUnsigned}, etc. methods are not provided.
+     *
+     * @param dividend the value to be divided
+     * @param divisor the value doing the dividing
+     * @return the unsigned quotient of the first argument divided by
+     * the second argument
+     * @see #remainderUnsigned
+     * @since 1.8
+     */
+    public static int divideUnsigned(int dividend, int divisor) {
+        // In lieu of tricky code, for now just use long arithmetic.
+        return (int)(toUnsignedLong(dividend) / toUnsignedLong(divisor));
+    }
+
+    /**
+     * Returns the unsigned remainder from dividing the first argument
+     * by the second where each argument and the result is interpreted
+     * as an unsigned value.
+     *
+     * @param dividend the value to be divided
+     * @param divisor the value doing the dividing
+     * @return the unsigned remainder of the first argument divided by
+     * the second argument
+     * @see #divideUnsigned
+     * @since 1.8
+     */
+    public static int remainderUnsigned(int dividend, int divisor) {
+        // In lieu of tricky code, for now just use long arithmetic.
+        return (int)(toUnsignedLong(dividend) % toUnsignedLong(divisor));
+    }
+
 
     // Bit twiddling
 
--- a/src/share/classes/java/lang/Long.java	Thu Jan 19 12:01:57 2012 -0800
+++ b/src/share/classes/java/lang/Long.java	Fri Jan 20 17:56:31 2012 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
 
 package java.lang;
 
+import java.math.*;
+
 /**
  * The {@code Long} class wraps a value of the primitive type {@code
  * long} in an object. An object of type {@code Long} contains a
@@ -140,6 +142,88 @@
     }
 
     /**
+     * Returns a string representation of the first argument as an
+     * unsigned integer value in the radix specified by the second
+     * argument.
+     *
+     * <p>If the radix is smaller than {@code Character.MIN_RADIX}
+     * or larger than {@code Character.MAX_RADIX}, then the radix
+     * {@code 10} is used instead.
+     *
+     * <p>Note that since the first argument is treated as an unsigned
+     * value, no leading sign character is printed.
+     *
+     * <p>If the magnitude is zero, it is represented by a single zero
+     * character {@code '0'} (<code>'&#92;u0030'</code>); otherwise,
+     * the first character of the representation of the magnitude will
+     * not be the zero character.
+     *
+     * <p>The behavior of radixes and the characters used as digits
+     * are the same as {@link #toString(long, int) toString}.
+     *
+     * @param   i       an integer to be converted to an unsigned string.
+     * @param   radix   the radix to use in the string representation.
+     * @return  an unsigned string representation of the argument in the specified radix.
+     * @see     #toString(long, int)
+     * @since 1.8
+     */
+    public static String toUnsignedString(long i, int radix) {
+        if (i >= 0)
+            return toString(i, radix);
+        else {
+            switch (radix) {
+            case 2:
+                return toBinaryString(i);
+
+            case 4:
+                return toUnsignedString0(i, 2);
+
+            case 8:
+                return toOctalString(i);
+
+            case 10:
+                /*
+                 * We can get the effect of an unsigned division by 10
+                 * on a long value by first shifting right, yielding a
+                 * positive value, and then dividing by 5.  This
+                 * allows the last digit and preceding digits to be
+                 * isolated more quickly than by an initial conversion
+                 * to BigInteger.
+                 */
+                long quot = (i >>> 1) / 5;
+                long rem = i - quot * 10;
+                return toString(quot) + rem;
+
+            case 16:
+                return toHexString(i);
+
+            case 32:
+                return toUnsignedString0(i, 5);
+
+            default:
+                return toUnsignedBigInteger(i).toString(radix);
+            }
+        }
+    }
+
+    /**
+     * Return a BigInteger equal to the unsigned value of the
+     * argument.
+     */
+    private static BigInteger toUnsignedBigInteger(long i) {
+        if (i >= 0L)
+            return BigInteger.valueOf(i);
+        else {
+            int upper = (int) (i >>> 32);
+            int lower = (int) i;
+
+            // return (upper << 32) + lower
+            return (BigInteger.valueOf(Integer.toUnsignedLong(upper))).shiftLeft(32).
+                add(BigInteger.valueOf(Integer.toUnsignedLong(lower)));
+        }
+    }
+
+    /**
      * Returns a string representation of the {@code long}
      * argument as an unsigned integer in base&nbsp;16.
      *
@@ -147,12 +231,18 @@
      * 2<sup>64</sup> if the argument is negative; otherwise, it is
      * equal to the argument.  This value is converted to a string of
      * ASCII digits in hexadecimal (base&nbsp;16) with no extra
-     * leading {@code 0}s.  If the unsigned magnitude is zero, it
-     * is represented by a single zero character {@code '0'}
-     * (<code>'&#92;u0030'</code>); otherwise, the first character of
-     * the representation of the unsigned magnitude will not be the
-     * zero character. The following characters are used as
-     * hexadecimal digits:
+     * leading {@code 0}s.
+     *
+     * <p>The value of the argument can be recovered from the returned
+     * string {@code s} by calling {@link
+     * Long#parseUnsignedLong(String, int) Long.parseUnsignedLong(s,
+     * 16)}.
+     *
+     * <p>If the unsigned magnitude is zero, it is represented by a
+     * single zero character {@code '0'} (<code>'&#92;u0030'</code>);
+     * otherwise, the first character of the representation of the
+     * unsigned magnitude will not be the zero character. The
+     * following characters are used as hexadecimal digits:
      *
      * <blockquote>
      *  {@code 0123456789abcdef}
@@ -172,10 +262,12 @@
      * @return  the string representation of the unsigned {@code long}
      *          value represented by the argument in hexadecimal
      *          (base&nbsp;16).
+     * @see #parseUnsignedLong(String, int)
+     * @see #toUnsignedString(long, int)
      * @since   JDK 1.0.2
      */
     public static String toHexString(long i) {
-        return toUnsignedString(i, 4);
+        return toUnsignedString0(i, 4);
     }
 
     /**
@@ -188,12 +280,16 @@
      * ASCII digits in octal (base&nbsp;8) with no extra leading
      * {@code 0}s.
      *
+     * <p>The value of the argument can be recovered from the returned
+     * string {@code s} by calling {@link
+     * Long#parseUnsignedLong(String, int) Long.parseUnsignedLong(s,
+     * 8)}.
+     *
      * <p>If the unsigned magnitude is zero, it is represented by a
-     * single zero character {@code '0'}
-     * (<code>'&#92;u0030'</code>); otherwise, the first character of
-     * the representation of the unsigned magnitude will not be the
-     * zero character. The following characters are used as octal
-     * digits:
+     * single zero character {@code '0'} (<code>'&#92;u0030'</code>);
+     * otherwise, the first character of the representation of the
+     * unsigned magnitude will not be the zero character. The
+     * following characters are used as octal digits:
      *
      * <blockquote>
      *  {@code 01234567}
@@ -205,10 +301,12 @@
      * @param   i   a {@code long} to be converted to a string.
      * @return  the string representation of the unsigned {@code long}
      *          value represented by the argument in octal (base&nbsp;8).
+     * @see #parseUnsignedLong(String, int)
+     * @see #toUnsignedString(long, int)
      * @since   JDK 1.0.2
      */
     public static String toOctalString(long i) {
-        return toUnsignedString(i, 3);
+        return toUnsignedString0(i, 3);
     }
 
     /**
@@ -219,27 +317,35 @@
      * 2<sup>64</sup> if the argument is negative; otherwise, it is
      * equal to the argument.  This value is converted to a string of
      * ASCII digits in binary (base&nbsp;2) with no extra leading
-     * {@code 0}s.  If the unsigned magnitude is zero, it is
-     * represented by a single zero character {@code '0'}
-     * (<code>'&#92;u0030'</code>); otherwise, the first character of
-     * the representation of the unsigned magnitude will not be the
-     * zero character. The characters {@code '0'}
-     * (<code>'&#92;u0030'</code>) and {@code '1'}
-     * (<code>'&#92;u0031'</code>) are used as binary digits.
+     * {@code 0}s.
+     *
+     * <p>The value of the argument can be recovered from the returned
+     * string {@code s} by calling {@link
+     * Long#parseUnsignedLong(String, int) Long.parseUnsignedLong(s,
+     * 2)}.
+     *
+     * <p>If the unsigned magnitude is zero, it is represented by a
+     * single zero character {@code '0'} (<code>'&#92;u0030'</code>);
+     * otherwise, the first character of the representation of the
+     * unsigned magnitude will not be the zero character. The
+     * characters {@code '0'} (<code>'&#92;u0030'</code>) and {@code
+     * '1'} (<code>'&#92;u0031'</code>) are used as binary digits.
      *
      * @param   i   a {@code long} to be converted to a string.
      * @return  the string representation of the unsigned {@code long}
      *          value represented by the argument in binary (base&nbsp;2).
+     * @see #parseUnsignedLong(String, int)
+     * @see #toUnsignedString(long, int)
      * @since   JDK 1.0.2
      */
     public static String toBinaryString(long i) {
-        return toUnsignedString(i, 1);
+        return toUnsignedString0(i, 1);
     }
 
     /**
      * Convert the integer to an unsigned number.
      */
-    private static String toUnsignedString(long i, int shift) {
+    private static String toUnsignedString0(long i, int shift) {
         char[] buf = new char[64];
         int charPos = 64;
         int radix = 1 << shift;
@@ -271,6 +377,24 @@
     }
 
     /**
+     * Returns a string representation of the argument as an unsigned
+     * decimal value.
+     *
+     * The argument is converted to unsigned decimal representation
+     * and returned as a string exactly as if the argument and radix
+     * 10 were given as arguments to the {@link #toUnsignedString(long,
+     * int)} method.
+     *
+     * @param   i  an integer to be converted to an unsigned string.
+     * @return  an unsigned string representation of the argument.
+     * @see     #toUnsignedString(long, int)
+     * @since 1.8
+     */
+    public static String toUnsignedString(long i) {
+        return toUnsignedString(i, 10);
+    }
+
+    /**
      * Places characters representing the integer i into the
      * character array buf. The characters are placed into
      * the buffer backwards starting with the least significant
@@ -485,6 +609,121 @@
     }
 
     /**
+     * Parses the string argument as an unsigned {@code long} in the
+     * radix specified by the second argument.  An unsigned integer
+     * maps the values usually associated with negative numbers to
+     * positive numbers larger than {@code MAX_VALUE}.
+     *
+     * The characters in the string must all be digits of the
+     * specified radix (as determined by whether {@link
+     * java.lang.Character#digit(char, int)} returns a nonnegative
+     * value), except that the first character may be an ASCII plus
+     * sign {@code '+'} (<code>'&#92;u002B'</code>). The resulting
+     * integer value is returned.
+     *
+     * <p>An exception of type {@code NumberFormatException} is
+     * thrown if any of the following situations occurs:
+     * <ul>
+     * <li>The first argument is {@code null} or is a string of
+     * length zero.
+     *
+     * <li>The radix is either smaller than
+     * {@link java.lang.Character#MIN_RADIX} or
+     * larger than {@link java.lang.Character#MAX_RADIX}.
+     *
+     * <li>Any character of the string is not a digit of the specified
+     * radix, except that the first character may be a plus sign
+     * {@code '+'} (<code>'&#92;u002B'</code>) provided that the
+     * string is longer than length 1.
+     *
+     * <li>The value represented by the string is larger than the
+     * largest unsigned {@code long}, 2<sup>64</sup>-1.
+     *
+     * </ul>
+     *
+     *
+     * @param      s   the {@code String} containing the unsigned integer
+     *                  representation to be parsed
+     * @param      radix   the radix to be used while parsing {@code s}.
+     * @return     the unsigned {@code long} represented by the string
+     *             argument in the specified radix.
+     * @throws     NumberFormatException if the {@code String}
+     *             does not contain a parsable {@code long}.
+     * @since 1.8
+     */
+    public static long parseUnsignedLong(String s, int radix)
+                throws NumberFormatException {
+        if (s == null)  {
+            throw new NumberFormatException("null");
+        }
+
+        int len = s.length();
+        if (len > 0) {
+            char firstChar = s.charAt(0);
+            if (firstChar == '-') {
+                throw new
+                    NumberFormatException(String.format("Illegal leading minus sign " +
+                                                       "on unsigned string %s.", s));
+            } else {
+                if (len <= 12 || // Long.MAX_VALUE in Character.MAX_RADIX is 13 digits
+                    (radix == 10 && len <= 18) ) { // Long.MAX_VALUE in base 10 is 19 digits
+                    return parseLong(s, radix);
+                }
+
+                // No need for range checks on len due to testing above.
+                long first = parseLong(s.substring(0, len - 1), radix);
+                int second = Character.digit(s.charAt(len - 1), radix);
+                if (second < 0) {
+                    throw new NumberFormatException("Bad digit at end of " + s);
+                }
+                long result = first * radix + second;
+                if (compareUnsigned(result, first) < 0) {
+                    /*
+                     * The maximum unsigned value, (2^64)-1, takes at
+                     * most one more digit to represent than the
+                     * maximum signed value, (2^63)-1.  Therefore,
+                     * parsing (len - 1) digits will be appropriately
+                     * in-range of the signed parsing.  In other
+                     * words, if parsing (len -1) digits overflows
+                     * signed parsing, parsing len digits will
+                     * certainly overflow unsigned parsing.
+                     *
+                     * The compareUnsigned check above catches
+                     * situations where an unsigned overflow occurs
+                     * incorporating the contribution of the final
+                     * digit.
+                     */
+                    throw new NumberFormatException(String.format("String value %s exceeds " +
+                                                                  "range of unsigned long.", s));
+                }
+                return result;
+            }
+        } else {
+            throw NumberFormatException.forInputString(s);
+        }
+    }
+
+    /**
+     * Parses the string argument as an unsigned decimal {@code long}. The
+     * characters in the string must all be decimal digits, except
+     * that the first character may be an an ASCII plus sign {@code
+     * '+'} (<code>'&#92;u002B'</code>). The resulting integer value
+     * is returned, exactly as if the argument and the radix 10 were
+     * given as arguments to the {@link
+     * #parseUnsignedLong(java.lang.String, int)} method.
+     *
+     * @param s   a {@code String} containing the unsigned {@code long}
+     *            representation to be parsed
+     * @return    the unsigned {@code long} value represented by the decimal string argument
+     * @throws    NumberFormatException  if the string does not contain a
+     *            parsable unsigned integer.
+     * @since 1.8
+     */
+    public static long parseUnsignedLong(String s) throws NumberFormatException {
+        return parseUnsignedLong(s, 10);
+    }
+
+    /**
      * Returns a {@code Long} object holding the value
      * extracted from the specified {@code String} when parsed
      * with the radix given by the second argument.  The first
@@ -977,6 +1216,85 @@
         return (x < y) ? -1 : ((x == y) ? 0 : 1);
     }
 
+    /**
+     * Compares two {@code long} values numerically treating the values
+     * as unsigned.
+     *
+     * @param  x the first {@code long} to compare
+     * @param  y the second {@code long} to compare
+     * @return the value {@code 0} if {@code x == y}; a value less
+     *         than {@code 0} if {@code x < y} as unsigned values; and
+     *         a value greater than {@code 0} if {@code x > y} as
+     *         unsigned values
+     * @since 1.8
+     */
+    public static int compareUnsigned(long x, long y) {
+        return compare(x + MIN_VALUE, y + MIN_VALUE);
+    }
+
+
+    /**
+     * Returns the unsigned quotient of dividing the first argument by
+     * the second where each argument and the result is interpreted as
+     * an unsigned value.
+     *
+     * <p>Note that in two's complement arithmetic, the three other
+     * basic arithmetic operations of add, subtract, and multiply are
+     * bit-wise identical if the two operands are regarded as both
+     * being signed or both being unsigned.  Therefore separate {@code
+     * addUnsigned}, etc. methods are not provided.
+     *
+     * @param dividend the value to be divided
+     * @param divisor the value doing the dividing
+     * @return the unsigned quotient of the first argument divided by
+     * the second argument
+     * @see #remainderUnsigned
+     * @since 1.8
+     */
+    public static long divideUnsigned(long dividend, long divisor) {
+        if (divisor < 0L) { // signed comparison
+            // Answer must be 0 or 1 depending on relative magnitude
+            // of dividend and divisor.
+            return (compareUnsigned(dividend, divisor)) < 0 ? 0L :1L;
+        }
+
+        if (dividend > 0) //  Both inputs non-negative
+            return dividend/divisor;
+        else {
+            /*
+             * For simple code, leveraging BigInteger.  Longer and faster
+             * code written directly in terms of operations on longs is
+             * possible; see "Hacker's Delight" for divide and remainder
+             * algorithms.
+             */
+            return toUnsignedBigInteger(dividend).
+                divide(toUnsignedBigInteger(divisor)).longValue();
+        }
+    }
+
+    /**
+     * Returns the unsigned remainder from dividing the first argument
+     * by the second where each argument and the result is interpreted
+     * as an unsigned value.
+     *
+     * @param dividend the value to be divided
+     * @param divisor the value doing the dividing
+     * @return the unsigned remainder of the first argument divided by
+     * the second argument
+     * @see #divideUnsigned
+     * @since 1.8
+     */
+    public static long remainderUnsigned(long dividend, long divisor) {
+        if (dividend > 0 && divisor > 0) { // signed comparisons
+            return dividend % divisor;
+        } else {
+            if (compareUnsigned(dividend, divisor) < 0) // Avoid explicit check for 0 divisor
+                return dividend;
+            else
+                return toUnsignedBigInteger(dividend).
+                    remainder(toUnsignedBigInteger(divisor)).longValue();
+        }
+    }
 
     // Bit Twiddling
 
--- a/src/share/classes/java/lang/Short.java	Thu Jan 19 12:01:57 2012 -0800
+++ b/src/share/classes/java/lang/Short.java	Fri Jan 20 17:56:31 2012 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -469,6 +469,47 @@
         return (short) (((i & 0xFF00) >> 8) | (i << 8));
     }
 
+
+    /**
+     * Converts the argument to an {@code int} by an unsigned
+     * conversion.  In an unsigned conversion to an {@code int}, the
+     * high-order 16 bits of the {@code int} are zero and the
+     * low-order 16 bits are equal to the bits of the {@code short} argument.
+     *
+     * Consequently, zero and positive {@code short} values are mapped
+     * to a numerically equal {@code int} value and negative {@code
+     * short} values are mapped to an {@code int} value equal to the
+     * input plus 2<sup>16</sup>.
+     *
+     * @param  x the value to convert to an unsigned {@code int}
+     * @return the argument converted to {@code int} by an unsigned
+     *         conversion
+     * @since 1.8
+     */
+    public static int toUnsignedInt(short x) {
+        return ((int) x) & 0xffff;
+    }
+
+    /**
+     * Converts the argument to a {@code long} by an unsigned
+     * conversion.  In an unsigned conversion to a {@code long}, the
+     * high-order 48 bits of the {@code long} are zero and the
+     * low-order 16 bits are equal to the bits of the {@code short} argument.
+     *
+     * Consequently, zero and positive {@code short} values are mapped
+     * to a numerically equal {@code long} value and negative {@code
+     * short} values are mapped to a {@code long} value equal to the
+     * input plus 2<sup>16</sup>.
+     *
+     * @param  x the value to convert to an unsigned {@code long}
+     * @return the argument converted to {@code long} by an unsigned
+     *         conversion
+     * @since 1.8
+     */
+    public static long toUnsignedLong(short x) {
+        return ((long) x) & 0xffffL;
+    }
+
     /** use serialVersionUID from JDK 1.1. for interoperability */
     private static final long serialVersionUID = 7515723908773894738L;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Integer/Unsigned.java	Fri Jan 20 17:56:31 2012 -0800
@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 4504839 4215269 6322074
+ * @summary Basic tests for unsigned operations.
+ * @author Joseph D. Darcy
+ */
+public class Unsigned {
+    public static void main(String... args) {
+        int errors = 0;
+
+        errors += testRoundtrip();
+        errors += testByteToUnsignedInt();
+        errors += testShortToUnsignedInt();
+        errors += testUnsignedCompare();
+        errors += testToUnsignedLong();
+        errors += testToStringUnsigned();
+        errors += testParseUnsignedInt();
+        errors += testDivideAndRemainder();
+
+        if (errors > 0) {
+            throw new RuntimeException(errors + " errors found in unsigned operations.");
+        }
+    }
+
+    private static int testRoundtrip() {
+        int errors = 0;
+
+        int[] data = {-1, 0, 1};
+
+        for(int datum : data) {
+            if (Integer.parseUnsignedInt(Integer.toBinaryString(datum), 2) != datum) {
+                errors++;
+                System.err.println("Bad binary roundtrip conversion of " + datum);
+            }
+
+            if (Integer.parseUnsignedInt(Integer.toOctalString(datum), 8) != datum) {
+                errors++;
+                System.err.println("Bad octal roundtrip conversion of " + datum);
+            }
+
+            if (Integer.parseUnsignedInt(Integer.toHexString(datum), 16) != datum) {
+                errors++;
+                System.err.println("Bad hex roundtrip conversion of " + datum);
+            }
+        }
+        return errors;
+    }
+
+    private static int testByteToUnsignedInt() {
+        int errors = 0;
+
+        for(int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
+            byte datum = (byte) i;
+            int ui = Byte.toUnsignedInt(datum);
+
+            if ( (ui & (~0xff)) != 0 ||
+                 ((byte)ui != datum )) {
+                errors++;
+                System.err.printf("Bad conversion of byte %d to unsigned int %d%n",
+                                  datum, ui);
+            }
+        }
+        return errors;
+    }
+
+    private static int testShortToUnsignedInt() {
+        int errors = 0;
+
+        for(int i = Short.MIN_VALUE; i <= Short.MAX_VALUE; i++) {
+            short datum = (short) i;
+            int ui = Short.toUnsignedInt(datum);
+
+            if ( (ui & (~0xffff)) != 0 ||
+                 ((short)ui != datum )) {
+                errors++;
+                System.err.printf("Bad conversion of short %d to unsigned int %d%n",
+                                  datum, ui);
+            }
+        }
+        return errors;
+    }
+
+    private static int testUnsignedCompare() {
+        int errors = 0;
+
+        int[] data = {
+            0,
+            1,
+            2,
+            3,
+            0x8000_0000,
+            0x8000_0001,
+            0x8000_0002,
+            0x8000_0003,
+            0xFFFF_FFFE,
+            0xFFFF_FFFF,
+        };
+
+        for(int i : data) {
+            for(int j : data) {
+                int libraryResult    = Integer.compareUnsigned(i, j);
+                int libraryResultRev = Integer.compareUnsigned(j, i);
+                int localResult      = compUnsigned(i, j);
+
+                if (i == j) {
+                    if (libraryResult != 0) {
+                        errors++;
+                        System.err.printf("Value 0x%x did not compare as " +
+                                          "an unsigned value equal to itself; got %d%n",
+                                          i, libraryResult);
+                    }
+                }
+
+                if (Integer.signum(libraryResult) != Integer.signum(localResult)) {
+                    errors++;
+                    System.err.printf("Unsigned compare of 0x%x to 0x%x%n:" +
+                                      "\texpected sign of %d, got %d%n",
+                                      i, j, localResult, libraryResult);
+                }
+
+                if (Integer.signum(libraryResult) !=
+                    -Integer.signum(libraryResultRev)) {
+                    errors++;
+                    System.err.printf("signum(compareUnsigned(x, y)) != -signum(compareUnsigned(y,x))" +
+                                      " for \t0x%x and 0x%x, computed %d and %d%n",
+                                      i, j, libraryResult, libraryResultRev);
+                }
+            }
+        }
+
+        return errors;
+    }
+
+    /**
+     * Straightforward compare unsigned algorithm.
+     */
+    private static int compUnsigned(int x, int y) {
+        int sign_x = x & Integer.MIN_VALUE;
+        int sign_y = y & Integer.MIN_VALUE;
+
+        int mant_x  = x & (~Integer.MIN_VALUE);
+        int mant_y  = y & (~Integer.MIN_VALUE);
+
+        if (sign_x == sign_y)
+            return Integer.compare(mant_x, mant_y);
+        else {
+            if (sign_x == 0)
+                return -1; // sign x is 0, sign y is 1 => (x < y)
+            else
+                return 1; //  sign x is 1, sign y is 0 => (x > y)
+        }
+    }
+
+    private static int testToUnsignedLong() {
+        int errors = 0;
+
+        int[] data = {
+            0,
+            1,
+            2,
+            3,
+            0x1234_5678,
+            0x8000_0000,
+            0x8000_0001,
+            0x8000_0002,
+            0x8000_0003,
+            0x8765_4321,
+            0xFFFF_FFFE,
+            0xFFFF_FFFF,
+        };
+
+        for(int datum : data) {
+            long result = Integer.toUnsignedLong(datum);
+
+            // High-order bits should be zero
+            if ((result & 0xffff_ffff_0000_0000L) != 0L) {
+                errors++;
+                System.err.printf("High bits set converting 0x%x to 0x%x%n",
+                                  datum, result);
+            }
+
+            // Lower-order bits should be equal to datum.
+            int lowOrder = (int)(result & 0x0000_0000_ffff_ffffL);
+            if (lowOrder != datum ) {
+                errors++;
+                System.err.printf("Low bits not preserved converting 0x%x to 0x%x%n",
+                                  datum, result);
+            }
+        }
+        return errors;
+    }
+
+    private static int testToStringUnsigned() {
+        int errors = 0;
+
+        int[] data = {
+            0,
+            1,
+            2,
+            3,
+            99999,
+            100000,
+            999999,
+            100000,
+            999999999,
+            1000000000,
+            0x1234_5678,
+            0x8000_0000,
+            0x8000_0001,
+            0x8000_0002,
+            0x8000_0003,
+            0x8765_4321,
+            0xFFFF_FFFE,
+            0xFFFF_FFFF,
+        };
+
+        for(int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+            for(int datum : data) {
+                String result1 = Integer.toUnsignedString(datum, radix);
+                String result2 = Long.toString(Integer.toUnsignedLong(datum), radix);
+
+                if (!result1.equals(result2)) {
+                    errors++;
+                    System.err.printf("Unexpected string difference converting 0x%x:" +
+                                      "\t%s %s%n",
+                                      datum, result1, result2);
+                }
+
+                if (radix == 10) {
+                    String result3 = Integer.toUnsignedString(datum);
+                    if (!result2.equals(result3)) {
+                        errors++;
+                        System.err.printf("Unexpected string difference converting 0x%x:" +
+                                          "\t%s %s%n",
+                                          datum, result3, result2);
+                    }
+                }
+
+                int parseResult = Integer.parseUnsignedInt(result1, radix);
+
+                if (parseResult != datum) {
+                    errors++;
+                        System.err.printf("Bad roundtrip conversion of %d in base %d" +
+                                          "\tconverting back ''%s'' resulted in %d%n",
+                                          datum, radix, result1,  parseResult);
+                }
+            }
+        }
+
+        return errors;
+    }
+
+    private static final long MAX_UNSIGNED_INT = Integer.toUnsignedLong(0xffff_ffff);
+
+    private static int testParseUnsignedInt() {
+        int errors = 0;
+
+        // Values include those between signed Integer.MAX_VALUE and
+        // unsignted int MAX_VALUE.
+        long[] inRange = {
+            0L,
+            1L,
+            10L,
+            2147483646L,   // MAX_VALUE - 1
+            2147483647L,   // MAX_VALUE
+            2147483648L,   // MAX_VALUE + 1
+
+            MAX_UNSIGNED_INT - 1L,
+            MAX_UNSIGNED_INT,
+        };
+
+        for(long value : inRange) {
+            for(int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+                String longString = Long.toString(value, radix);
+                int intResult = Integer.parseUnsignedInt(longString, radix);
+
+                if (Integer.toUnsignedLong(intResult) != value) {
+                    errors++;
+                    System.err.printf("Bad roundtrip conversion of %d in base %d" +
+                                      "\tconverting back ''%s'' resulted in %d%n",
+                                      value, radix, longString,  intResult);
+                }
+            }
+        }
+
+        String[] outOfRange = {
+            null,
+            "",
+            "-1",
+            Long.toString(MAX_UNSIGNED_INT + 1L),
+            Long.toString(Long.MAX_VALUE)
+        };
+
+        for(String s : outOfRange) {
+            try {
+                int result = Integer.parseUnsignedInt(s);
+                errors++; // Should not reach here
+                System.err.printf("Unexpected got %d from an unsigned conversion of %s",
+                                  result, s);
+            } catch(NumberFormatException nfe) {
+                ; // Correct result
+            }
+        }
+
+        return errors;
+    }
+
+    private static int testDivideAndRemainder() {
+        int errors = 0;
+
+        long[] inRange = {
+            0L,
+            1L,
+            2L,
+            2147483646L,   // MAX_VALUE - 1
+            2147483647L,   // MAX_VALUE
+            2147483648L,   // MAX_VALUE + 1
+
+            MAX_UNSIGNED_INT - 1L,
+            MAX_UNSIGNED_INT,
+        };
+
+        for(long dividend : inRange) {
+            for(long divisor : inRange) {
+                int quotient;
+                long longQuotient;
+
+                int remainder;
+                long longRemainder;
+
+                if (divisor == 0) {
+                    try {
+                        quotient = Integer.divideUnsigned((int) dividend, (int) divisor);
+                        errors++;
+                    } catch(ArithmeticException ea) {
+                        ; // Expected
+                    }
+
+                    try {
+                        remainder = Integer.remainderUnsigned((int) dividend, (int) divisor);
+                        errors++;
+                    } catch(ArithmeticException ea) {
+                        ; // Expected
+                    }
+                } else {
+                    quotient = Integer.divideUnsigned((int) dividend, (int) divisor);
+                    longQuotient = dividend / divisor;
+
+                    if (quotient != (int)longQuotient) {
+                        errors++;
+                        System.err.printf("Unexpected unsigned divide result %s on %s/%s%n",
+                                          Integer.toUnsignedString(quotient),
+                                          Integer.toUnsignedString((int) dividend),
+                                          Integer.toUnsignedString((int) divisor));
+                    }
+
+                    remainder = Integer.remainderUnsigned((int) dividend, (int) divisor);
+                    longRemainder = dividend % divisor;
+
+                    if (remainder != (int)longRemainder) {
+                        errors++;
+                        System.err.printf("Unexpected unsigned remainder result %s on %s%%%s%n",
+                                          Integer.toUnsignedString(remainder),
+                                          Integer.toUnsignedString((int) dividend),
+                                          Integer.toUnsignedString((int) divisor));
+                    }
+                }
+            }
+        }
+
+        return errors;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Long/Unsigned.java	Fri Jan 20 17:56:31 2012 -0800
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 4504839 4215269 6322074
+ * @summary Basic tests for unsigned operations
+ * @author Joseph D. Darcy
+ */
+
+import java.math.*;
+
+public class Unsigned {
+    public static void main(String... args) {
+        int errors = 0;
+
+        errors += testRoundtrip();
+        errors += testByteToUnsignedLong();
+        errors += testShortToUnsignedLong();
+        errors += testUnsignedCompare();
+        errors += testToStringUnsigned();
+        errors += testParseUnsignedLong();
+        errors += testDivideAndRemainder();
+
+        if (errors > 0) {
+            throw new RuntimeException(errors + " errors found in unsigned operations.");
+        }
+    }
+
+    private static final BigInteger TWO = BigInteger.valueOf(2L);
+
+    private static int testRoundtrip() {
+        int errors = 0;
+
+        long[] data = {-1L, 0L, 1L};
+
+        for(long datum : data) {
+            if (Long.parseUnsignedLong(Long.toBinaryString(datum), 2) != datum) {
+                errors++;
+                System.err.println("Bad binary roundtrip conversion of " + datum);
+            }
+
+            if (Long.parseUnsignedLong(Long.toOctalString(datum), 8) != datum) {
+                errors++;
+                System.err.println("Bad octal roundtrip conversion of " + datum);
+            }
+
+            if (Long.parseUnsignedLong(Long.toHexString(datum), 16) != datum) {
+                errors++;
+                System.err.println("Bad hex roundtrip conversion of " + datum);
+            }
+        }
+        return errors;
+    }
+
+    private static int testByteToUnsignedLong() {
+        int errors = 0;
+
+        for(int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
+            byte datum = (byte) i;
+            long ui = Byte.toUnsignedLong(datum);
+
+            if ( (ui & (~0xffL)) != 0L ||
+                 ((byte)ui != datum )) {
+                errors++;
+                System.err.printf("Bad conversion of byte %d to unsigned long %d%n",
+                                  datum, ui);
+            }
+        }
+        return errors;
+    }
+
+    private static int testShortToUnsignedLong() {
+        int errors = 0;
+
+        for(int i = Short.MIN_VALUE; i <= Short.MAX_VALUE; i++) {
+            short datum = (short) i;
+            long ui = Short.toUnsignedLong(datum);
+
+            if ( (ui & (~0xffffL)) != 0L ||
+                 ((short)ui != datum )) {
+                errors++;
+                System.err.printf("Bad conversion of short %d to unsigned long %d%n",
+                                  datum, ui);
+            }
+        }
+        return errors;
+    }
+    private static int testUnsignedCompare() {
+        int errors = 0;
+
+        long[] data = {
+            0L,
+            1L,
+            2L,
+            3L,
+            0x00000000_80000000L,
+            0x00000000_FFFFFFFFL,
+            0x00000001_00000000L,
+            0x80000000_00000000L,
+            0x80000000_00000001L,
+            0x80000000_00000002L,
+            0x80000000_00000003L,
+            0x80000000_80000000L,
+            0xFFFFFFFF_FFFFFFFEL,
+            0xFFFFFFFF_FFFFFFFFL,
+        };
+
+        for(long i : data) {
+            for(long j : data) {
+                long libraryResult    = Long.compareUnsigned(i, j);
+                long libraryResultRev = Long.compareUnsigned(j, i);
+                long localResult      = compUnsigned(i, j);
+
+                if (i == j) {
+                    if (libraryResult != 0) {
+                        errors++;
+                        System.err.printf("Value 0x%x did not compare as " +
+                                          "an unsigned equal to itself; got %d%n",
+                                          i, libraryResult);
+                    }
+                }
+
+                   if (Long.signum(libraryResult) != Long.signum(localResult)) {
+                       errors++;
+                       System.err.printf("Unsigned compare of 0x%x to 0x%x%n:" +
+                                         "\texpected sign of %d, got %d%n",
+                                         i, j, localResult, libraryResult);
+                   }
+
+                if (Long.signum(libraryResult) !=
+                    -Long.signum(libraryResultRev)) {
+                    errors++;
+                    System.err.printf("signum(compareUnsigned(x, y)) != -signum(compareUnsigned(y,x))" +
+                                      " for \t0x%x and 0x%x, computed %d and %d%n",
+                                      i, j, libraryResult, libraryResultRev);
+                }
+            }
+        }
+
+        return errors;
+    }
+
+    private static int compUnsigned(long x, long y) {
+        BigInteger big_x = toUnsignedBigInt(x);
+        BigInteger big_y = toUnsignedBigInt(y);
+
+        return big_x.compareTo(big_y);
+    }
+
+    private static BigInteger toUnsignedBigInt(long x) {
+        if (x >= 0)
+            return BigInteger.valueOf(x);
+        else {
+            int upper = (int)(((long)x) >> 32);
+            int lower = (int) x;
+
+            BigInteger bi = // (upper << 32) + lower
+                (BigInteger.valueOf(Integer.toUnsignedLong(upper))).shiftLeft(32).
+                add(BigInteger.valueOf(Integer.toUnsignedLong(lower)));
+
+            // System.out.printf("%n\t%d%n\t%s%n", x, bi.toString());
+            return bi;
+        }
+    }
+
+    private static int testToStringUnsigned() {
+        int errors = 0;
+
+        long[] data = {
+            0L,
+            1L,
+            2L,
+            3L,
+            99999L,
+            100000L,
+            999999L,
+            100000L,
+            999999999L,
+            1000000000L,
+            0x1234_5678L,
+            0x8000_0000L,
+            0x8000_0001L,
+            0x8000_0002L,
+            0x8000_0003L,
+            0x8765_4321L,
+            0xFFFF_FFFEL,
+            0xFFFF_FFFFL,
+
+            // Long-range values
+              999_999_999_999L,
+            1_000_000_000_000L,
+
+              999_999_999_999_999_999L,
+            1_000_000_000_000_000_000L,
+
+            0xFFFF_FFFF_FFFF_FFFEL,
+            0xFFFF_FFFF_FFFF_FFFFL,
+        };
+
+        for(int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+            for(long datum : data) {
+                String result1 = Long.toUnsignedString(datum, radix);
+                String result2 = toUnsignedBigInt(datum).toString(radix);
+
+                if (!result1.equals(result2)) {
+                    errors++;
+                    System.err.printf("Unexpected string difference converting 0x%x:" +
+                                      "\t%s %s%n",
+                                      datum, result1, result2);
+                }
+
+                if (radix == 10) {
+                    String result3 = Long.toUnsignedString(datum);
+                    if (!result2.equals(result3)) {
+                        errors++;
+                        System.err.printf("Unexpected string difference converting 0x%x:" +
+                                          "\t%s %s%n",
+                                          datum, result3, result2);
+                    }
+                }
+
+                long parseResult = Long.parseUnsignedLong(result1, radix);
+
+                if (parseResult != datum) {
+                    errors++;
+                        System.err.printf("Bad roundtrip conversion of %d in base %d" +
+                                          "\tconverting back ''%s'' resulted in %d%n",
+                                          datum, radix, result1,  parseResult);
+                }
+            }
+        }
+
+        return errors;
+    }
+
+    private static int testParseUnsignedLong() {
+        int errors = 0;
+        long maxUnsignedInt = Integer.toUnsignedLong(0xffff_ffff);
+
+        // Values include those between signed Long.MAX_VALUE and
+        // unsignted Long MAX_VALUE.
+        BigInteger[] inRange = {
+            BigInteger.valueOf(0L),
+            BigInteger.valueOf(1L),
+            BigInteger.valueOf(10L),
+            BigInteger.valueOf(2147483646L),   // Integer.MAX_VALUE - 1
+            BigInteger.valueOf(2147483647L),   // Integer.MAX_VALUE
+            BigInteger.valueOf(2147483648L),   // Integer.MAX_VALUE + 1
+
+            BigInteger.valueOf(maxUnsignedInt - 1L),
+            BigInteger.valueOf(maxUnsignedInt),
+
+            BigInteger.valueOf(Long.MAX_VALUE - 1L),
+            BigInteger.valueOf(Long.MAX_VALUE),
+            BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE),
+
+            TWO.pow(64).subtract(BigInteger.ONE)
+        };
+
+        for(BigInteger value : inRange) {
+            for(int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
+                String bigString = value.toString(radix);
+                long longResult = Long.parseUnsignedLong(bigString, radix);
+
+                if (!toUnsignedBigInt(longResult).equals(value)) {
+                    errors++;
+                    System.err.printf("Bad roundtrip conversion of %d in base %d" +
+                                      "\tconverting back ''%s'' resulted in %d%n",
+                                      value, radix, bigString,  longResult);
+                }
+            }
+        }
+
+        String[] outOfRange = {
+            null,
+            "",
+            "-1",
+            TWO.pow(64).toString(),
+        };
+
+        for(String s : outOfRange) {
+            try {
+                long result = Long.parseUnsignedLong(s);
+                errors++; // Should not reach here
+                System.err.printf("Unexpected got %d from an unsigned conversion of %s",
+                                  result, s);
+            } catch(NumberFormatException nfe) {
+                ; // Correct result
+            }
+        }
+
+        return errors;
+    }
+
+    private static int testDivideAndRemainder() {
+        int errors = 0;
+        long MAX_UNSIGNED_INT = Integer.toUnsignedLong(0xffff_ffff);
+
+        BigInteger[] inRange = {
+            BigInteger.valueOf(0L),
+            BigInteger.valueOf(1L),
+            BigInteger.valueOf(10L),
+            BigInteger.valueOf(2147483646L),   // Integer.MAX_VALUE - 1
+            BigInteger.valueOf(2147483647L),   // Integer.MAX_VALUE
+            BigInteger.valueOf(2147483648L),   // Integer.MAX_VALUE + 1
+
+            BigInteger.valueOf(MAX_UNSIGNED_INT - 1L),
+            BigInteger.valueOf(MAX_UNSIGNED_INT),
+
+            BigInteger.valueOf(Long.MAX_VALUE - 1L),
+            BigInteger.valueOf(Long.MAX_VALUE),
+            BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE),
+
+            TWO.pow(64).subtract(BigInteger.ONE)
+        };
+
+        for(BigInteger dividend : inRange) {
+            for(BigInteger divisor : inRange) {
+                long quotient;
+                BigInteger longQuotient;
+
+                long remainder;
+                BigInteger longRemainder;
+
+                if (divisor.equals(BigInteger.ZERO)) {
+                    try {
+                        quotient = Long.divideUnsigned(dividend.longValue(), divisor.longValue());
+                        errors++;
+                    } catch(ArithmeticException ea) {
+                        ; // Expected
+                    }
+
+                    try {
+                        remainder = Long.remainderUnsigned(dividend.longValue(), divisor.longValue());
+                        errors++;
+                    } catch(ArithmeticException ea) {
+                        ; // Expected
+                    }
+                } else {
+                    quotient = Long.divideUnsigned(dividend.longValue(), divisor.longValue());
+                    longQuotient = dividend.divide(divisor);
+
+                    if (quotient != longQuotient.longValue()) {
+                        errors++;
+                        System.err.printf("Unexpected unsigned divide result %s on %s/%s%n",
+                                          Long.toUnsignedString(quotient),
+                                          Long.toUnsignedString(dividend.longValue()),
+                                          Long.toUnsignedString(divisor.longValue()));
+                    }
+
+                    remainder = Long.remainderUnsigned(dividend.longValue(), divisor.longValue());
+                    longRemainder = dividend.remainder(divisor);
+
+                    if (remainder != longRemainder.longValue()) {
+                        errors++;
+                        System.err.printf("Unexpected unsigned remainder result %s on %s%%%s%n",
+                                          Long.toUnsignedString(remainder),
+                                          Long.toUnsignedString(dividend.longValue()),
+                                          Long.toUnsignedString(divisor.longValue()));
+                    }
+                }
+            }
+        }
+
+        return errors;
+    }
+}