--- old/src/share/classes/java/lang/Byte.java 2012-01-20 17:55:53.000000000 -0800 +++ new/src/share/classes/java/lang/Byte.java 2012-01-20 17:55:53.000000000 -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 28. + * + * @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 28. + * + * @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. * --- old/src/share/classes/java/lang/Integer.java 2012-01-20 17:55:54.000000000 -0800 +++ new/src/share/classes/java/lang/Integer.java 2012-01-20 17:55:54.000000000 -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. + * + *

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. + * + *

Note that since the first argument is treated as an unsigned + * value, no leading sign character is printed. + * + *

If the magnitude is zero, it is represented by a single zero + * character {@code '0'} ('\u0030'); otherwise, + * the first character of the representation of the magnitude will + * not be the zero character. + * + *

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 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 16) with no extra leading - * {@code 0}s. If the unsigned magnitude is zero, it is - * represented by a single zero character {@code '0'} - * ('\u0030'); 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. + * + *

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)}. + * + *

If the unsigned magnitude is zero, it is represented by a + * single zero character {@code '0'} ('\u0030'); + * 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 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 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 8) with no extra leading {@code 0}s. * + *

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)}. + * *

If the unsigned magnitude is zero, it is represented by a - * single zero character {@code '0'} - * ('\u0030'); 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'} ('\u0030'); + * 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: * *

* {@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 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 2) with no extra leading {@code 0}s. - * If the unsigned magnitude is zero, it is represented by a - * single zero character {@code '0'} - * ('\u0030'); otherwise, the first character of - * the representation of the unsigned magnitude will not be the - * zero character. The characters {@code '0'} - * ('\u0030') and {@code '1'} - * ('\u0031') are used as binary digits. + * + *

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)}. + * + *

If the unsigned magnitude is zero, it is represented by a + * single zero character {@code '0'} ('\u0030'); + * otherwise, the first character of the representation of the + * unsigned magnitude will not be the zero character. The + * characters {@code '0'} ('\u0030') and {@code + * '1'} ('\u0031') 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 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 '+'} ('\u002B'). The resulting + * integer value is returned. + * + *

An exception of type {@code NumberFormatException} is + * thrown if any of the following situations occurs: + *

+ * + * + * @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 + * '+'} ('\u002B'). 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 232. + * + * @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. + * + *

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 --- old/src/share/classes/java/lang/Long.java 2012-01-20 17:55:54.000000000 -0800 +++ new/src/share/classes/java/lang/Long.java 2012-01-20 17:55:54.000000000 -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. + * + *

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. + * + *

Note that since the first argument is treated as an unsigned + * value, no leading sign character is printed. + * + *

If the magnitude is zero, it is represented by a single zero + * character {@code '0'} ('\u0030'); otherwise, + * the first character of the representation of the magnitude will + * not be the zero character. + * + *

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 16. * @@ -147,12 +231,18 @@ * 264 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 16) with no extra - * leading {@code 0}s. If the unsigned magnitude is zero, it - * is represented by a single zero character {@code '0'} - * ('\u0030'); 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. + * + *

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)}. + * + *

If the unsigned magnitude is zero, it is represented by a + * single zero character {@code '0'} ('\u0030'); + * 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 0123456789abcdef} @@ -172,10 +262,12 @@ * @return the string representation of the unsigned {@code long} * value represented by the argument in hexadecimal * (base 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 8) with no extra leading * {@code 0}s. * + *

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)}. + * *

If the unsigned magnitude is zero, it is represented by a - * single zero character {@code '0'} - * ('\u0030'); 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'} ('\u0030'); + * 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: * *

* {@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 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 @@ * 264 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 2) with no extra leading - * {@code 0}s. If the unsigned magnitude is zero, it is - * represented by a single zero character {@code '0'} - * ('\u0030'); otherwise, the first character of - * the representation of the unsigned magnitude will not be the - * zero character. The characters {@code '0'} - * ('\u0030') and {@code '1'} - * ('\u0031') are used as binary digits. + * {@code 0}s. + * + *

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)}. + * + *

If the unsigned magnitude is zero, it is represented by a + * single zero character {@code '0'} ('\u0030'); + * otherwise, the first character of the representation of the + * unsigned magnitude will not be the zero character. The + * characters {@code '0'} ('\u0030') and {@code + * '1'} ('\u0031') 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 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 '+'} ('\u002B'). The resulting + * integer value is returned. + * + *

An exception of type {@code NumberFormatException} is + * thrown if any of the following situations occurs: + *

    + *
  • The first argument is {@code null} or is a string of + * length zero. + * + *
  • The radix is either smaller than + * {@link java.lang.Character#MIN_RADIX} or + * larger than {@link java.lang.Character#MAX_RADIX}. + * + *
  • Any character of the string is not a digit of the specified + * radix, except that the first character may be a plus sign + * {@code '+'} ('\u002B') provided that the + * string is longer than length 1. + * + *
  • The value represented by the string is larger than the + * largest unsigned {@code long}, 264-1. + * + *
+ * + * + * @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 + * '+'} ('\u002B'). 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. + * + *

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 --- old/src/share/classes/java/lang/Short.java 2012-01-20 17:55:55.000000000 -0800 +++ new/src/share/classes/java/lang/Short.java 2012-01-20 17:55:55.000000000 -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 216. + * + * @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 216. + * + * @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 2012-01-10 11:47:00.807870926 -0800 +++ new/test/java/lang/Integer/Unsigned.java 2012-01-20 17:55:55.000000000 -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 2012-01-10 11:47:00.807870926 -0800 +++ new/test/java/lang/Long/Unsigned.java 2012-01-20 17:55:56.000000000 -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; + } +}