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 package test.java.lang.Long; 31 32 // Android-added: support for wrapper to avoid d8 backporting of Integer.parseInt (b/215435867). 33 import java.lang.invoke.MethodHandle; 34 import java.lang.invoke.MethodHandles; 35 import java.lang.invoke.MethodType; 36 37 import java.math.*; 38 39 import org.testng.annotations.Test; 40 import org.testng.Assert; 41 42 public class Unsigned { 43 private static final BigInteger TWO = BigInteger.valueOf(2L); 44 45 @Test testRoundtrip()46 public void testRoundtrip() { 47 long[] data = {-1L, 0L, 1L}; 48 49 for(long datum : data) { 50 Assert.assertEquals( 51 Long.parseUnsignedLong(Long.toBinaryString(datum), 2), 52 datum, 53 "Bad binary roundtrip conversion of " + datum); 54 55 Assert.assertEquals( 56 Long.parseUnsignedLong(Long.toOctalString(datum), 8), 57 datum, 58 "Bad octal roundtrip conversion of " + datum); 59 60 Assert.assertEquals( 61 Long.parseUnsignedLong(Long.toHexString(datum), 16), 62 datum, 63 "Bad hex roundtrip conversion of " + datum); 64 } 65 } 66 67 @Test testByteToUnsignedLong()68 public void testByteToUnsignedLong() { 69 for(int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) { 70 byte datum = (byte) i; 71 long ui = Byte.toUnsignedLong(datum); 72 73 if ( (ui & (~0xffL)) != 0L || ((byte)ui != datum )) { 74 Assert.fail( 75 String.format("Bad conversion of byte %d to unsigned long %d%n", datum, ui)); 76 } 77 } 78 } 79 80 @Test testShortToUnsignedLong()81 public void testShortToUnsignedLong() { 82 for(int i = Short.MIN_VALUE; i <= Short.MAX_VALUE; i++) { 83 short datum = (short) i; 84 long ui = Short.toUnsignedLong(datum); 85 86 if ( (ui & (~0xffffL)) != 0L || ((short)ui != datum )) { 87 Assert.fail( 88 String.format("Bad conversion of short %d to unsigned long %d%n", datum, ui)); 89 } 90 } 91 } 92 93 @Test testUnsignedCompare()94 public void testUnsignedCompare() { 95 long[] data = { 96 0L, 97 1L, 98 2L, 99 3L, 100 0x00000000_80000000L, 101 0x00000000_FFFFFFFFL, 102 0x00000001_00000000L, 103 0x80000000_00000000L, 104 0x80000000_00000001L, 105 0x80000000_00000002L, 106 0x80000000_00000003L, 107 0x80000000_80000000L, 108 0xFFFFFFFF_FFFFFFFEL, 109 0xFFFFFFFF_FFFFFFFFL, 110 }; 111 112 for(long i : data) { 113 for(long j : data) { 114 long libraryResult = Long.compareUnsigned(i, j); 115 long libraryResultRev = Long.compareUnsigned(j, i); 116 long localResult = compUnsigned(i, j); 117 118 if (i == j) { 119 Assert.assertEquals( 120 libraryResult, 121 0, 122 String.format("Value 0x%x did not compare as " + 123 "an unsigned equal to itself; got %d%n", 124 i, libraryResult)); 125 } 126 127 Assert.assertEquals( 128 Long.signum(libraryResult), 129 Long.signum(localResult), 130 String.format("Unsigned compare of 0x%x to 0x%x%n:" + 131 "\texpected sign of %d, got %d%n", 132 i, j, localResult, libraryResult)); 133 134 Assert.assertEquals( 135 Long.signum(libraryResult), 136 -Long.signum(libraryResultRev), 137 String.format("signum(compareUnsigned(x, y)) != -signum(compareUnsigned(y,x))" + 138 " for \t0x%x and 0x%x, computed %d and %d%n", 139 i, j, libraryResult, libraryResultRev)); 140 } 141 } 142 } 143 compUnsigned(long x, long y)144 private static int compUnsigned(long x, long y) { 145 BigInteger big_x = toUnsignedBigInt(x); 146 BigInteger big_y = toUnsignedBigInt(y); 147 148 return big_x.compareTo(big_y); 149 } 150 toUnsignedBigInt(long x)151 private static BigInteger toUnsignedBigInt(long x) { 152 if (x >= 0) 153 return BigInteger.valueOf(x); 154 else { 155 int upper = (int)(((long)x) >> 32); 156 int lower = (int) x; 157 158 BigInteger bi = // (upper << 32) + lower 159 (BigInteger.valueOf(Integer.toUnsignedLong(upper))).shiftLeft(32). 160 add(BigInteger.valueOf(Integer.toUnsignedLong(lower))); 161 162 // System.out.printf("%n\t%d%n\t%s%n", x, bi.toString()); 163 return bi; 164 } 165 } 166 167 @Test testToStringUnsigned()168 public void testToStringUnsigned() { 169 long[] data = { 170 0L, 171 1L, 172 2L, 173 3L, 174 99999L, 175 100000L, 176 999999L, 177 100000L, 178 999999999L, 179 1000000000L, 180 0x1234_5678L, 181 0x8000_0000L, 182 0x8000_0001L, 183 0x8000_0002L, 184 0x8000_0003L, 185 0x8765_4321L, 186 0xFFFF_FFFEL, 187 0xFFFF_FFFFL, 188 189 // Long-range values 190 999_999_999_999L, 191 1_000_000_000_000L, 192 193 999_999_999_999_999_999L, 194 1_000_000_000_000_000_000L, 195 196 0xFFFF_FFFF_FFFF_FFFEL, 197 0xFFFF_FFFF_FFFF_FFFFL, 198 }; 199 200 for(int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { 201 for(long datum : data) { 202 String result1 = Long.toUnsignedString(datum, radix); 203 String result2 = toUnsignedBigInt(datum).toString(radix); 204 205 Assert.assertEquals( 206 result1, 207 result2, 208 String.format("Unexpected string difference converting 0x%x:" + 209 "\t%s %s%n", datum, result1, result2)); 210 211 if (radix == 10) { 212 String result3 = Long.toUnsignedString(datum); 213 Assert.assertEquals( 214 result2, 215 result3, 216 String.format("Unexpected string difference converting 0x%x:" + 217 "\t%s %s%n", datum, result3, result2)); 218 } 219 220 long parseResult = Long.parseUnsignedLong(result1, radix); 221 222 Assert.assertEquals( 223 parseResult, 224 datum, 225 String.format("Bad roundtrip conversion of %d in base %d" + 226 "\tconverting back ''%s'' resulted in %d%n", 227 datum, radix, result1, parseResult)); 228 } 229 } 230 } 231 232 @Test testParseUnsignedLong()233 public void testParseUnsignedLong() { 234 long maxUnsignedInt = Integer.toUnsignedLong(0xffff_ffff); 235 236 // Values include those between signed Long.MAX_VALUE and 237 // unsignted Long MAX_VALUE. 238 BigInteger[] inRange = { 239 BigInteger.valueOf(0L), 240 BigInteger.valueOf(1L), 241 BigInteger.valueOf(10L), 242 BigInteger.valueOf(2147483646L), // Integer.MAX_VALUE - 1 243 BigInteger.valueOf(2147483647L), // Integer.MAX_VALUE 244 BigInteger.valueOf(2147483648L), // Integer.MAX_VALUE + 1 245 246 BigInteger.valueOf(maxUnsignedInt - 1L), 247 BigInteger.valueOf(maxUnsignedInt), 248 249 BigInteger.valueOf(Long.MAX_VALUE - 1L), 250 BigInteger.valueOf(Long.MAX_VALUE), 251 BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE), 252 253 TWO.pow(64).subtract(BigInteger.ONE) 254 }; 255 256 for(BigInteger value : inRange) { 257 for(int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { 258 String bigString = value.toString(radix); 259 long longResult = Long.parseUnsignedLong(bigString, radix); 260 261 Assert.assertEquals( 262 toUnsignedBigInt(longResult), 263 value, 264 String.format("Bad roundtrip conversion of %d in base %d" + 265 "\tconverting back ''%s'' resulted in %d%n", 266 value, radix, bigString, longResult)); 267 268 // test offset based parse method 269 // Android-changed: avoid d8 backporting Long.parseUnsignedLong (b/215435867). 270 // longResult = Long.parseUnsignedLong("prefix" + bigString + "suffix", "prefix".length(), 271 // "prefix".length() + bigString.length(), radix); 272 longResult = Long_parseUnsignedLong("prefix" + bigString + "suffix", "prefix".length(), 273 "prefix".length() + bigString.length(), radix); 274 275 Assert.assertEquals( 276 toUnsignedBigInt(longResult), 277 value, 278 String.format("Bad roundtrip conversion of %d in base %d" + 279 "\tconverting back ''%s'' resulted in %d%n", 280 value, radix, bigString, longResult)); 281 } 282 } 283 284 String[] outOfRange = { 285 null, 286 "", 287 "-1", 288 TWO.pow(64).toString(), 289 }; 290 291 for(String s : outOfRange) { 292 try { 293 long result = Long.parseUnsignedLong(s); 294 Assert.fail(String.format("Unexpected got %d from an unsigned conversion of %s", 295 result, s)); 296 } catch(NumberFormatException nfe) { 297 ; // Correct result 298 } 299 } 300 301 // test case known at one time to fail 302 testUnsignedOverflow("1234567890abcdef1", 16, true); 303 304 // largest value with guard = 91 = 13*7; radix = 13 305 testUnsignedOverflow("196a78a44c3bba320c", 13, false); 306 307 // smallest value with guard = 92 = 23*2*2; radix = 23 308 testUnsignedOverflow("137060c6g1c1dg0", 23, false); 309 310 // guard in [92,98]: no overflow 311 312 // one less than smallest guard value to overflow: guard = 99 = 11*3*3, radix = 33 313 testUnsignedOverflow("b1w8p7j5q9r6f", 33, false); 314 315 // smallest guard value to overflow: guard = 99 = 11*3*3, radix = 33 316 testUnsignedOverflow("b1w8p7j5q9r6g", 33, true); 317 318 // test overflow of overflow 319 BigInteger maxUnsignedLong = 320 BigInteger.ONE.shiftLeft(64).subtract(BigInteger.ONE); 321 for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { 322 BigInteger quotient = maxUnsignedLong.divide(BigInteger.valueOf(radix)); 323 for (int addend = 2; addend <= radix; addend++) { 324 BigInteger b = quotient.multiply(BigInteger.valueOf(radix + addend)); 325 testUnsignedOverflow(b.toString(radix), radix, b.compareTo(maxUnsignedLong) > 0); 326 } 327 } 328 } 329 330 // test for missing or unexpected unsigned overflow exception testUnsignedOverflow(String s, int radix, boolean exception)331 private static void testUnsignedOverflow(String s, int radix, boolean exception) { 332 long result; 333 try { 334 result = Long.parseUnsignedLong(s, radix); 335 if (exception) { 336 Assert.fail(String.format("Unexpected result %d for Long.parseUnsignedLong(%s,%d)\n", 337 result, s, radix)); 338 } 339 } catch (NumberFormatException nfe) { 340 if (!exception) { 341 Assert.fail( 342 String.format("Unexpected exception %s for Long.parseUnsignedLong(%s,%d)\n", 343 nfe.toString(), s, radix)); 344 } 345 } 346 } 347 348 @Test testDivideAndRemainder()349 public void testDivideAndRemainder() { 350 long MAX_UNSIGNED_INT = Integer.toUnsignedLong(0xffff_ffff); 351 352 BigInteger[] inRange = { 353 BigInteger.valueOf(0L), 354 BigInteger.valueOf(1L), 355 BigInteger.valueOf(10L), 356 BigInteger.valueOf(2147483646L), // Integer.MAX_VALUE - 1 357 BigInteger.valueOf(2147483647L), // Integer.MAX_VALUE 358 BigInteger.valueOf(2147483648L), // Integer.MAX_VALUE + 1 359 360 BigInteger.valueOf(MAX_UNSIGNED_INT - 1L), 361 BigInteger.valueOf(MAX_UNSIGNED_INT), 362 363 BigInteger.valueOf(Long.MAX_VALUE - 1L), 364 BigInteger.valueOf(Long.MAX_VALUE), 365 BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE), 366 367 TWO.pow(64).subtract(BigInteger.ONE) 368 }; 369 370 for(BigInteger dividend : inRange) { 371 for(BigInteger divisor : inRange) { 372 long quotient; 373 BigInteger longQuotient; 374 375 long remainder; 376 BigInteger longRemainder; 377 378 if (divisor.equals(BigInteger.ZERO)) { 379 try { 380 quotient = Long.divideUnsigned(dividend.longValue(), divisor.longValue()); 381 Assert.fail("Unexpectedly did not throw while dividing by zero"); 382 } catch(ArithmeticException ea) { 383 ; // Expected 384 } 385 386 try { 387 remainder = Long.remainderUnsigned(dividend.longValue(), divisor.longValue()); 388 Assert.fail("Unexpectedly did not throw while dividing by zero"); 389 } catch(ArithmeticException ea) { 390 ; // Expected 391 } 392 } else { 393 quotient = Long.divideUnsigned(dividend.longValue(), divisor.longValue()); 394 longQuotient = dividend.divide(divisor); 395 396 Assert.assertEquals( 397 quotient, 398 longQuotient.longValue(), 399 String.format("Unexpected unsigned divide result %s on %s/%s%n", 400 Long.toUnsignedString(quotient), 401 Long.toUnsignedString(dividend.longValue()), 402 Long.toUnsignedString(divisor.longValue()))); 403 404 remainder = Long.remainderUnsigned(dividend.longValue(), divisor.longValue()); 405 longRemainder = dividend.remainder(divisor); 406 407 Assert.assertEquals( 408 remainder, 409 longRemainder.longValue(), 410 String.format("Unexpected unsigned remainder result %s on %s%%%s%n", 411 Long.toUnsignedString(remainder), 412 Long.toUnsignedString(dividend.longValue()), 413 Long.toUnsignedString(divisor.longValue()))); 414 } 415 } 416 } 417 } 418 419 // Android-added: wrapper to avoid d8 backporting of Long.parseUnsignedLong(JIII) (b/215435867). Long_parseUnsignedLong(String val, int start, int end, int radix)420 private static long Long_parseUnsignedLong(String val, int start, int end, int radix) { 421 try { 422 MethodType parseType = MethodType.methodType(long.class, 423 CharSequence.class, 424 int.class, 425 int.class, 426 int.class); 427 MethodHandle parse = 428 MethodHandles.lookup().findStatic(Long.class, "parseUnsignedLong", parseType); 429 return (long) parse.invokeExact((CharSequence) val, start, end, radix); 430 } catch (IndexOutOfBoundsException | NullPointerException | NumberFormatException e) { 431 // Expected exceptions from the target method during the tests here. 432 throw e; 433 } catch (Throwable t) { 434 // Everything else. 435 throw new RuntimeException(t); 436 } 437 } 438 } 439