/** Karazuba multiplication */
  private BigIntPolynomial multRecursive(BigIntPolynomial poly2) {
    BigInteger[] a = coeffs;
    BigInteger[] b = poly2.coeffs;

    int n = poly2.coeffs.length;
    if (n <= 1) {
      BigInteger[] c = Arrays.clone(coeffs);
      for (int i = 0; i < coeffs.length; i++) {
        c[i] = c[i].multiply(poly2.coeffs[0]);
      }
      return new BigIntPolynomial(c);
    } else {
      int n1 = n / 2;

      BigIntPolynomial a1 = new BigIntPolynomial(Arrays.copyOf(a, n1));
      BigIntPolynomial a2 = new BigIntPolynomial(Arrays.copyOfRange(a, n1, n));
      BigIntPolynomial b1 = new BigIntPolynomial(Arrays.copyOf(b, n1));
      BigIntPolynomial b2 = new BigIntPolynomial(Arrays.copyOfRange(b, n1, n));

      BigIntPolynomial A = (BigIntPolynomial) a1.clone();
      A.add(a2);
      BigIntPolynomial B = (BigIntPolynomial) b1.clone();
      B.add(b2);

      BigIntPolynomial c1 = a1.multRecursive(b1);
      BigIntPolynomial c2 = a2.multRecursive(b2);
      BigIntPolynomial c3 = A.multRecursive(B);
      c3.sub(c1);
      c3.sub(c2);

      BigIntPolynomial c = new BigIntPolynomial(2 * n - 1);
      for (int i = 0; i < c1.coeffs.length; i++) {
        c.coeffs[i] = c1.coeffs[i];
      }
      for (int i = 0; i < c3.coeffs.length; i++) {
        c.coeffs[n1 + i] = c.coeffs[n1 + i].add(c3.coeffs[i]);
      }
      for (int i = 0; i < c2.coeffs.length; i++) {
        c.coeffs[2 * n1 + i] = c.coeffs[2 * n1 + i].add(c2.coeffs[i]);
      }
      return c;
    }
  }
 /**
  * Adds another polynomial which can have a different number of coefficients, and takes the
  * coefficient values mod <code>modulus</code>.
  *
  * @param b another polynomial
  */
 void add(BigIntPolynomial b, BigInteger modulus) {
   add(b);
   mod(modulus);
 }