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 }