1 /* 2 * Copyright (c) 1998, 2015, 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 * @library .. 27 * @bug 4181191 4161971 4227146 4194389 4823171 4624738 4812225 4837946 4026465 8074460 28 * @summary tests methods in BigInteger (use -Dseed=X to set PRNG seed) 29 * @run main/timeout=400 BigIntegerTest 30 * @author madbot 31 */ 32 33 import java.io.File; 34 import java.io.FileInputStream; 35 import java.io.FileOutputStream; 36 import java.io.ObjectInputStream; 37 import java.io.ObjectOutputStream; 38 import java.math.BigInteger; 39 40 /** 41 * This is a simple test class created to ensure that the results 42 * generated by BigInteger adhere to certain identities. Passing 43 * this test is a strong assurance that the BigInteger operations 44 * are working correctly. 45 * 46 * Four arguments may be specified which give the number of 47 * decimal digits you desire in the four batches of test numbers. 48 * 49 * The tests are performed on arrays of random numbers which are 50 * generated by a Random class as well as special cases which 51 * throw in boundary numbers such as 0, 1, maximum sized, etc. 52 * 53 */ 54 public class BigIntegerTest { 55 // 56 // Bit large number thresholds based on the int thresholds 57 // defined in BigInteger itself: 58 // 59 // KARATSUBA_THRESHOLD = 80 ints = 2560 bits 60 // TOOM_COOK_THRESHOLD = 240 ints = 7680 bits 61 // KARATSUBA_SQUARE_THRESHOLD = 128 ints = 4096 bits 62 // TOOM_COOK_SQUARE_THRESHOLD = 216 ints = 6912 bits 63 // 64 // SCHOENHAGE_BASE_CONVERSION_THRESHOLD = 20 ints = 640 bits 65 // 66 // BURNIKEL_ZIEGLER_THRESHOLD = 80 ints = 2560 bits 67 // 68 static final int BITS_KARATSUBA = 2560; 69 static final int BITS_TOOM_COOK = 7680; 70 static final int BITS_KARATSUBA_SQUARE = 4096; 71 static final int BITS_TOOM_COOK_SQUARE = 6912; 72 static final int BITS_SCHOENHAGE_BASE = 640; 73 static final int BITS_BURNIKEL_ZIEGLER = 2560; 74 static final int BITS_BURNIKEL_ZIEGLER_OFFSET = 1280; 75 76 static final int ORDER_SMALL = 60; 77 static final int ORDER_MEDIUM = 100; 78 // #bits for testing Karatsuba 79 static final int ORDER_KARATSUBA = 2760; 80 // #bits for testing Toom-Cook and Burnikel-Ziegler 81 static final int ORDER_TOOM_COOK = 8000; 82 // #bits for testing Karatsuba squaring 83 static final int ORDER_KARATSUBA_SQUARE = 4200; 84 // #bits for testing Toom-Cook squaring 85 static final int ORDER_TOOM_COOK_SQUARE = 7000; 86 87 static final int SIZE = 1000; // numbers per batch 88 89 private static RandomSeed rndSeed = new RandomSeed(false); 90 91 static boolean failure = false; 92 93 public static void constructor() { 94 int failCount = 0; 95 96 // --- guard condition tests for array indexing --- 97 98 int arrayLength = 23; 99 int halfLength = arrayLength/2; 100 byte[] array = new byte[arrayLength]; 101 rndSeed.getRandom().nextBytes(array); 102 103 int[][] offLen = new int[][] { // offset, length, num exceptions 104 {-1, arrayLength, 1}, // negative offset 105 {0, arrayLength, 0}, // OK 106 {1, arrayLength, 1}, // length overflow 107 {arrayLength - 1, 1, 0}, // OK 108 {arrayLength, 1, 1}, // offset overflow 109 {0, -1, 1}, // negative length 110 {halfLength, arrayLength - halfLength + 1, 1} // length overflow 111 }; 112 113 // two's complement 114 for (int[] ol : offLen) { 115 int numExceptions = 0; 116 try { 117 BigInteger bi = new BigInteger(array, ol[0], ol[1]); 118 } catch (IndexOutOfBoundsException e) { 119 numExceptions++; 120 } 121 if (numExceptions != ol[2]) { 122 System.err.println("IndexOutOfBoundsException did not occur for " 123 + " two's complement constructor with parameters offset " 124 + ol[0] + " and length " + ol[1]); 125 failCount++; 126 } 127 } 128 129 // sign-magnitude 130 for (int[] ol : offLen) { 131 int numExceptions = 0; 132 try { 133 BigInteger bi = new BigInteger(1, array, ol[0], ol[1]); 134 } catch (IndexOutOfBoundsException e) { 135 numExceptions++; 136 } 137 if (numExceptions != ol[2]) { 138 System.err.println("IndexOutOfBoundsException did not occur for " 139 + " sign-magnitude constructor with parameters offset " 140 + ol[0] + " and length " + ol[1]); 141 failCount++; 142 } 143 } 144 145 // --- tests for creation of zero-valued BigIntegers --- 146 147 byte[] magZeroLength = new byte[0]; 148 for (int signum = -1; signum <= 1; signum++) { 149 BigInteger bi = new BigInteger(signum, magZeroLength); 150 if (bi.compareTo(BigInteger.ZERO) != 0) { 151 System.err.println("A: Zero length BigInteger != 0 for signum " + signum); 152 failCount++; 153 } 154 } 155 156 for (int signum = -1; signum <= 1; signum++) { 157 BigInteger bi = new BigInteger(signum, magZeroLength, 0, 0); 158 if (bi.compareTo(BigInteger.ZERO) != 0) { 159 System.err.println("B: Zero length BigInteger != 0 for signum " + signum); 160 failCount++; 161 } 162 } 163 164 byte[] magNonZeroLength = new byte[42]; 165 rndSeed.getRandom().nextBytes(magNonZeroLength); 166 for (int signum = -1; signum <= 1; signum++) { 167 BigInteger bi = new BigInteger(signum, magNonZeroLength, 0, 0); 168 if (bi.compareTo(BigInteger.ZERO) != 0) { 169 System.err.println("C: Zero length BigInteger != 0 for signum " + signum); 170 failCount++; 171 } 172 } 173 174 // --- tests for accurate creation of non-zero BigIntegers --- 175 176 for (int i = 0; i < SIZE; i++) { 177 // create reference value via a different code path from those tested 178 BigInteger reference = new BigInteger(2 + rndSeed.getRandom().nextInt(336), 4, rndSeed.getRandom()); 179 180 byte[] refArray = reference.toByteArray(); 181 int refLen = refArray.length; 182 int factor = rndSeed.getRandom().nextInt(5); 183 int objLen = refArray.length + factor*rndSeed.getRandom().nextInt(refArray.length) + 1; 184 int offset = rndSeed.getRandom().nextInt(objLen - refLen); 185 byte[] objArray = new byte[objLen]; 186 System.arraycopy(refArray, 0, objArray, offset, refLen); 187 188 BigInteger twosComp = new BigInteger(objArray, offset, refLen); 189 if (twosComp.compareTo(reference) != 0) { 190 System.err.println("Two's-complement BigInteger not equal for offset " + 191 offset + " and length " + refLen); 192 failCount++; 193 } 194 195 boolean isNegative = rndSeed.getRandom().nextBoolean(); 196 BigInteger signMag = new BigInteger(isNegative ? -1 : 1, objArray, offset, refLen); 197 if (signMag.compareTo(isNegative ? reference.negate() : reference) != 0) { 198 System.err.println("Sign-magnitude BigInteger not equal for offset " + 199 offset + " and length " + refLen); 200 failCount++; 201 } 202 } 203 204 report("Constructor", failCount); 205 } 206 207 public static void pow(int order) { 208 int failCount1 = 0; 209 210 for (int i=0; i<SIZE; i++) { 211 // Test identity x^power == x*x*x ... *x 212 int power = rndSeed.getRandom().nextInt(6) + 2; 213 BigInteger x = fetchNumber(order); 214 BigInteger y = x.pow(power); 215 BigInteger z = x; 216 217 for (int j=1; j<power; j++) 218 z = z.multiply(x); 219 220 if (!y.equals(z)) 221 failCount1++; 222 } 223 report("pow for " + order + " bits", failCount1); 224 } 225 226 public static void square(int order) { 227 int failCount1 = 0; 228 229 for (int i=0; i<SIZE; i++) { 230 // Test identity x^2 == x*x 231 BigInteger x = fetchNumber(order); 232 BigInteger xx = x.multiply(x); 233 BigInteger x2 = x.pow(2); 234 235 if (!x2.equals(xx)) 236 failCount1++; 237 } 238 report("square for " + order + " bits", failCount1); 239 } 240 241 public static void arithmetic(int order) { 242 int failCount = 0; 243 244 for (int i=0; i<SIZE; i++) { 245 BigInteger x = fetchNumber(order); 246 while(x.compareTo(BigInteger.ZERO) != 1) 247 x = fetchNumber(order); 248 BigInteger y = fetchNumber(order/2); 249 while(x.compareTo(y) == -1) 250 y = fetchNumber(order/2); 251 if (y.equals(BigInteger.ZERO)) 252 y = y.add(BigInteger.ONE); 253 254 // Test identity ((x/y))*y + x%y - x == 0 255 // using separate divide() and remainder() 256 BigInteger baz = x.divide(y); 257 baz = baz.multiply(y); 258 baz = baz.add(x.remainder(y)); 259 baz = baz.subtract(x); 260 if (!baz.equals(BigInteger.ZERO)) 261 failCount++; 262 } 263 report("Arithmetic I for " + order + " bits", failCount); 264 265 failCount = 0; 266 for (int i=0; i<100; i++) { 267 BigInteger x = fetchNumber(order); 268 while(x.compareTo(BigInteger.ZERO) != 1) 269 x = fetchNumber(order); 270 BigInteger y = fetchNumber(order/2); 271 while(x.compareTo(y) == -1) 272 y = fetchNumber(order/2); 273 if (y.equals(BigInteger.ZERO)) 274 y = y.add(BigInteger.ONE); 275 276 // Test identity ((x/y))*y + x%y - x == 0 277 // using divideAndRemainder() 278 BigInteger baz[] = x.divideAndRemainder(y); 279 baz[0] = baz[0].multiply(y); 280 baz[0] = baz[0].add(baz[1]); 281 baz[0] = baz[0].subtract(x); 282 if (!baz[0].equals(BigInteger.ZERO)) 283 failCount++; 284 } 285 report("Arithmetic II for " + order + " bits", failCount); 286 } 287 288 /** 289 * Sanity test for Karatsuba and 3-way Toom-Cook multiplication. 290 * For each of the Karatsuba and 3-way Toom-Cook multiplication thresholds, 291 * construct two factors each with a mag array one element shorter than the 292 * threshold, and with the most significant bit set and the rest of the bits 293 * random. Each of these numbers will therefore be below the threshold but 294 * if shifted left be above the threshold. Call the numbers 'u' and 'v' and 295 * define random shifts 'a' and 'b' in the range [1,32]. Then we have the 296 * identity 297 * <pre> 298 * (u << a)*(v << b) = (u*v) << (a + b) 299 * </pre> 300 * For Karatsuba multiplication, the right hand expression will be evaluated 301 * using the standard naive algorithm, and the left hand expression using 302 * the Karatsuba algorithm. For 3-way Toom-Cook multiplication, the right 303 * hand expression will be evaluated using Karatsuba multiplication, and the 304 * left hand expression using 3-way Toom-Cook multiplication. 305 */ 306 public static void multiplyLarge() { 307 int failCount = 0; 308 309 BigInteger base = BigInteger.ONE.shiftLeft(BITS_KARATSUBA - 32 - 1); 310 for (int i=0; i<SIZE; i++) { 311 BigInteger x = fetchNumber(BITS_KARATSUBA - 32 - 1); 312 BigInteger u = base.add(x); 313 int a = 1 + rndSeed.getRandom().nextInt(31); 314 BigInteger w = u.shiftLeft(a); 315 316 BigInteger y = fetchNumber(BITS_KARATSUBA - 32 - 1); 317 BigInteger v = base.add(y); 318 int b = 1 + rndSeed.getRandom().nextInt(32); 319 BigInteger z = v.shiftLeft(b); 320 321 BigInteger multiplyResult = u.multiply(v).shiftLeft(a + b); 322 BigInteger karatsubaMultiplyResult = w.multiply(z); 323 324 if (!multiplyResult.equals(karatsubaMultiplyResult)) { 325 failCount++; 326 } 327 } 328 329 report("multiplyLarge Karatsuba", failCount); 330 331 failCount = 0; 332 base = base.shiftLeft(BITS_TOOM_COOK - BITS_KARATSUBA); 333 for (int i=0; i<SIZE; i++) { 334 BigInteger x = fetchNumber(BITS_TOOM_COOK - 32 - 1); 335 BigInteger u = base.add(x); 336 BigInteger u2 = u.shiftLeft(1); 337 BigInteger y = fetchNumber(BITS_TOOM_COOK - 32 - 1); 338 BigInteger v = base.add(y); 339 BigInteger v2 = v.shiftLeft(1); 340 341 BigInteger multiplyResult = u.multiply(v).shiftLeft(2); 342 BigInteger toomCookMultiplyResult = u2.multiply(v2); 343 344 if (!multiplyResult.equals(toomCookMultiplyResult)) { 345 failCount++; 346 } 347 } 348 349 report("multiplyLarge Toom-Cook", failCount); 350 } 351 352 /** 353 * Sanity test for Karatsuba and 3-way Toom-Cook squaring. 354 * This test is analogous to {@link AbstractMethodError#multiplyLarge} 355 * with both factors being equal. The squaring methods will not be tested 356 * unless the <code>bigInteger.multiply(bigInteger)</code> tests whether 357 * the parameter is the same instance on which the method is being invoked 358 * and calls <code>square()</code> accordingly. 359 */ 360 public static void squareLarge() { 361 int failCount = 0; 362 363 BigInteger base = BigInteger.ONE.shiftLeft(BITS_KARATSUBA_SQUARE - 32 - 1); 364 for (int i=0; i<SIZE; i++) { 365 BigInteger x = fetchNumber(BITS_KARATSUBA_SQUARE - 32 - 1); 366 BigInteger u = base.add(x); 367 int a = 1 + rndSeed.getRandom().nextInt(31); 368 BigInteger w = u.shiftLeft(a); 369 370 BigInteger squareResult = u.multiply(u).shiftLeft(2*a); 371 BigInteger karatsubaSquareResult = w.multiply(w); 372 373 if (!squareResult.equals(karatsubaSquareResult)) { 374 failCount++; 375 } 376 } 377 378 report("squareLarge Karatsuba", failCount); 379 380 failCount = 0; 381 base = base.shiftLeft(BITS_TOOM_COOK_SQUARE - BITS_KARATSUBA_SQUARE); 382 for (int i=0; i<SIZE; i++) { 383 BigInteger x = fetchNumber(BITS_TOOM_COOK_SQUARE - 32 - 1); 384 BigInteger u = base.add(x); 385 int a = 1 + rndSeed.getRandom().nextInt(31); 386 BigInteger w = u.shiftLeft(a); 387 388 BigInteger squareResult = u.multiply(u).shiftLeft(2*a); 389 BigInteger toomCookSquareResult = w.multiply(w); 390 391 if (!squareResult.equals(toomCookSquareResult)) { 392 failCount++; 393 } 394 } 395 396 report("squareLarge Toom-Cook", failCount); 397 } 398 399 /** 400 * Sanity test for Burnikel-Ziegler division. The Burnikel-Ziegler division 401 * algorithm is used when each of the dividend and the divisor has at least 402 * a specified number of ints in its representation. This test is based on 403 * the observation that if {@code w = u*pow(2,a)} and {@code z = v*pow(2,b)} 404 * where {@code abs(u) > abs(v)} and {@code a > b && b > 0}, then if 405 * {@code w/z = q1*z + r1} and {@code u/v = q2*v + r2}, then 406 * {@code q1 = q2*pow(2,a-b)} and {@code r1 = r2*pow(2,b)}. The test 407 * ensures that {@code v} is just under the B-Z threshold, that {@code z} is 408 * over the threshold and {@code w} is much larger than {@code z}. This 409 * implies that {@code u/v} uses the standard division algorithm and 410 * {@code w/z} uses the B-Z algorithm. The results of the two algorithms 411 * are then compared using the observation described in the foregoing and 412 * if they are not equal a failure is logged. 413 */ 414 public static void divideLarge() { 415 int failCount = 0; 416 417 BigInteger base = BigInteger.ONE.shiftLeft(BITS_BURNIKEL_ZIEGLER + BITS_BURNIKEL_ZIEGLER_OFFSET - 33); 418 for (int i=0; i<SIZE; i++) { 419 BigInteger addend = new BigInteger(BITS_BURNIKEL_ZIEGLER + BITS_BURNIKEL_ZIEGLER_OFFSET - 34, rndSeed.getRandom()); 420 BigInteger v = base.add(addend); 421 422 BigInteger u = v.multiply(BigInteger.valueOf(2 + rndSeed.getRandom().nextInt(Short.MAX_VALUE - 1))); 423 424 if(rndSeed.getRandom().nextBoolean()) { 425 u = u.negate(); 426 } 427 if(rndSeed.getRandom().nextBoolean()) { 428 v = v.negate(); 429 } 430 431 int a = BITS_BURNIKEL_ZIEGLER_OFFSET + rndSeed.getRandom().nextInt(16); 432 int b = 1 + rndSeed.getRandom().nextInt(16); 433 BigInteger w = u.multiply(BigInteger.ONE.shiftLeft(a)); 434 BigInteger z = v.multiply(BigInteger.ONE.shiftLeft(b)); 435 436 BigInteger[] divideResult = u.divideAndRemainder(v); 437 divideResult[0] = divideResult[0].multiply(BigInteger.ONE.shiftLeft(a - b)); 438 divideResult[1] = divideResult[1].multiply(BigInteger.ONE.shiftLeft(b)); 439 BigInteger[] bzResult = w.divideAndRemainder(z); 440 441 if (divideResult[0].compareTo(bzResult[0]) != 0 || 442 divideResult[1].compareTo(bzResult[1]) != 0) { 443 failCount++; 444 } 445 } 446 447 report("divideLarge", failCount); 448 } 449 450 public static void bitCount() { 451 int failCount = 0; 452 453 for (int i=0; i<SIZE*10; i++) { 454 int x = rndSeed.getRandom().nextInt(); 455 BigInteger bigX = BigInteger.valueOf((long)x); 456 int bit = (x < 0 ? 0 : 1); 457 int tmp = x, bitCount = 0; 458 for (int j=0; j<32; j++) { 459 bitCount += ((tmp & 1) == bit ? 1 : 0); 460 tmp >>= 1; 461 } 462 463 if (bigX.bitCount() != bitCount) { 464 //System.err.println(x+": "+bitCount+", "+bigX.bitCount()); 465 failCount++; 466 } 467 } 468 report("Bit Count", failCount); 469 } 470 471 public static void bitLength() { 472 int failCount = 0; 473 474 for (int i=0; i<SIZE*10; i++) { 475 int x = rndSeed.getRandom().nextInt(); 476 BigInteger bigX = BigInteger.valueOf((long)x); 477 int signBit = (x < 0 ? 0x80000000 : 0); 478 int tmp = x, bitLength, j; 479 for (j=0; j<32 && (tmp & 0x80000000)==signBit; j++) 480 tmp <<= 1; 481 bitLength = 32 - j; 482 483 if (bigX.bitLength() != bitLength) { 484 //System.err.println(x+": "+bitLength+", "+bigX.bitLength()); 485 failCount++; 486 } 487 } 488 489 report("BitLength", failCount); 490 } 491 492 public static void bitOps(int order) { 493 int failCount1 = 0, failCount2 = 0, failCount3 = 0; 494 495 for (int i=0; i<SIZE*5; i++) { 496 BigInteger x = fetchNumber(order); 497 BigInteger y; 498 499 // Test setBit and clearBit (and testBit) 500 if (x.signum() < 0) { 501 y = BigInteger.valueOf(-1); 502 for (int j=0; j<x.bitLength(); j++) 503 if (!x.testBit(j)) 504 y = y.clearBit(j); 505 } else { 506 y = BigInteger.ZERO; 507 for (int j=0; j<x.bitLength(); j++) 508 if (x.testBit(j)) 509 y = y.setBit(j); 510 } 511 if (!x.equals(y)) 512 failCount1++; 513 514 // Test flipBit (and testBit) 515 y = BigInteger.valueOf(x.signum()<0 ? -1 : 0); 516 for (int j=0; j<x.bitLength(); j++) 517 if (x.signum()<0 ^ x.testBit(j)) 518 y = y.flipBit(j); 519 if (!x.equals(y)) 520 failCount2++; 521 } 522 report("clearBit/testBit for " + order + " bits", failCount1); 523 report("flipBit/testBit for " + order + " bits", failCount2); 524 525 for (int i=0; i<SIZE*5; i++) { 526 BigInteger x = fetchNumber(order); 527 528 // Test getLowestSetBit() 529 int k = x.getLowestSetBit(); 530 if (x.signum() == 0) { 531 if (k != -1) 532 failCount3++; 533 } else { 534 BigInteger z = x.and(x.negate()); 535 int j; 536 for (j=0; j<z.bitLength() && !z.testBit(j); j++) 537 ; 538 if (k != j) 539 failCount3++; 540 } 541 } 542 report("getLowestSetBit for " + order + " bits", failCount3); 543 } 544 545 public static void bitwise(int order) { 546 547 // Test identity x^y == x|y &~ x&y 548 int failCount = 0; 549 for (int i=0; i<SIZE; i++) { 550 BigInteger x = fetchNumber(order); 551 BigInteger y = fetchNumber(order); 552 BigInteger z = x.xor(y); 553 BigInteger w = x.or(y).andNot(x.and(y)); 554 if (!z.equals(w)) 555 failCount++; 556 } 557 report("Logic (^ | & ~) for " + order + " bits", failCount); 558 559 // Test identity x &~ y == ~(~x | y) 560 failCount = 0; 561 for (int i=0; i<SIZE; i++) { 562 BigInteger x = fetchNumber(order); 563 BigInteger y = fetchNumber(order); 564 BigInteger z = x.andNot(y); 565 BigInteger w = x.not().or(y).not(); 566 if (!z.equals(w)) 567 failCount++; 568 } 569 report("Logic (&~ | ~) for " + order + " bits", failCount); 570 } 571 572 public static void shift(int order) { 573 int failCount1 = 0; 574 int failCount2 = 0; 575 int failCount3 = 0; 576 577 for (int i=0; i<100; i++) { 578 BigInteger x = fetchNumber(order); 579 int n = Math.abs(rndSeed.getRandom().nextInt()%200); 580 581 if (!x.shiftLeft(n).equals 582 (x.multiply(BigInteger.valueOf(2L).pow(n)))) 583 failCount1++; 584 585 BigInteger y[] =x.divideAndRemainder(BigInteger.valueOf(2L).pow(n)); 586 BigInteger z = (x.signum()<0 && y[1].signum()!=0 587 ? y[0].subtract(BigInteger.ONE) 588 : y[0]); 589 590 BigInteger b = x.shiftRight(n); 591 592 if (!b.equals(z)) { 593 System.err.println("Input is "+x.toString(2)); 594 System.err.println("shift is "+n); 595 596 System.err.println("Divided "+z.toString(2)); 597 System.err.println("Shifted is "+b.toString(2)); 598 if (b.toString().equals(z.toString())) 599 System.err.println("Houston, we have a problem."); 600 failCount2++; 601 } 602 603 if (!x.shiftLeft(n).shiftRight(n).equals(x)) 604 failCount3++; 605 } 606 report("baz shiftLeft for " + order + " bits", failCount1); 607 report("baz shiftRight for " + order + " bits", failCount2); 608 report("baz shiftLeft/Right for " + order + " bits", failCount3); 609 } 610 611 public static void divideAndRemainder(int order) { 612 int failCount1 = 0; 613 614 for (int i=0; i<SIZE; i++) { 615 BigInteger x = fetchNumber(order).abs(); 616 while(x.compareTo(BigInteger.valueOf(3L)) != 1) 617 x = fetchNumber(order).abs(); 618 BigInteger z = x.divide(BigInteger.valueOf(2L)); 619 BigInteger y[] = x.divideAndRemainder(x); 620 if (!y[0].equals(BigInteger.ONE)) { 621 failCount1++; 622 System.err.println("fail1 x :"+x); 623 System.err.println(" y :"+y); 624 } 625 else if (!y[1].equals(BigInteger.ZERO)) { 626 failCount1++; 627 System.err.println("fail2 x :"+x); 628 System.err.println(" y :"+y); 629 } 630 631 y = x.divideAndRemainder(z); 632 if (!y[0].equals(BigInteger.valueOf(2))) { 633 failCount1++; 634 System.err.println("fail3 x :"+x); 635 System.err.println(" y :"+y); 636 } 637 } 638 report("divideAndRemainder for " + order + " bits", failCount1); 639 } 640 641 public static void stringConv() { 642 int failCount = 0; 643 644 // Generic string conversion. 645 for (int i=0; i<100; i++) { 646 byte xBytes[] = new byte[Math.abs(rndSeed.getRandom().nextInt())%100+1]; 647 rndSeed.getRandom().nextBytes(xBytes); 648 BigInteger x = new BigInteger(xBytes); 649 650 for (int radix=Character.MIN_RADIX; radix < Character.MAX_RADIX; radix++) { 651 String result = x.toString(radix); 652 BigInteger test = new BigInteger(result, radix); 653 if (!test.equals(x)) { 654 failCount++; 655 System.err.println("BigInteger toString: "+x); 656 System.err.println("Test: "+test); 657 System.err.println(radix); 658 } 659 } 660 } 661 662 // String conversion straddling the Schoenhage algorithm crossover 663 // threshold, and at twice and four times the threshold. 664 for (int k = 0; k <= 2; k++) { 665 int factor = 1 << k; 666 int upper = factor * BITS_SCHOENHAGE_BASE + 33; 667 int lower = upper - 35; 668 669 for (int bits = upper; bits >= lower; bits--) { 670 for (int i = 0; i < 50; i++) { 671 BigInteger x = BigInteger.ONE.shiftLeft(bits - 1).or(new BigInteger(bits - 2, rndSeed.getRandom())); 672 673 for (int radix = Character.MIN_RADIX; radix < Character.MAX_RADIX; radix++) { 674 String result = x.toString(radix); 675 BigInteger test = new BigInteger(result, radix); 676 if (!test.equals(x)) { 677 failCount++; 678 System.err.println("BigInteger toString: " + x); 679 System.err.println("Test: " + test); 680 System.err.println(radix); 681 } 682 } 683 } 684 } 685 } 686 687 report("String Conversion", failCount); 688 } 689 690 public static void byteArrayConv(int order) { 691 int failCount = 0; 692 693 for (int i=0; i<SIZE; i++) { 694 BigInteger x = fetchNumber(order); 695 while (x.equals(BigInteger.ZERO)) 696 x = fetchNumber(order); 697 BigInteger y = new BigInteger(x.toByteArray()); 698 if (!x.equals(y)) { 699 failCount++; 700 System.err.println("orig is "+x); 701 System.err.println("new is "+y); 702 } 703 } 704 report("Array Conversion for " + order + " bits", failCount); 705 } 706 707 public static void modInv(int order) { 708 int failCount = 0, successCount = 0, nonInvCount = 0; 709 710 for (int i=0; i<SIZE; i++) { 711 BigInteger x = fetchNumber(order); 712 while(x.equals(BigInteger.ZERO)) 713 x = fetchNumber(order); 714 BigInteger m = fetchNumber(order).abs(); 715 while(m.compareTo(BigInteger.ONE) != 1) 716 m = fetchNumber(order).abs(); 717 718 try { 719 BigInteger inv = x.modInverse(m); 720 BigInteger prod = inv.multiply(x).remainder(m); 721 722 if (prod.signum() == -1) 723 prod = prod.add(m); 724 725 if (prod.equals(BigInteger.ONE)) 726 successCount++; 727 else 728 failCount++; 729 } catch(ArithmeticException e) { 730 nonInvCount++; 731 } 732 } 733 report("Modular Inverse for " + order + " bits", failCount); 734 } 735 736 public static void modExp(int order1, int order2) { 737 int failCount = 0; 738 739 for (int i=0; i<SIZE/10; i++) { 740 BigInteger m = fetchNumber(order1).abs(); 741 while(m.compareTo(BigInteger.ONE) != 1) 742 m = fetchNumber(order1).abs(); 743 BigInteger base = fetchNumber(order2); 744 BigInteger exp = fetchNumber(8).abs(); 745 746 BigInteger z = base.modPow(exp, m); 747 BigInteger w = base.pow(exp.intValue()).mod(m); 748 if (!z.equals(w)) { 749 System.err.println("z is "+z); 750 System.err.println("w is "+w); 751 System.err.println("mod is "+m); 752 System.err.println("base is "+base); 753 System.err.println("exp is "+exp); 754 failCount++; 755 } 756 } 757 report("Exponentiation I for " + order1 + " and " + 758 order2 + " bits", failCount); 759 } 760 761 // This test is based on Fermat's theorem 762 // which is not ideal because base must not be multiple of modulus 763 // and modulus must be a prime or pseudoprime (Carmichael number) 764 public static void modExp2(int order) { 765 int failCount = 0; 766 767 for (int i=0; i<10; i++) { 768 BigInteger m = new BigInteger(100, 5, rndSeed.getRandom()); 769 while(m.compareTo(BigInteger.ONE) != 1) 770 m = new BigInteger(100, 5, rndSeed.getRandom()); 771 BigInteger exp = m.subtract(BigInteger.ONE); 772 BigInteger base = fetchNumber(order).abs(); 773 while(base.compareTo(m) != -1) 774 base = fetchNumber(order).abs(); 775 while(base.equals(BigInteger.ZERO)) 776 base = fetchNumber(order).abs(); 777 778 BigInteger one = base.modPow(exp, m); 779 if (!one.equals(BigInteger.ONE)) { 780 System.err.println("m is "+m); 781 System.err.println("base is "+base); 782 System.err.println("exp is "+exp); 783 failCount++; 784 } 785 } 786 report("Exponentiation II for " + order + " bits", failCount); 787 } 788 789 private static final int[] mersenne_powers = { 790 521, 607, 1279, 2203, 2281, 3217, 4253, 4423, 9689, 9941, 11213, 19937, 791 21701, 23209, 44497, 86243, 110503, 132049, 216091, 756839, 859433, 792 1257787, 1398269, 2976221, 3021377, 6972593, 13466917 }; 793 794 private static final long[] carmichaels = { 795 561,1105,1729,2465,2821,6601,8911,10585,15841,29341,41041,46657,52633, 796 62745,63973,75361,101101,115921,126217,162401,172081,188461,252601, 797 278545,294409,314821,334153,340561,399001,410041,449065,488881,512461, 798 225593397919L }; 799 800 // Note: testing the larger ones takes too long. 801 private static final int NUM_MERSENNES_TO_TEST = 7; 802 // Note: this constant used for computed Carmichaels, not the array above 803 private static final int NUM_CARMICHAELS_TO_TEST = 5; 804 805 private static final String[] customer_primes = { 806 "120000000000000000000000000000000019", 807 "633825300114114700748351603131", 808 "1461501637330902918203684832716283019651637554291", 809 "779626057591079617852292862756047675913380626199", 810 "857591696176672809403750477631580323575362410491", 811 "910409242326391377348778281801166102059139832131", 812 "929857869954035706722619989283358182285540127919", 813 "961301750640481375785983980066592002055764391999", 814 "1267617700951005189537696547196156120148404630231", 815 "1326015641149969955786344600146607663033642528339" }; 816 817 private static final BigInteger ZERO = BigInteger.ZERO; 818 private static final BigInteger ONE = BigInteger.ONE; 819 private static final BigInteger TWO = new BigInteger("2"); 820 private static final BigInteger SIX = new BigInteger("6"); 821 private static final BigInteger TWELVE = new BigInteger("12"); 822 private static final BigInteger EIGHTEEN = new BigInteger("18"); 823 824 public static void prime() { 825 BigInteger p1, p2, c1; 826 int failCount = 0; 827 828 // Test consistency 829 for(int i=0; i<10; i++) { 830 p1 = BigInteger.probablePrime(100, rndSeed.getRandom()); 831 if (!p1.isProbablePrime(100)) { 832 System.err.println("Consistency "+p1.toString(16)); 833 failCount++; 834 } 835 } 836 837 // Test some known Mersenne primes (2^n)-1 838 // The array holds the exponents, not the numbers being tested 839 for (int i=0; i<NUM_MERSENNES_TO_TEST; i++) { 840 p1 = new BigInteger("2"); 841 p1 = p1.pow(mersenne_powers[i]); 842 p1 = p1.subtract(BigInteger.ONE); 843 if (!p1.isProbablePrime(100)) { 844 System.err.println("Mersenne prime "+i+ " failed."); 845 failCount++; 846 } 847 } 848 849 // Test some primes reported by customers as failing in the past 850 for (int i=0; i<customer_primes.length; i++) { 851 p1 = new BigInteger(customer_primes[i]); 852 if (!p1.isProbablePrime(100)) { 853 System.err.println("Customer prime "+i+ " failed."); 854 failCount++; 855 } 856 } 857 858 // Test some known Carmichael numbers. 859 for (int i=0; i<carmichaels.length; i++) { 860 c1 = BigInteger.valueOf(carmichaels[i]); 861 if(c1.isProbablePrime(100)) { 862 System.err.println("Carmichael "+i+ " reported as prime."); 863 failCount++; 864 } 865 } 866 867 // Test some computed Carmichael numbers. 868 // Numbers of the form (6k+1)(12k+1)(18k+1) are Carmichael numbers if 869 // each of the factors is prime 870 int found = 0; 871 BigInteger f1 = new BigInteger(40, 100, rndSeed.getRandom()); 872 while (found < NUM_CARMICHAELS_TO_TEST) { 873 BigInteger k = null; 874 BigInteger f2, f3; 875 f1 = f1.nextProbablePrime(); 876 BigInteger[] result = f1.subtract(ONE).divideAndRemainder(SIX); 877 if (result[1].equals(ZERO)) { 878 k = result[0]; 879 f2 = k.multiply(TWELVE).add(ONE); 880 if (f2.isProbablePrime(100)) { 881 f3 = k.multiply(EIGHTEEN).add(ONE); 882 if (f3.isProbablePrime(100)) { 883 c1 = f1.multiply(f2).multiply(f3); 884 if (c1.isProbablePrime(100)) { 885 System.err.println("Computed Carmichael " 886 +c1.toString(16)); 887 failCount++; 888 } 889 found++; 890 } 891 } 892 } 893 f1 = f1.add(TWO); 894 } 895 896 // Test some composites that are products of 2 primes 897 for (int i=0; i<50; i++) { 898 p1 = BigInteger.probablePrime(100, rndSeed.getRandom()); 899 p2 = BigInteger.probablePrime(100, rndSeed.getRandom()); 900 c1 = p1.multiply(p2); 901 if (c1.isProbablePrime(100)) { 902 System.err.println("Composite failed "+c1.toString(16)); 903 failCount++; 904 } 905 } 906 907 for (int i=0; i<4; i++) { 908 p1 = BigInteger.probablePrime(600, rndSeed.getRandom()); 909 p2 = BigInteger.probablePrime(600, rndSeed.getRandom()); 910 c1 = p1.multiply(p2); 911 if (c1.isProbablePrime(100)) { 912 System.err.println("Composite failed "+c1.toString(16)); 913 failCount++; 914 } 915 } 916 917 report("Prime", failCount); 918 } 919 920 private static final long[] primesTo100 = { 921 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97 922 }; 923 924 private static final long[] aPrimeSequence = { 925 1999999003L, 1999999013L, 1999999049L, 1999999061L, 1999999081L, 926 1999999087L, 1999999093L, 1999999097L, 1999999117L, 1999999121L, 927 1999999151L, 1999999171L, 1999999207L, 1999999219L, 1999999271L, 928 1999999321L, 1999999373L, 1999999423L, 1999999439L, 1999999499L, 929 1999999553L, 1999999559L, 1999999571L, 1999999609L, 1999999613L, 930 1999999621L, 1999999643L, 1999999649L, 1999999657L, 1999999747L, 931 1999999763L, 1999999777L, 1999999811L, 1999999817L, 1999999829L, 932 1999999853L, 1999999861L, 1999999871L, 1999999873 933 }; 934 935 public static void nextProbablePrime() throws Exception { 936 int failCount = 0; 937 BigInteger p1, p2, p3; 938 p1 = p2 = p3 = ZERO; 939 940 // First test nextProbablePrime on the low range starting at zero 941 for (int i=0; i<primesTo100.length; i++) { 942 p1 = p1.nextProbablePrime(); 943 if (p1.longValue() != primesTo100[i]) { 944 System.err.println("low range primes failed"); 945 System.err.println("p1 is "+p1); 946 System.err.println("expected "+primesTo100[i]); 947 failCount++; 948 } 949 } 950 951 // Test nextProbablePrime on a relatively small, known prime sequence 952 p1 = BigInteger.valueOf(aPrimeSequence[0]); 953 for (int i=1; i<aPrimeSequence.length; i++) { 954 p1 = p1.nextProbablePrime(); 955 if (p1.longValue() != aPrimeSequence[i]) { 956 System.err.println("prime sequence failed"); 957 failCount++; 958 } 959 } 960 961 // Next, pick some large primes, use nextProbablePrime to find the 962 // next one, and make sure there are no primes in between 963 for (int i=0; i<100; i+=10) { 964 p1 = BigInteger.probablePrime(50 + i, rndSeed.getRandom()); 965 p2 = p1.add(ONE); 966 p3 = p1.nextProbablePrime(); 967 while(p2.compareTo(p3) < 0) { 968 if (p2.isProbablePrime(100)){ 969 System.err.println("nextProbablePrime failed"); 970 System.err.println("along range "+p1.toString(16)); 971 System.err.println("to "+p3.toString(16)); 972 failCount++; 973 break; 974 } 975 p2 = p2.add(ONE); 976 } 977 } 978 979 report("nextProbablePrime", failCount); 980 } 981 982 public static void serialize() throws Exception { 983 int failCount = 0; 984 985 String bitPatterns[] = { 986 "ffffffff00000000ffffffff00000000ffffffff00000000", 987 "ffffffffffffffffffffffff000000000000000000000000", 988 "ffffffff0000000000000000000000000000000000000000", 989 "10000000ffffffffffffffffffffffffffffffffffffffff", 990 "100000000000000000000000000000000000000000000000", 991 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 992 "-ffffffff00000000ffffffff00000000ffffffff00000000", 993 "-ffffffffffffffffffffffff000000000000000000000000", 994 "-ffffffff0000000000000000000000000000000000000000", 995 "-10000000ffffffffffffffffffffffffffffffffffffffff", 996 "-100000000000000000000000000000000000000000000000", 997 "-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 998 }; 999 1000 for(int i = 0; i < bitPatterns.length; i++) { 1001 BigInteger b1 = new BigInteger(bitPatterns[i], 16); 1002 BigInteger b2 = null; 1003 1004 File f = new File("serialtest"); 1005 1006 try (FileOutputStream fos = new FileOutputStream(f)) { 1007 try (ObjectOutputStream oos = new ObjectOutputStream(fos)) { 1008 oos.writeObject(b1); 1009 oos.flush(); 1010 } 1011 1012 try (FileInputStream fis = new FileInputStream(f); 1013 ObjectInputStream ois = new ObjectInputStream(fis)) 1014 { 1015 b2 = (BigInteger)ois.readObject(); 1016 } 1017 1018 if (!b1.equals(b2) || 1019 !b1.equals(b1.or(b2))) { 1020 failCount++; 1021 System.err.println("Serialized failed for hex " + 1022 b1.toString(16)); 1023 } 1024 } 1025 f.delete(); 1026 } 1027 1028 for(int i=0; i<10; i++) { 1029 BigInteger b1 = fetchNumber(rndSeed.getRandom().nextInt(100)); 1030 BigInteger b2 = null; 1031 File f = new File("serialtest"); 1032 try (FileOutputStream fos = new FileOutputStream(f)) { 1033 try (ObjectOutputStream oos = new ObjectOutputStream(fos)) { 1034 oos.writeObject(b1); 1035 oos.flush(); 1036 } 1037 1038 try (FileInputStream fis = new FileInputStream(f); 1039 ObjectInputStream ois = new ObjectInputStream(fis)) 1040 { 1041 b2 = (BigInteger)ois.readObject(); 1042 } 1043 } 1044 1045 if (!b1.equals(b2) || 1046 !b1.equals(b1.or(b2))) 1047 failCount++; 1048 f.delete(); 1049 } 1050 1051 report("Serialize", failCount); 1052 } 1053 1054 /** 1055 * Main to interpret arguments and run several tests. 1056 * 1057 * Up to three arguments may be given to specify the SIZE of BigIntegers 1058 * used for call parameters 1, 2, and 3. The SIZE is interpreted as 1059 * the maximum number of decimal digits that the parameters will have. 1060 * 1061 */ 1062 public static void main(String[] args) throws Exception { 1063 System.out.println("Random number generator seed = " + rndSeed.getSeed()); 1064 1065 // Some variables for sizing test numbers in bits 1066 int order1 = ORDER_MEDIUM; 1067 int order2 = ORDER_SMALL; 1068 int order3 = ORDER_KARATSUBA; 1069 int order4 = ORDER_TOOM_COOK; 1070 1071 if (args.length >0) 1072 order1 = (int)((Integer.parseInt(args[0]))* 3.333); 1073 if (args.length >1) 1074 order2 = (int)((Integer.parseInt(args[1]))* 3.333); 1075 if (args.length >2) 1076 order3 = (int)((Integer.parseInt(args[2]))* 3.333); 1077 if (args.length >3) 1078 order4 = (int)((Integer.parseInt(args[3]))* 3.333); 1079 1080 constructor(); 1081 1082 prime(); 1083 nextProbablePrime(); 1084 1085 arithmetic(order1); // small numbers 1086 arithmetic(order3); // Karatsuba range 1087 arithmetic(order4); // Toom-Cook / Burnikel-Ziegler range 1088 1089 divideAndRemainder(order1); // small numbers 1090 divideAndRemainder(order3); // Karatsuba range 1091 divideAndRemainder(order4); // Toom-Cook / Burnikel-Ziegler range 1092 1093 pow(order1); 1094 pow(order3); 1095 pow(order4); 1096 1097 square(ORDER_MEDIUM); 1098 square(ORDER_KARATSUBA_SQUARE); 1099 square(ORDER_TOOM_COOK_SQUARE); 1100 1101 bitCount(); 1102 bitLength(); 1103 bitOps(order1); 1104 bitwise(order1); 1105 1106 shift(order1); 1107 1108 byteArrayConv(order1); 1109 1110 modInv(order1); // small numbers 1111 modInv(order3); // Karatsuba range 1112 modInv(order4); // Toom-Cook / Burnikel-Ziegler range 1113 1114 modExp(order1, order2); 1115 modExp2(order1); 1116 1117 stringConv(); 1118 serialize(); 1119 1120 multiplyLarge(); 1121 squareLarge(); 1122 divideLarge(); 1123 1124 if (failure) 1125 throw new RuntimeException("Failure in BigIntegerTest."); 1126 } 1127 1128 /* 1129 * Get a random or boundary-case number. This is designed to provide 1130 * a lot of numbers that will find failure points, such as max sized 1131 * numbers, empty BigIntegers, etc. 1132 * 1133 * If order is less than 2, order is changed to 2. 1134 */ 1135 private static BigInteger fetchNumber(int order) { 1136 boolean negative = rndSeed.getRandom().nextBoolean(); 1137 int numType = rndSeed.getRandom().nextInt(7); 1138 BigInteger result = null; 1139 if (order < 2) order = 2; 1140 1141 switch (numType) { 1142 case 0: // Empty 1143 result = BigInteger.ZERO; 1144 break; 1145 1146 case 1: // One 1147 result = BigInteger.ONE; 1148 break; 1149 1150 case 2: // All bits set in number 1151 int numBytes = (order+7)/8; 1152 byte[] fullBits = new byte[numBytes]; 1153 for(int i=0; i<numBytes; i++) 1154 fullBits[i] = (byte)0xff; 1155 int excessBits = 8*numBytes - order; 1156 fullBits[0] &= (1 << (8-excessBits)) - 1; 1157 result = new BigInteger(1, fullBits); 1158 break; 1159 1160 case 3: // One bit in number 1161 result = BigInteger.ONE.shiftLeft(rndSeed.getRandom().nextInt(order)); 1162 break; 1163 1164 case 4: // Random bit density 1165 byte[] val = new byte[(order+7)/8]; 1166 int iterations = rndSeed.getRandom().nextInt(order); 1167 for (int i=0; i<iterations; i++) { 1168 int bitIdx = rndSeed.getRandom().nextInt(order); 1169 val[bitIdx/8] |= 1 << (bitIdx%8); 1170 } 1171 result = new BigInteger(1, val); 1172 break; 1173 case 5: // Runs of consecutive ones and zeros 1174 result = ZERO; 1175 int remaining = order; 1176 int bit = rndSeed.getRandom().nextInt(2); 1177 while (remaining > 0) { 1178 int runLength = Math.min(remaining, rndSeed.getRandom().nextInt(order)); 1179 result = result.shiftLeft(runLength); 1180 if (bit > 0) 1181 result = result.add(ONE.shiftLeft(runLength).subtract(ONE)); 1182 remaining -= runLength; 1183 bit = 1 - bit; 1184 } 1185 break; 1186 1187 default: // random bits 1188 result = new BigInteger(order, rndSeed.getRandom()); 1189 } 1190 1191 if (negative) 1192 result = result.negate(); 1193 1194 return result; 1195 } 1196 1197 static void report(String testName, int failCount) { 1198 System.err.println(testName+": " + 1199 (failCount==0 ? "Passed":"Failed("+failCount+")")); 1200 if (failCount > 0) 1201 failure = true; 1202 } 1203 }