1 /*
   2  * Copyright (c) 2013, 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 import java.math.BigInteger;
  25 import java.util.Random;
  26 import sun.misc.FDBigInteger;
  27 
  28 /**
  29  * @test
  30  * @bug 7032154
  31  * @summary unit testys of sun.misc.FDBigInteger
  32  * @author Dmitry Nadezhin
  33  */
  34 public class TestFDBigInteger {
  35 
  36     private static final int MAX_P5 = 413;
  37     private static final int MAX_P2 = 65;
  38     private static final long LONG_SIGN_MASK = (1L << 63);
  39     private static final BigInteger FIVE = BigInteger.valueOf(5);
  40     private static final FDBigInteger MUTABLE_ZERO = FDBigInteger.valueOfPow52(0, 0).leftInplaceSub(FDBigInteger.valueOfPow52(0, 0));
  41     private static final FDBigInteger IMMUTABLE_ZERO = FDBigInteger.valueOfPow52(0, 0).leftInplaceSub(FDBigInteger.valueOfPow52(0, 0));
  42     private static final FDBigInteger IMMUTABLE_MILLION = genMillion1();
  43     private static final FDBigInteger IMMUTABLE_BILLION = genBillion1();
  44     private static final FDBigInteger IMMUTABLE_TEN18 = genTen18();
  45 
  46     static {
  47         IMMUTABLE_ZERO.makeImmutable();
  48         IMMUTABLE_MILLION.makeImmutable();
  49         IMMUTABLE_BILLION.makeImmutable();
  50         IMMUTABLE_TEN18.makeImmutable();
  51     }
  52 
  53     private static FDBigInteger mutable(String hex, int offset) {
  54         char[] chars = new BigInteger(hex, 16).toString().toCharArray();
  55         return new FDBigInteger(0, chars, 0, chars.length).multByPow52(0, offset * 32);
  56     }
  57 
  58     private static FDBigInteger immutable(String hex, int offset) {
  59         FDBigInteger fd = mutable(hex, offset);
  60         fd.makeImmutable();
  61         return fd;
  62     }
  63 
  64     private static BigInteger biPow52(int p5, int p2) {
  65         return FIVE.pow(p5).shiftLeft(p2);
  66     }
  67 
  68     // data.length == 1, nWords == 1, offset == 0
  69     private static FDBigInteger genMillion1() {
  70         return FDBigInteger.valueOfPow52(6, 0).leftShift(6);
  71     }
  72 
  73     // data.length == 2, nWords == 1, offset == 0
  74     private static FDBigInteger genMillion2() {
  75         return FDBigInteger.valueOfMulPow52(1000000L, 0, 0);
  76     }
  77 
  78     // data.length == 1, nWords == 1, offset == 0
  79     private static FDBigInteger genBillion1() {
  80         return FDBigInteger.valueOfPow52(9, 0).leftShift(9);
  81     }
  82 
  83     // data.length == 2, nWords == 2, offset == 0
  84     private static FDBigInteger genTen18() {
  85         return FDBigInteger.valueOfPow52(18, 0).leftShift(18);
  86     }
  87 
  88     private static void check(BigInteger expected, FDBigInteger actual, String message) throws Exception {
  89         if (!expected.equals(actual.toBigInteger())) {
  90             throw new Exception(message + " result " + actual.toHexString() + " expected " + expected.toString(16));
  91         }
  92     }
  93 
  94     private static void testValueOfPow52(int p5, int p2) throws Exception {
  95         check(biPow52(p5, p2), FDBigInteger.valueOfPow52(p5, p2),
  96                 "valueOfPow52(" + p5 + "," + p2 + ")");
  97     }
  98 
  99     private static void testValueOfPow52() throws Exception {
 100         for (int p5 = 0; p5 <= MAX_P5; p5++) {
 101             for (int p2 = 0; p2 <= MAX_P2; p2++) {
 102                 testValueOfPow52(p5, p2);
 103             }
 104         }
 105     }
 106 
 107     private static void testValueOfMulPow52(long value, int p5, int p2) throws Exception {
 108         BigInteger bi = BigInteger.valueOf(value & ~LONG_SIGN_MASK);
 109         if (value < 0) {
 110             bi = bi.setBit(63);
 111         }
 112         check(biPow52(p5, p2).multiply(bi), FDBigInteger.valueOfMulPow52(value, p5, p2),
 113                 "valueOfMulPow52(" + Long.toHexString(value) + "." + p5 + "," + p2 + ")");
 114     }
 115 
 116     private static void testValueOfMulPow52(long value, int p5) throws Exception {
 117         testValueOfMulPow52(value, p5, 0);
 118         testValueOfMulPow52(value, p5, 1);
 119         testValueOfMulPow52(value, p5, 30);
 120         testValueOfMulPow52(value, p5, 31);
 121         testValueOfMulPow52(value, p5, 33);
 122         testValueOfMulPow52(value, p5, 63);
 123     }
 124 
 125     private static void testValueOfMulPow52() throws Exception {
 126         for (int p5 = 0; p5 <= MAX_P5; p5++) {
 127             testValueOfMulPow52(0xFFFFFFFFL, p5);
 128             testValueOfMulPow52(0x123456789AL, p5);
 129             testValueOfMulPow52(0x7FFFFFFFFFFFFFFFL, p5);
 130             testValueOfMulPow52(0xFFFFFFFFFFF54321L, p5);
 131         }
 132     }
 133 
 134     private static void testLeftShift(FDBigInteger t, int shift, boolean isImmutable) throws Exception {
 135         BigInteger bt = t.toBigInteger();
 136         FDBigInteger r = t.leftShift(shift);
 137         if ((bt.signum() == 0 || shift == 0 || !isImmutable) && r != t) {
 138             throw new Exception("leftShift doesn't reuse its argument");
 139         }
 140         if (isImmutable) {
 141             check(bt, t, "leftShift corrupts its argument");
 142         }
 143         check(bt.shiftLeft(shift), r, "leftShift returns wrong result");
 144     }
 145 
 146     private static void testLeftShift() throws Exception {
 147         testLeftShift(IMMUTABLE_ZERO, 0, true);
 148         testLeftShift(IMMUTABLE_ZERO, 10, true);
 149         testLeftShift(MUTABLE_ZERO, 0, false);
 150         testLeftShift(MUTABLE_ZERO, 10, false);
 151 
 152         testLeftShift(IMMUTABLE_MILLION, 0, true);
 153         testLeftShift(IMMUTABLE_MILLION, 1, true);
 154         testLeftShift(IMMUTABLE_MILLION, 12, true);
 155         testLeftShift(IMMUTABLE_MILLION, 13, true);
 156         testLeftShift(IMMUTABLE_MILLION, 32, true);
 157         testLeftShift(IMMUTABLE_MILLION, 33, true);
 158         testLeftShift(IMMUTABLE_MILLION, 44, true);
 159         testLeftShift(IMMUTABLE_MILLION, 45, true);
 160 
 161         testLeftShift(genMillion1(), 0, false);
 162         testLeftShift(genMillion1(), 1, false);
 163         testLeftShift(genMillion1(), 12, false);
 164         testLeftShift(genMillion1(), 13, false);
 165         testLeftShift(genMillion1(), 25, false);
 166         testLeftShift(genMillion1(), 26, false);
 167         testLeftShift(genMillion1(), 32, false);
 168         testLeftShift(genMillion1(), 33, false);
 169         testLeftShift(genMillion1(), 44, false);
 170         testLeftShift(genMillion1(), 45, false);
 171 
 172         testLeftShift(genMillion2(), 0, false);
 173         testLeftShift(genMillion2(), 1, false);
 174         testLeftShift(genMillion2(), 12, false);
 175         testLeftShift(genMillion2(), 13, false);
 176         testLeftShift(genMillion2(), 25, false);
 177         testLeftShift(genMillion2(), 26, false);
 178         testLeftShift(genMillion2(), 32, false);
 179         testLeftShift(genMillion2(), 33, false);
 180         testLeftShift(genMillion2(), 44, false);
 181         testLeftShift(genMillion2(), 45, false);
 182     }
 183 
 184     private static void testQuoRemIteration(FDBigInteger t, FDBigInteger s) throws Exception {
 185         BigInteger bt = t.toBigInteger();
 186         BigInteger bs = s.toBigInteger();
 187         int q = t.quoRemIteration(s);
 188         BigInteger[] qr = bt.divideAndRemainder(bs);
 189         if (!BigInteger.valueOf(q).equals(qr[0])) {
 190             throw new Exception("quoRemIteration returns incorrect quo");
 191         }
 192         check(qr[1].multiply(BigInteger.TEN), t, "quoRemIteration returns incorrect rem");
 193     }
 194 
 195     private static void testQuoRemIteration() throws Exception {
 196         // IMMUTABLE_TEN18 == 0de0b6b3a7640000
 197         // q = 0
 198         testQuoRemIteration(mutable("00000001", 0), IMMUTABLE_TEN18);
 199         testQuoRemIteration(mutable("00000001", 1), IMMUTABLE_TEN18);
 200         testQuoRemIteration(mutable("0de0b6b2", 1), IMMUTABLE_TEN18);
 201         // q = 1 -> q = 0
 202         testQuoRemIteration(mutable("0de0b6b3", 1), IMMUTABLE_TEN18);
 203         testQuoRemIteration(mutable("0de0b6b3a763FFFF", 0), IMMUTABLE_TEN18);
 204         // q = 1
 205         testQuoRemIteration(mutable("0de0b6b3a7640000", 0), IMMUTABLE_TEN18);
 206         testQuoRemIteration(mutable("0de0b6b3FFFFFFFF", 0), IMMUTABLE_TEN18);
 207         testQuoRemIteration(mutable("8ac72304", 1), IMMUTABLE_TEN18);
 208         testQuoRemIteration(mutable("0de0b6b400000000", 0), IMMUTABLE_TEN18);
 209         testQuoRemIteration(mutable("8ac72305", 1), IMMUTABLE_TEN18);
 210         // q = 18
 211         testQuoRemIteration(mutable("FFFFFFFF", 1), IMMUTABLE_TEN18);
 212     }
 213 
 214     private static void testCmp(FDBigInteger t, FDBigInteger o) throws Exception {
 215         BigInteger bt = t.toBigInteger();
 216         BigInteger bo = o.toBigInteger();
 217         int cmp = t.cmp(o);
 218         int bcmp = bt.compareTo(bo);
 219         if (bcmp != cmp) {
 220             throw new Exception("cmp returns " + cmp + " expected " + bcmp);
 221         }
 222         check(bt, t, "cmp corrupts this");
 223         check(bo, o, "cmp corrupts other");
 224         if (o.cmp(t) != -cmp) {
 225             throw new Exception("asymmetrical cmp");
 226         }
 227         check(bt, t, "cmp corrupts this");
 228         check(bo, o, "cmp corrupts other");
 229     }
 230 
 231     private static void testCmp() throws Exception {
 232         testCmp(mutable("FFFFFFFF", 0), mutable("100000000", 0));
 233         testCmp(mutable("FFFFFFFF", 0), mutable("1", 1));
 234         testCmp(mutable("5", 0), mutable("6", 0));
 235         testCmp(mutable("5", 0), mutable("5", 0));
 236         testCmp(mutable("5000000001", 0), mutable("500000001", 0));
 237         testCmp(mutable("5000000001", 0), mutable("6", 1));
 238         testCmp(mutable("5000000001", 0), mutable("5", 1));
 239         testCmp(mutable("5000000000", 0), mutable("5", 1));
 240     }
 241 
 242     private static void testCmpPow52(FDBigInteger t, int p5, int p2) throws Exception {
 243         FDBigInteger o = FDBigInteger.valueOfPow52(p5, p2);
 244         BigInteger bt = t.toBigInteger();
 245         BigInteger bo = biPow52(p5, p2);
 246         int cmp = t.cmp(o);
 247         int bcmp = bt.compareTo(bo);
 248         if (bcmp != cmp) {
 249             throw new Exception("cmpPow52 returns " + cmp + " expected " + bcmp);
 250         }
 251         check(bt, t, "cmpPow52 corrupts this");
 252         check(bo, o, "cmpPow5 corrupts other");
 253     }
 254 
 255     private static void testCmpPow52() throws Exception {
 256         testCmpPow52(mutable("00000002", 1), 0, 31);
 257         testCmpPow52(mutable("00000002", 1), 0, 32);
 258         testCmpPow52(mutable("00000002", 1), 0, 33);
 259         testCmpPow52(mutable("00000002", 1), 0, 34);
 260         testCmpPow52(mutable("00000002", 1), 0, 64);
 261         testCmpPow52(mutable("00000003", 1), 0, 32);
 262         testCmpPow52(mutable("00000003", 1), 0, 33);
 263         testCmpPow52(mutable("00000003", 1), 0, 34);
 264     }
 265 
 266     private static void testAddAndCmp(FDBigInteger t, FDBigInteger x, FDBigInteger y) throws Exception {
 267         BigInteger bt = t.toBigInteger();
 268         BigInteger bx = x.toBigInteger();
 269         BigInteger by = y.toBigInteger();
 270         int cmp = t.addAndCmp(x, y);
 271         int bcmp = bt.compareTo(bx.add(by));
 272         if (bcmp != cmp) {
 273             throw new Exception("addAndCmp returns " + cmp + " expected " + bcmp);
 274         }
 275         check(bt, t, "addAndCmp corrupts this");
 276         check(bx, x, "addAndCmp corrupts x");
 277         check(by, y, "addAndCmp corrupts y");
 278     }
 279 
 280     private static void testAddAndCmp() throws Exception {
 281         testAddAndCmp(MUTABLE_ZERO, MUTABLE_ZERO, MUTABLE_ZERO);
 282         testAddAndCmp(mutable("00000001", 0), MUTABLE_ZERO, MUTABLE_ZERO);
 283         testAddAndCmp(mutable("00000001", 0), mutable("00000001", 0), MUTABLE_ZERO);
 284         testAddAndCmp(mutable("00000001", 0), MUTABLE_ZERO, mutable("00000001", 0));
 285         testAddAndCmp(mutable("00000001", 0), mutable("00000002", 0), MUTABLE_ZERO);
 286         testAddAndCmp(mutable("00000001", 0), MUTABLE_ZERO, mutable("00000002", 0));
 287         testAddAndCmp(mutable("00000001", 2), mutable("FFFFFFFF", 0), mutable("FFFFFFFF", 0));
 288         testAddAndCmp(mutable("00000001", 0), mutable("00000001", 1), mutable("00000001", 0));
 289 
 290         testAddAndCmp(mutable("00000001", 2), mutable("0F0F0F0F80000000", 1), mutable("F0F0F0F080000000", 1));
 291         testAddAndCmp(mutable("00000001", 2), mutable("0F0F0F0E80000000", 1), mutable("F0F0F0F080000000", 1));
 292 
 293         testAddAndCmp(mutable("00000002", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
 294         testAddAndCmp(mutable("00000003", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
 295         testAddAndCmp(mutable("00000004", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
 296         testAddAndCmp(mutable("00000005", 1), mutable("0000000180000000", 1), mutable("0000000280000000", 1));
 297 
 298         testAddAndCmp(mutable("00000001", 2), mutable("8000000000000000", 0), mutable("8000000000000000", 0));
 299         testAddAndCmp(mutable("00000001", 2), mutable("8000000000000000", 0), mutable("8000000000000001", 0));
 300         testAddAndCmp(mutable("00000002", 2), mutable("8000000000000000", 0), mutable("8000000000000000", 0));
 301         testAddAndCmp(mutable("00000003", 2), mutable("8000000000000000", 0), mutable("8000000000000000", 0));
 302     }
 303 
 304     private static void testMultBy10(FDBigInteger t, boolean isImmutable) throws Exception {
 305         BigInteger bt = t.toBigInteger();
 306         FDBigInteger r = t.multBy10();
 307         if ((bt.signum() == 0 || !isImmutable) && r != t) {
 308             throw new Exception("multBy10 of doesn't reuse its argument");
 309         }
 310         if (isImmutable) {
 311             check(bt, t, "multBy10 corrupts its argument");
 312         }
 313         check(bt.multiply(BigInteger.TEN), r, "multBy10 returns wrong result");
 314     }
 315 
 316     private static void testMultBy10() throws Exception {
 317         for (int p5 = 0; p5 <= MAX_P5; p5++) {
 318             for (int p2 = 0; p2 <= MAX_P2; p2++) {
 319                 // This strange way of creating a value ensures that it is mutable.
 320                 FDBigInteger value = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
 321                 testMultBy10(value, false);
 322                 value.makeImmutable();
 323                 testMultBy10(value, true);
 324             }
 325         }
 326     }
 327 
 328     private static void testMultByPow52(FDBigInteger t, int p5, int p2) throws Exception {
 329         BigInteger bt = t.toBigInteger();
 330         FDBigInteger r = t.multByPow52(p5, p2);
 331         if (bt.signum() == 0 && r != t) {
 332             throw new Exception("multByPow52 of doesn't reuse its argument");
 333         }
 334         check(bt.multiply(biPow52(p5, p2)), r, "multByPow52 returns wrong result");
 335     }
 336 
 337     private static void testMultByPow52() throws Exception {
 338         for (int p5 = 0; p5 <= MAX_P5; p5++) {
 339             for (int p2 = 0; p2 <= MAX_P2; p2++) {
 340                 // This strange way of creating a value ensures that it is mutable.
 341                 FDBigInteger value = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
 342                 testMultByPow52(value, p5, p2);
 343             }
 344         }
 345     }
 346 
 347     private static void testLeftInplaceSub(FDBigInteger left, FDBigInteger right, boolean isImmutable) throws Exception {
 348         BigInteger biLeft = left.toBigInteger();
 349         BigInteger biRight = right.toBigInteger();
 350         FDBigInteger diff = left.leftInplaceSub(right);
 351         if (!isImmutable && diff != left) {
 352             throw new Exception("leftInplaceSub of doesn't reuse its argument");
 353         }
 354         check(biLeft.subtract(biRight), diff, "leftInplaceSub returns wrong result");
 355     }
 356 
 357     private static void testLeftInplaceSub() throws Exception {
 358         for (int p5 = 0; p5 <= MAX_P5; p5++) {
 359             for (int p2 = 0; p2 <= MAX_P2; p2++) {
 360 //                for (int p5r = 0; p5r <= p5; p5r += 10) {
 361 //                    for (int p2r = 0; p2r <= p2; p2r += 10) {
 362                 for (int p5r = 0; p5r <= p5; p5r++) {
 363                     for (int p2r = 0; p2r <= p2; p2r++) {
 364                         // This strange way of creating a value ensures that it is mutable.
 365                         FDBigInteger left = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
 366                         FDBigInteger right = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5r, p2r);
 367                         testLeftInplaceSub(left, right, false);
 368                         left = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
 369                         left.makeImmutable();
 370                         testLeftInplaceSub(left, right, true);
 371                     }
 372                 }
 373             }
 374         }
 375     }
 376 
 377     private static void testRightInplaceSub(FDBigInteger left, FDBigInteger right, boolean isImmutable) throws Exception {
 378         BigInteger biLeft = left.toBigInteger();
 379         BigInteger biRight = right.toBigInteger();
 380         FDBigInteger diff = left.rightInplaceSub(right);
 381         if (!isImmutable && diff != right) {
 382             throw new Exception("rightInplaceSub of doesn't reuse its argument");
 383         }
 384         try {
 385             check(biLeft.subtract(biRight), diff, "rightInplaceSub returns wrong result");
 386         } catch (Exception e) {
 387             System.out.println(biLeft+" - "+biRight+" = "+biLeft.subtract(biRight));
 388             throw e;
 389         }
 390     }
 391 
 392     private static void testRightInplaceSub() throws Exception {
 393         for (int p5 = 0; p5 <= MAX_P5; p5++) {
 394             for (int p2 = 0; p2 <= MAX_P2; p2++) {
 395 //                for (int p5r = 0; p5r <= p5; p5r += 10) {
 396 //                    for (int p2r = 0; p2r <= p2; p2r += 10) {
 397                 for (int p5r = 0; p5r <= p5; p5r++) {
 398                     for (int p2r = 0; p2r <= p2; p2r++) {
 399                         // This strange way of creating a value ensures that it is mutable.
 400                         FDBigInteger left = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5, p2);
 401                         FDBigInteger right = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5r, p2r);
 402                         testRightInplaceSub(left, right, false);
 403                         right = FDBigInteger.valueOfPow52(0, 0).multByPow52(p5r, p2r);
 404                         right.makeImmutable();
 405                         testRightInplaceSub(left, right, true);
 406                     }
 407                 }
 408             }
 409         }
 410     }
 411 
 412     public static void main(String[] args) throws Exception {
 413         testValueOfPow52();
 414         testValueOfMulPow52();
 415         testLeftShift();
 416         testQuoRemIteration();
 417         testCmp();
 418         testCmpPow52();
 419         testAddAndCmp();
 420         // Uncomment the following for more comprehensize but slow testing.
 421         // testLeftInplaceSub();
 422         // testMultBy10();
 423         // testMultByPow52();
 424         // testRightInplaceSub();
 425     }
 426 }