• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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