public BigInteger gcd(BigInteger val) { BigInteger val1 = this.abs(); BigInteger val2 = val.abs(); // To avoid a possible division by zero if (val1.signum() == 0) { return(val2); } else if (val2.signum() == 0) { return(val1); } // Optimization for small operands // (op2.bitLength() < 64) and (op1.bitLength() < 64) if (((val1.numberLength == 1) || ((val1.numberLength == 2) && (val1.digits[1] > 0))) && (val2.numberLength == 1 || (val2.numberLength == 2 && val2.digits[1] > 0))) { return(BigInteger.valueOf(Division.gcdBinary(val1.longValue(), val2 .longValue()))); } return(Division.gcdBinary(val1.copy(), val2.copy())); }
internal static BigInteger gcdBinary(BigInteger op1, BigInteger op2) { // PRE: (op1 > 0) and (op2 > 0) /* * Divide both number the maximal possible times by 2 without rounding * gcd(2*a, 2*b) = 2 * gcd(a,b) */ int lsb1 = op1.getLowestSetBit(); int lsb2 = op2.getLowestSetBit(); int pow2Count = Math.Min(lsb1, lsb2); BitLevel.inplaceShiftRight(op1, lsb1); BitLevel.inplaceShiftRight(op2, lsb2); BigInteger swap; // I want op2 > op1 if (op1.compareTo(op2) == BigInteger.GREATER) { swap = op1; op1 = op2; op2 = swap; } do // INV: op2 >= op1 && both are odd unless op1 = 0 // Optimization for small operands // (op2.bitLength() < 64) implies by INV (op1.bitLength() < 64) { if ((op2.numberLength == 1) || ((op2.numberLength == 2) && (op2.digits[1] > 0))) { op2 = BigInteger.valueOf(Division.gcdBinary(op1.longValue(), op2.longValue())); break; } // Implements one step of the Euclidean algorithm // To reduce one operand if it's much smaller than the other one if (op2.numberLength > op1.numberLength * 1.2) { op2 = op2.remainder(op1); if (op2.signum() != 0) { BitLevel.inplaceShiftRight(op2, op2.getLowestSetBit()); } } else { // Use Knuth's algorithm of successive subtract and shifting do { Elementary.inplaceSubtract(op2, op1); // both are odd BitLevel.inplaceShiftRight(op2, op2.getLowestSetBit()); // op2 is even } while (op2.compareTo(op1) >= BigInteger.EQUALS); } // now op1 >= op2 swap = op2; op2 = op1; op1 = swap; } while (op1.sign != 0); return(op2.shiftLeft(pow2Count)); }