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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  20  * CA 95054 USA or visit www.sun.com if you need additional information or
  21  * have any questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 4504839 4215269 6322074
  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         }
 294 
 295         String[] outOfRange = {
 296             null,
 297             "",
 298             "-1",
 299             TWO.pow(64).toString(),
 300         };
 301 
 302         for(String s : outOfRange) {
 303             try {
 304                 long result = Long.parseUnsignedLong(s);
 305                 errors++; // Should not reach here
 306                 System.err.printf("Unexpected got %d from an unsigned conversion of %s",
 307                                   result, s);
 308             } catch(NumberFormatException nfe) {
 309                 ; // Correct result
 310             }
 311         }
 312 
 313         return errors;
 314     }
 315 
 316     private static int testDivideAndRemainder() {
 317         int errors = 0;
 318         long MAX_UNSIGNED_INT = Integer.toUnsignedLong(0xffff_ffff);
 319 
 320         BigInteger[] inRange = {
 321             BigInteger.valueOf(0L),
 322             BigInteger.valueOf(1L),
 323             BigInteger.valueOf(10L),
 324             BigInteger.valueOf(2147483646L),   // Integer.MAX_VALUE - 1
 325             BigInteger.valueOf(2147483647L),   // Integer.MAX_VALUE
 326             BigInteger.valueOf(2147483648L),   // Integer.MAX_VALUE + 1
 327 
 328             BigInteger.valueOf(MAX_UNSIGNED_INT - 1L),
 329             BigInteger.valueOf(MAX_UNSIGNED_INT),
 330 
 331             BigInteger.valueOf(Long.MAX_VALUE - 1L),
 332             BigInteger.valueOf(Long.MAX_VALUE),
 333             BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE),
 334 
 335             TWO.pow(64).subtract(BigInteger.ONE)
 336         };
 337 
 338         for(BigInteger dividend : inRange) {
 339             for(BigInteger divisor : inRange) {
 340                 long quotient;
 341                 BigInteger longQuotient;
 342 
 343                 long remainder;
 344                 BigInteger longRemainder;
 345 
 346                 if (divisor.equals(BigInteger.ZERO)) {
 347                     try {
 348                         quotient = Long.divideUnsigned(dividend.longValue(), divisor.longValue());
 349                         errors++;
 350                     } catch(ArithmeticException ea) {
 351                         ; // Expected
 352                     }
 353 
 354                     try {
 355                         remainder = Long.remainderUnsigned(dividend.longValue(), divisor.longValue());
 356                         errors++;
 357                     } catch(ArithmeticException ea) {
 358                         ; // Expected
 359                     }
 360                 } else {
 361                     quotient = Long.divideUnsigned(dividend.longValue(), divisor.longValue());
 362                     longQuotient = dividend.divide(divisor);
 363 
 364                     if (quotient != longQuotient.longValue()) {
 365                         errors++;
 366                         System.err.printf("Unexpected unsigned divide result %s on %s/%s%n",
 367                                           Long.toUnsignedString(quotient),
 368                                           Long.toUnsignedString(dividend.longValue()),
 369                                           Long.toUnsignedString(divisor.longValue()));
 370                     }
 371 
 372                     remainder = Long.remainderUnsigned(dividend.longValue(), divisor.longValue());
 373                     longRemainder = dividend.remainder(divisor);
 374 
 375                     if (remainder != longRemainder.longValue()) {
 376                         errors++;
 377                         System.err.printf("Unexpected unsigned remainder result %s on %s%%%s%n",
 378                                           Long.toUnsignedString(remainder),
 379                                           Long.toUnsignedString(dividend.longValue()),
 380                                           Long.toUnsignedString(divisor.longValue()));
 381                     }
 382                 }
 383             }
 384         }
 385 
 386         return errors;
 387     }
 388 }