package org.matheclipse.core.reflection.system;

import java.math.BigInteger;

import org.matheclipse.core.basic.Config;
import org.matheclipse.core.eval.exception.Validate;
import org.matheclipse.core.eval.interfaces.AbstractFunctionEvaluator;
import org.matheclipse.core.expression.F;
import org.matheclipse.core.interfaces.IAST;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.IInteger;

/**
 * Returns the gcd of two positive numbers plus the bezout relations
 * 
 * See Extended
 * Euclidean algorithm and See Bézout's
 * identity
 * 
 * @author jeremy watts
 * @version 05/03/07
 */
public class ExtendedGCD extends AbstractFunctionEvaluator {

	public ExtendedGCD() {
	}

	@Override
	public IExpr evaluate(final IAST ast) {
		Validate.checkRange(ast, 3);
		 
		for (int i = 1; i < ast.size(); i++) {
			if (!ast.get(i).isInteger()) {
				return null;
			}
			if (!((IInteger) ast.get(i)).isPositive()) {
				return null;
			}
		}
		// all arguments are positive integers now

		try {
			BigInteger gcd = ((IInteger) ast.arg1()).getBigNumerator();
			BigInteger factor = BigInteger.ONE;
			BigInteger[] subBezouts = new BigInteger[ast.size() - 1];
			Object[] stepResult = extendedGCD(((IInteger) ast.arg2()).getBigNumerator(), gcd);

			gcd = (BigInteger) stepResult[0];
			subBezouts[0] = ((BigInteger[]) stepResult[1])[0];
			subBezouts[1] = ((BigInteger[]) stepResult[1])[1];

			for (int i = 3; i < ast.size(); i++) {
				stepResult = extendedGCD(((IInteger) ast.get(i)).getBigNumerator(), gcd);
				gcd = (BigInteger) stepResult[0];
				factor = ((BigInteger[]) stepResult[1])[0];
				for (int j = 0; j < i - 1; j++) {
					subBezouts[j] = subBezouts[j].multiply(factor);
				}
				subBezouts[i - 1] = ((BigInteger[]) stepResult[1])[1];
			}
			// convert the Bezout numbers to sublists
			IAST subList = F.List();
			for (int i = 0; i < subBezouts.length; i++) {
				subList.add(F.integer(subBezouts[i]));
			}
			// create the output list
			IAST list = F.List();
			list.add(F.integer(gcd));
			list.add(subList);
			return list;
		} catch (ArithmeticException ae) {
			if (Config.SHOW_STACKTRACE) {
				ae.printStackTrace();
			}
		}
		return null;
	}

	/**
	 * Returns the gcd of two positive numbers plus the bezout relation
	 */
	public static Object[] extendedGCD(BigInteger numberOne, BigInteger numberTwo) throws ArithmeticException {
		Object[] results = new Object[2];
		BigInteger[] divisionResult = new BigInteger[2];
		BigInteger dividend;
		BigInteger divisor;
		BigInteger quotient;
		BigInteger remainder;
		BigInteger xValue;
		BigInteger yValue;
		BigInteger tempValue;
		BigInteger lastxValue;
		BigInteger lastyValue;
		BigInteger gcd = BigInteger.ONE;
		BigInteger mValue = BigInteger.ONE;
		BigInteger nValue = BigInteger.ONE;
		boolean exchange;

		remainder = BigInteger.ONE;
		xValue = BigInteger.ZERO;
		lastxValue = BigInteger.ONE;
		yValue = BigInteger.ONE;
		lastyValue = BigInteger.ZERO;
		if ((!((numberOne.compareTo(BigInteger.ZERO) == 0) || (numberTwo.compareTo(BigInteger.ZERO) == 0)))
				&& (((numberOne.compareTo(BigInteger.ZERO) == 1) && (numberTwo.compareTo(BigInteger.ZERO) == 1)))) {
			if (numberOne.compareTo(numberTwo) == 1) {
				exchange = false;
				dividend = numberOne;
				divisor = numberTwo;
			} else {
				exchange = true;
				dividend = numberTwo;
				divisor = numberOne;
			}

			while (remainder.compareTo(BigInteger.ZERO) != 0) {
				divisionResult = dividend.divideAndRemainder(divisor);
				quotient = divisionResult[0];
				remainder = divisionResult[1];

				dividend = divisor;
				divisor = remainder;

				tempValue = xValue;
				xValue = lastxValue.subtract(quotient.multiply(xValue));
				lastxValue = tempValue;

				tempValue = yValue;
				yValue = lastyValue.subtract(quotient.multiply(yValue));
				lastyValue = tempValue;
			}

			gcd = dividend;
			if (exchange) {
				mValue = lastyValue;
				nValue = lastxValue;
			} else {
				mValue = lastxValue;
				nValue = lastyValue;
			}
		} else {
			throw new ArithmeticException("ExtendedGCD contains wrong arguments");
		}
		results[0] = gcd;
		BigInteger[] values = new BigInteger[2];
		values[0] = nValue;
		values[1] = mValue;
		results[1] = values;
		return results;
	}

}

 

Ads help maintain this website.