1 /*
   2  * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 4504839 4215269 6322074 8030814
  27  * @summary Basic tests for unsigned operations
  28  * @author Joseph D. Darcy
  29  */
  30 
  31 import java.math.*;
  32 
  33 public class Unsigned {
  34     public static void main(String... args) {
  35         int errors = 0;
  36 
  37         errors += testRoundtrip();
  38         errors += testByteToUnsignedLong();
  39         errors += testShortToUnsignedLong();
  40         errors += testUnsignedCompare();
  41         errors += testToStringUnsigned();
  42         errors += testParseUnsignedLong();
  43         errors += testDivideAndRemainder();
  44 
  45         if (errors > 0) {
  46             throw new RuntimeException(errors + " errors found in unsigned operations.");
  47         }
  48     }
  49 
  50     private static final BigInteger TWO = BigInteger.valueOf(2L);
  51 
  52     private static int testRoundtrip() {
  53         int errors = 0;
  54 
  55         long[] data = {-1L, 0L, 1L};
  56 
  57         for(long datum : data) {
  58             if (Long.parseUnsignedLong(Long.toBinaryString(datum), 2) != datum) {
  59                 errors++;
  60                 System.err.println("Bad binary roundtrip conversion of " + datum);
  61             }
  62 
  63             if (Long.parseUnsignedLong(Long.toOctalString(datum), 8) != datum) {
  64                 errors++;
  65                 System.err.println("Bad octal roundtrip conversion of " + datum);
  66             }
  67 
  68             if (Long.parseUnsignedLong(Long.toHexString(datum), 16) != datum) {
  69                 errors++;
  70                 System.err.println("Bad hex roundtrip conversion of " + datum);
  71             }
  72         }
  73         return errors;
  74     }
  75 
  76     private static int testByteToUnsignedLong() {
  77         int errors = 0;
  78 
  79         for(int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
  80             byte datum = (byte) i;
  81             long ui = Byte.toUnsignedLong(datum);
  82 
  83             if ( (ui & (~0xffL)) != 0L ||
  84                  ((byte)ui != datum )) {
  85                 errors++;
  86                 System.err.printf("Bad conversion of byte %d to unsigned long %d%n",
  87                                   datum, ui);
  88             }
  89         }
  90         return errors;
  91     }
  92 
  93     private static int testShortToUnsignedLong() {
  94         int errors = 0;
  95 
  96         for(int i = Short.MIN_VALUE; i <= Short.MAX_VALUE; i++) {
  97             short datum = (short) i;
  98             long ui = Short.toUnsignedLong(datum);
  99 
 100             if ( (ui & (~0xffffL)) != 0L ||
 101                  ((short)ui != datum )) {
 102                 errors++;
 103                 System.err.printf("Bad conversion of short %d to unsigned long %d%n",
 104                                   datum, ui);
 105             }
 106         }
 107         return errors;
 108     }
 109     private static int testUnsignedCompare() {
 110         int errors = 0;
 111 
 112         long[] data = {
 113             0L,
 114             1L,
 115             2L,
 116             3L,
 117             0x00000000_80000000L,
 118             0x00000000_FFFFFFFFL,
 119             0x00000001_00000000L,
 120             0x80000000_00000000L,
 121             0x80000000_00000001L,
 122             0x80000000_00000002L,
 123             0x80000000_00000003L,
 124             0x80000000_80000000L,
 125             0xFFFFFFFF_FFFFFFFEL,
 126             0xFFFFFFFF_FFFFFFFFL,
 127         };
 128 
 129         for(long i : data) {
 130             for(long j : data) {
 131                 long libraryResult    = Long.compareUnsigned(i, j);
 132                 long libraryResultRev = Long.compareUnsigned(j, i);
 133                 long localResult      = compUnsigned(i, j);
 134 
 135                 if (i == j) {
 136                     if (libraryResult != 0) {
 137                         errors++;
 138                         System.err.printf("Value 0x%x did not compare as " +
 139                                           "an unsigned equal to itself; got %d%n",
 140                                           i, libraryResult);
 141                     }
 142                 }
 143 
 144                    if (Long.signum(libraryResult) != Long.signum(localResult)) {
 145                        errors++;
 146                        System.err.printf("Unsigned compare of 0x%x to 0x%x%n:" +
 147                                          "\texpected sign of %d, got %d%n",
 148                                          i, j, localResult, libraryResult);
 149                    }
 150 
 151                 if (Long.signum(libraryResult) !=
 152                     -Long.signum(libraryResultRev)) {
 153                     errors++;
 154                     System.err.printf("signum(compareUnsigned(x, y)) != -signum(compareUnsigned(y,x))" +
 155                                       " for \t0x%x and 0x%x, computed %d and %d%n",
 156                                       i, j, libraryResult, libraryResultRev);
 157                 }
 158             }
 159         }
 160 
 161         return errors;
 162     }
 163 
 164     private static int compUnsigned(long x, long y) {
 165         BigInteger big_x = toUnsignedBigInt(x);
 166         BigInteger big_y = toUnsignedBigInt(y);
 167 
 168         return big_x.compareTo(big_y);
 169     }
 170 
 171     private static BigInteger toUnsignedBigInt(long x) {
 172         if (x >= 0)
 173             return BigInteger.valueOf(x);
 174         else {
 175             int upper = (int)(((long)x) >> 32);
 176             int lower = (int) x;
 177 
 178             BigInteger bi = // (upper << 32) + lower
 179                 (BigInteger.valueOf(Integer.toUnsignedLong(upper))).shiftLeft(32).
 180                 add(BigInteger.valueOf(Integer.toUnsignedLong(lower)));
 181 
 182             // System.out.printf("%n\t%d%n\t%s%n", x, bi.toString());
 183             return bi;
 184         }
 185     }
 186 
 187     private static int testToStringUnsigned() {
 188         int errors = 0;
 189 
 190         long[] data = {
 191             0L,
 192             1L,
 193             2L,
 194             3L,
 195             99999L,
 196             100000L,
 197             999999L,
 198             100000L,
 199             999999999L,
 200             1000000000L,
 201             0x1234_5678L,
 202             0x8000_0000L,
 203             0x8000_0001L,
 204             0x8000_0002L,
 205             0x8000_0003L,
 206             0x8765_4321L,
 207             0xFFFF_FFFEL,
 208             0xFFFF_FFFFL,
 209 
 210             // Long-range values
 211               999_999_999_999L,
 212             1_000_000_000_000L,
 213 
 214               999_999_999_999_999_999L,
 215             1_000_000_000_000_000_000L,
 216 
 217             0xFFFF_FFFF_FFFF_FFFEL,
 218             0xFFFF_FFFF_FFFF_FFFFL,
 219         };
 220 
 221         for(int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
 222             for(long datum : data) {
 223                 String result1 = Long.toUnsignedString(datum, radix);
 224                 String result2 = toUnsignedBigInt(datum).toString(radix);
 225 
 226                 if (!result1.equals(result2)) {
 227                     errors++;
 228                     System.err.printf("Unexpected string difference converting 0x%x:" +
 229                                       "\t%s %s%n",
 230                                       datum, result1, result2);
 231                 }
 232 
 233                 if (radix == 10) {
 234                     String result3 = Long.toUnsignedString(datum);
 235                     if (!result2.equals(result3)) {
 236                         errors++;
 237                         System.err.printf("Unexpected string difference converting 0x%x:" +
 238                                           "\t%s %s%n",
 239                                           datum, result3, result2);
 240                     }
 241                 }
 242 
 243                 long parseResult = Long.parseUnsignedLong(result1, radix);
 244 
 245                 if (parseResult != datum) {
 246                     errors++;
 247                         System.err.printf("Bad roundtrip conversion of %d in base %d" +
 248                                           "\tconverting back ''%s'' resulted in %d%n",
 249                                           datum, radix, result1,  parseResult);
 250                 }
 251             }
 252         }
 253 
 254         return errors;
 255     }
 256 
 257     private static int testParseUnsignedLong() {
 258         int errors = 0;
 259         long maxUnsignedInt = Integer.toUnsignedLong(0xffff_ffff);
 260 
 261         // Values include those between signed Long.MAX_VALUE and
 262         // unsignted Long MAX_VALUE.
 263         BigInteger[] inRange = {
 264             BigInteger.valueOf(0L),
 265             BigInteger.valueOf(1L),
 266             BigInteger.valueOf(10L),
 267             BigInteger.valueOf(2147483646L),   // Integer.MAX_VALUE - 1
 268             BigInteger.valueOf(2147483647L),   // Integer.MAX_VALUE
 269             BigInteger.valueOf(2147483648L),   // Integer.MAX_VALUE + 1
 270 
 271             BigInteger.valueOf(maxUnsignedInt - 1L),
 272             BigInteger.valueOf(maxUnsignedInt),
 273 
 274             BigInteger.valueOf(Long.MAX_VALUE - 1L),
 275             BigInteger.valueOf(Long.MAX_VALUE),
 276             BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE),
 277 
 278             TWO.pow(64).subtract(BigInteger.ONE)
 279         };
 280 
 281         for(BigInteger value : inRange) {
 282             for(int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
 283                 String bigString = value.toString(radix);
 284                 long longResult = Long.parseUnsignedLong(bigString, radix);
 285 
 286                 if (!toUnsignedBigInt(longResult).equals(value)) {
 287                     errors++;
 288                     System.err.printf("Bad roundtrip conversion of %d in base %d" +
 289                                       "\tconverting back ''%s'' resulted in %d%n",
 290                                       value, radix, bigString,  longResult);
 291                 }
 292 
 293                 // test offset based parse method
 294                 longResult = Long.parseUnsignedLong("prefix" + bigString + "suffix", "prefix".length(),
 295                         "prefix".length() + bigString.length(), radix);
 296 
 297                 if (!toUnsignedBigInt(longResult).equals(value)) {
 298                     errors++;
 299                     System.err.printf("Bad roundtrip conversion of %d in base %d" +
 300                             "\tconverting back ''%s'' resulted in %d%n",
 301                             value, radix, bigString,  longResult);
 302                 }
 303             }
 304         }
 305 
 306         String[] outOfRange = {
 307             null,
 308             "",
 309             "-1",
 310             TWO.pow(64).toString(),
 311         };
 312 
 313         for(String s : outOfRange) {
 314             try {
 315                 long result = Long.parseUnsignedLong(s);
 316                 errors++; // Should not reach here
 317                 System.err.printf("Unexpected got %d from an unsigned conversion of %s",
 318                                   result, s);
 319             } catch(NumberFormatException nfe) {
 320                 ; // Correct result
 321             }
 322         }
 323 
 324         // test case known at one time to fail
 325         errors += testUnsignedOverflow("1234567890abcdef1", 16, true);
 326 
 327         // largest value with guard = 91 = 13*7; radix = 13
 328         errors += testUnsignedOverflow("196a78a44c3bba320c", 13, false);
 329 
 330         // smallest value with guard = 92 = 23*2*2; radix = 23
 331         errors += testUnsignedOverflow("137060c6g1c1dg0", 23, false);
 332 
 333         // guard in [92,98]: no overflow
 334 
 335         // one less than smallest guard value to overflow: guard = 99 = 11*3*3, radix = 33
 336         errors += testUnsignedOverflow("b1w8p7j5q9r6f", 33, false);
 337 
 338         // smallest guard value to overflow: guard = 99 = 11*3*3, radix = 33
 339         errors += testUnsignedOverflow("b1w8p7j5q9r6g", 33, true);
 340 
 341         // test overflow of overflow
 342         BigInteger maxUnsignedLong =
 343                 BigInteger.ONE.shiftLeft(64).subtract(BigInteger.ONE);
 344         for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) {
 345             BigInteger quotient = maxUnsignedLong.divide(BigInteger.valueOf(radix));
 346             for (int addend = 2; addend <= radix; addend++) {
 347                 BigInteger b = quotient.multiply(BigInteger.valueOf(radix + addend));
 348                 errors += testUnsignedOverflow(b.toString(radix), radix, b.compareTo(maxUnsignedLong) > 0);
 349             }
 350         }
 351 
 352         return errors;
 353     }
 354 
 355     // test for missing or unexpected unsigned overflow exception
 356     private static int testUnsignedOverflow(String s, int radix, boolean exception) {
 357         int errors = 0;
 358         long result;
 359         try {
 360             result = Long.parseUnsignedLong(s, radix);
 361             if (exception) {
 362                 System.err.printf("Unexpected result %d for Long.parseUnsignedLong(%s,%d)\n",
 363                         result, s, radix);
 364                 errors++;
 365             }
 366         } catch (NumberFormatException nfe) {
 367             if (!exception) {
 368                 System.err.printf("Unexpected exception %s for Long.parseUnsignedLong(%s,%d)\n",
 369                         nfe.toString(), s, radix);
 370                 errors++;
 371             }
 372         }
 373         return errors;
 374     }
 375 
 376     private static int testDivideAndRemainder() {
 377         int errors = 0;
 378         long MAX_UNSIGNED_INT = Integer.toUnsignedLong(0xffff_ffff);
 379 
 380         BigInteger[] inRange = {
 381             BigInteger.valueOf(0L),
 382             BigInteger.valueOf(1L),
 383             BigInteger.valueOf(10L),
 384             BigInteger.valueOf(2147483646L),   // Integer.MAX_VALUE - 1
 385             BigInteger.valueOf(2147483647L),   // Integer.MAX_VALUE
 386             BigInteger.valueOf(2147483648L),   // Integer.MAX_VALUE + 1
 387 
 388             BigInteger.valueOf(MAX_UNSIGNED_INT - 1L),
 389             BigInteger.valueOf(MAX_UNSIGNED_INT),
 390 
 391             BigInteger.valueOf(Long.MAX_VALUE - 1L),
 392             BigInteger.valueOf(Long.MAX_VALUE),
 393             BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE),
 394 
 395             TWO.pow(64).subtract(BigInteger.ONE)
 396         };
 397 
 398         for(BigInteger dividend : inRange) {
 399             for(BigInteger divisor : inRange) {
 400                 long quotient;
 401                 BigInteger longQuotient;
 402 
 403                 long remainder;
 404                 BigInteger longRemainder;
 405 
 406                 if (divisor.equals(BigInteger.ZERO)) {
 407                     try {
 408                         quotient = Long.divideUnsigned(dividend.longValue(), divisor.longValue());
 409                         errors++;
 410                     } catch(ArithmeticException ea) {
 411                         ; // Expected
 412                     }
 413 
 414                     try {
 415                         remainder = Long.remainderUnsigned(dividend.longValue(), divisor.longValue());
 416                         errors++;
 417                     } catch(ArithmeticException ea) {
 418                         ; // Expected
 419                     }
 420                 } else {
 421                     quotient = Long.divideUnsigned(dividend.longValue(), divisor.longValue());
 422                     longQuotient = dividend.divide(divisor);
 423 
 424                     if (quotient != longQuotient.longValue()) {
 425                         errors++;
 426                         System.err.printf("Unexpected unsigned divide result %s on %s/%s%n",
 427                                           Long.toUnsignedString(quotient),
 428                                           Long.toUnsignedString(dividend.longValue()),
 429                                           Long.toUnsignedString(divisor.longValue()));
 430                     }
 431 
 432                     remainder = Long.remainderUnsigned(dividend.longValue(), divisor.longValue());
 433                     longRemainder = dividend.remainder(divisor);
 434 
 435                     if (remainder != longRemainder.longValue()) {
 436                         errors++;
 437                         System.err.printf("Unexpected unsigned remainder result %s on %s%%%s%n",
 438                                           Long.toUnsignedString(remainder),
 439                                           Long.toUnsignedString(dividend.longValue()),
 440                                           Long.toUnsignedString(divisor.longValue()));
 441                     }
 442                 }
 443             }
 444         }
 445 
 446         return errors;
 447     }
 448 }