Package jmathexpr.arithmetic.op

Source Code of jmathexpr.arithmetic.op.Division

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package jmathexpr.arithmetic.op;

import jmathexpr.Expression;
import jmathexpr.Precedence;
import jmathexpr.arithmetic.ANumber;
import jmathexpr.arithmetic.Polynomial;
import jmathexpr.arithmetic.integer.IntegerNumber;
import jmathexpr.arithmetic.natural.NaturalNumber;
import jmathexpr.arithmetic.natural.Naturals;
import jmathexpr.arithmetic.natural.PrimeFactorization;
import jmathexpr.arithmetic.real.Reals;
import jmathexpr.op.BinaryOperation;
import jmathexpr.op.Sign;
import jmathexpr.set.FiniteSet;
import jmathexpr.set.Set;
import jmathexpr.set.op.CartesianProduct;
import jmathexpr.set.op.Difference;
import jmathexpr.util.logging.Logger;

/**
*
* @author Elemér Furka
*/
public class Division extends BinaryOperation {

    public Division(Expression lhs, Expression rhs) {
        super(lhs, rhs, Sign.Division);
    }

    @Override
    public Expression evaluate() {
        Expression simplified = simplify();
       
        if (!(simplified instanceof Division)) return simplified;
       
        Expression l = ((Division) simplified).lhs;
        Expression r = ((Division) simplified).rhs;

        if (l instanceof ANumber && r instanceof ANumber) {
            if (((ANumber) r).isZero()) {
                throw new IllegalArgumentException("Division by 0");
            } else {
                return ((ANumber) l).divide((ANumber) r);
            }
        } else if (l instanceof Multiplication && r instanceof ANumber) { // simplification of a*b/c
            Multiplication dividend = (Multiplication) l;

            if (dividend.lhs() instanceof ANumber) {
                return new Multiplication(new Division(dividend.lhs(), r), dividend.rhs()).evaluate();
            } else if (dividend.rhs() instanceof ANumber) {
                return new Multiplication(dividend.lhs(), new Division(dividend.rhs(), r)).evaluate();
            }
        } else if (l instanceof Multiplication) {
            Multiplication dividend = (Multiplication) l;

            if (dividend.lhs().equals(r)) { // simplification of a*b/a
                return dividend.rhs();
            } else if (dividend.rhs().equals(r)) { // simplification of b*a/a
                return dividend.lhs();
            }
        } else if (l instanceof Polynomial) {
            return ((Polynomial) l).divide(r);
        }
       
        return new Division(l, r);
    }

    private Expression simplify() {
        Expression l = lhs.evaluate();
        Expression r = rhs.evaluate();
       
        if (l.equals(r) && !(r instanceof ANumber && ((ANumber) r).isZero())) { // a/a = 1 (a != 0)
            return Naturals.one();
        }
       
        if (l instanceof Multiplication) {
            Multiplication dividend = (Multiplication) l;

            if (dividend.lhs().equals(r)) { // simplification of a*b/a
                return dividend.rhs();
            } else if (dividend.rhs().equals(r)) { // simplification of b*a/a
                return dividend.lhs();
            }
        } else if (l instanceof Division) { // (a / b) / c = a / (bc)
            Expression a = ((Division) l).lhs();
            Expression b = ((Division) l).rhs();
           
            return new Division(a, new Multiplication(b, r)).evaluate();
        } else if (l instanceof Negation) { // -(a)/b = -(a/b)
            return new Negation(new Division(((Negation) l).getChild(), r)).evaluate();
        } else if (l instanceof Addition || l instanceof Subtraction) { // simplifying (a +- b) / r
            if (r instanceof NaturalNumber) {
                return simplifyAdditive((BinaryOperation) l, (NaturalNumber) r);
            } else if (r instanceof IntegerNumber) {
                if (!((IntegerNumber) r).isNegative()) {
                    NaturalNumber n = ((IntegerNumber) r).toNatural();
                   
                    return simplifyAdditive((BinaryOperation) l, n);
                }
            }
        }
       
        return new Division(l, r);
    }
   
    private Expression simplifyAdditive(BinaryOperation sum, NaturalNumber denominator) {
        PrimeFactorization factors = denominator.factorize();
        Expression l = sum.lhs();
        Expression r = sum.rhs();
        NaturalNumber divisor = Naturals.one();
       
        for (NaturalNumber p : factors.primeFactors()) {
            if (isDivisibleBy(l, p) && isDivisibleBy(r, p)) {
                l = new Division(l, p).evaluate();
                r = new Division(r, p).evaluate();
                divisor = (NaturalNumber) divisor.multiply(p);
            }
        }
       
        ANumber simplifiedDenominator = denominator.divide(divisor);
        Expression numerator;
       
        if (sum instanceof Addition) {
            numerator = new Addition(l, r).evaluate();
        } else if (sum instanceof Subtraction) {
            numerator = new Subtraction(l, r).evaluate();
        } else {
            throw new IllegalStateException(String.format(
                    "Unexpected operation type: %s (%s)", sum, sum.getClass()));
        }
       
        if (simplifiedDenominator.isOne()) {
            return numerator;
        } else {
            return new Division(numerator, simplifiedDenominator);
        }
    }
   
    private boolean isDivisibleBy(Expression expr, Expression divisor) {
        if (divisor instanceof NaturalNumber) {
            if (expr instanceof IntegerNumber) {
                return ((IntegerNumber) expr).mod((NaturalNumber) divisor).isZero();
            } else if (expr instanceof Multiplication) {
                Multiplication m = (Multiplication) expr;
               
                if (m.lhs() instanceof IntegerNumber) {
                    return ((IntegerNumber) m.lhs()).mod((NaturalNumber) divisor).isZero();
                } else if (m.rhs() instanceof IntegerNumber) {
                    return ((IntegerNumber) m.rhs()).mod((NaturalNumber) divisor).isZero();
                }
            }
        }
       
        return false;
    }
       
    @Override
    public Precedence getPrecedence() {
        return Precedence.Multiplication;
    }

    @Override
    public Set domain() {
        return new CartesianProduct(Reals.getInstance(), new Difference(Reals.getInstance(), new FiniteSet(Naturals.zero())));
    }

    @Override
    public Set codomain() {
        return Reals.getInstance();
    }

    @Override
    protected BinaryOperation create(Expression lhs, Expression rhs) {
        return new Division(lhs, rhs);
    }
   
    @Override
    public String toString() {
        if (lhs.getPrecedence().lt(getPrecedence())) {
            return String.format("(%s) %s %s", lhs, sign, rhs);
        } else if (rhs.getPrecedence().lt(getPrecedence())) {
            return String.format("%s %s (%s)", lhs, sign, rhs);
        } else {
            return super.toString();
        }
    }

    @Override
    public boolean isCommutative() {
        return false;
    }
}
TOP

Related Classes of jmathexpr.arithmetic.op.Division

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.