unikl.disco.numbers.NumFraction.java Source code

Java tutorial

Introduction

Here is the source code for unikl.disco.numbers.NumFraction.java

Source

/*
 * This file is part of the Disco Deterministic Network Calculator v2.2.6 "Hydra".
 *
 * Copyright (C) 2013 - 2016 Steffen Bondorf
 *
 * disco | Distributed Computer Systems Lab
 * University of Kaiserslautern, Germany
 *
 * http://disco.cs.uni-kl.de
 *
 *
 * The Disco Deterministic Network Calculator (DiscoDNC) is free software;
 * you can redistribute it and/or modify it under the terms of the 
 * GNU Lesser General Public License as published by the Free Software Foundation; 
 * either version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 */

package unikl.disco.numbers;

import org.apache.commons.math3.fraction.Fraction;

import unikl.disco.nc.CalculatorConfig.NumClass;

/**
 * Wrapper class around org.apache.commons.math3.fraction.Fraction
 * introducing special values like positive / negative infinity and NaN
 * as well as operators like min, max, ==, >, >=, <, and <= that are
 * not part of Fraction but needed by the network calculator.
 * 
 * For the ease of converting from the primitive data type double
 * to Fraction objects, copy by value semantic are is applied. 
 * 
 * @author Steffen Bondorf
 *
 */
public class NumFraction extends Num {
    public final NumClass num_class = NumClass.FRACTION;

    private Fraction value = new Fraction(0.0);

    // Unfortunately you cannot give the constructor the double value 0.0000001
    private static final Fraction EPSILON = new Fraction(1, 1000000);

    // Fraction is based in Integer and thus there's no infinity (and Fraction is prone to overflows as well)
    public static final NumFraction POSITIVE_INFINITY = createPositiveInfinity();
    public static final NumFraction NEGATIVE_INFINITY = createNegativeInfinity();
    public static final NumFraction NaN = createNaN();
    public static final NumFraction ZERO = createZero();

    private NumFraction() {
    }

    public NumFraction(double value) {
        this.value = new Fraction(value);
        checkInftyNaN();
    }

    public NumFraction(String num_str) throws Exception {
        if (num_str.equals("Infinity")) {
            value = POSITIVE_INFINITY.value;
        } else {
            value = new Fraction(Num.parse(num_str).doubleValue());
            checkInftyNaN();
        }
    }

    public NumFraction(int num) {
        value = new Fraction(num);
        checkInftyNaN();
    }

    public NumFraction(int num, int den) {
        value = new Fraction(num, den);
        checkInftyNaN();
    }

    public NumFraction(NumFraction num) {
        value = new Fraction(num.value.getNumerator(), num.value.getDenominator());
        checkInftyNaN();
    }

    private NumFraction(Fraction frac) {
        value = new Fraction(frac.getNumerator(), frac.getDenominator());
        checkInftyNaN();
    }

    protected NumFraction(SpecialValue indicator) {
        switch (indicator) {
        case POSITIVE_INFINITY:
            instantiatePositiveInfinity();
            break;
        case NEGATIVE_INFINITY:
            instantiateNegativeInfinity();
            break;
        case NaN:
            instantiateNaN();
            break;
        case ZERO:
            instantiateZero();
            break;
        }
    }

    private void checkInftyNaN() {
        if (value.compareTo(NaN.value) == 0) {
            isNaN = true;
            isPosInfty = false;
            isNegInfty = false;
            return;
        }
        if (value.compareTo(POSITIVE_INFINITY.value) == 0) {
            isNaN = false;
            isPosInfty = true;
            isNegInfty = false;
            return;
        }
        if (value.compareTo(NEGATIVE_INFINITY.value) == 0) {
            isNaN = false;
            isPosInfty = false;
            isNegInfty = true;
            return;
        }
    }

    public static NumFraction createPositiveInfinity() {
        NumFraction pos_infty = new NumFraction();
        pos_infty.instantiatePositiveInfinity();
        return pos_infty;
    }

    private void instantiatePositiveInfinity() {
        value = new Fraction(Integer.MAX_VALUE);
        isNaN = false;
        isPosInfty = true;
        isNegInfty = false;
    }

    public static NumFraction createNegativeInfinity() {
        NumFraction neg_infty = new NumFraction();
        neg_infty.instantiateNegativeInfinity();
        return neg_infty;
    }

    private void instantiateNegativeInfinity() {
        value = new Fraction(Integer.MIN_VALUE);
        isNaN = false;
        isPosInfty = false;
        isNegInfty = true;
    }

    public static NumFraction createNaN() {
        NumFraction nan = new NumFraction();
        nan.instantiateNaN();
        return nan;
    }

    private void instantiateNaN() {
        value = new Fraction(Double.NaN);
        isNaN = true;
        isPosInfty = false;
        isNegInfty = false;
    }

    public static NumFraction createZero() {
        NumFraction zero = new NumFraction();
        zero.instantiateZero();
        return zero;
    }

    private void instantiateZero() {
        value = new Fraction(0.0);
        isNaN = false;
        isPosInfty = false;
        isNegInfty = false;
    }

    protected static NumFraction createEpsilon() {
        return new NumFraction(EPSILON);
    }

    // In order to simplify the transition from the primitive data type double to
    // a rational number object, these functions emulate copy by value for objects that
    // typically inhibit copy by reference
    protected static NumFraction add(NumFraction num1, NumFraction num2) {
        // May throw MathArithmeticException due to integer overflow
        return new NumFraction(num1.value.add(num2.value));
    }

    protected static NumFraction sub(NumFraction num1, NumFraction num2) {
        // May throw MathArithmeticException due to integer overflow
        return new NumFraction(num1.value.subtract(num2.value));
    }

    protected static NumFraction mult(NumFraction num1, NumFraction num2) {
        // May throw MathArithmeticException due to integer overflow
        return new NumFraction(num1.value.multiply(num2.value));
    }

    protected static NumFraction div(NumFraction num1, NumFraction num2) {
        if (num2.value.getNumerator() == 0) {
            return createPositiveInfinity();
        } else {
            return new NumFraction(num1.value.divide(num2.value));
        }
    }

    protected static NumFraction diff(NumFraction num1, NumFraction num2) {
        return sub(max(num1, num2), min(num1, num2));
    }

    protected static NumFraction max(NumFraction num1, NumFraction num2) {
        if (num1.value.compareTo(num2.value) >= 0) {
            return num1;
        } else {
            return num2;
        }
    }

    protected static NumFraction min(NumFraction num1, NumFraction num2) {
        if (num1.value.compareTo(num2.value) <= 0) {
            return num1;
        } else {
            return num2;
        }
    }

    protected static NumFraction abs(NumFraction num) {
        return new NumFraction(num.value.abs());
    }

    protected static NumFraction negate(NumFraction num) {
        return new NumFraction(num.value.negate());
    }

    public boolean greater(Num num2) {
        if (this.isNaN || num2.isNaN) {
            return false;
        }

        if (num2.isPosInfty) {
            return false;
        }
        if (this.isPosInfty) {
            return true;
        }

        if (this.isNegInfty) {
            return false;
        }
        if (num2.isNegInfty) {
            return true;
        }

        if (this.value.compareTo(((NumFraction) num2).value) > 0) {
            return true;
        } else {
            return false;
        }
    }

    public boolean ge(Num num2) {
        if (this.isNaN || num2.isNaN) {
            return false;
        }

        if (this.isPosInfty) {
            return true;
        }
        if (num2.isPosInfty) {
            return false;
        }

        if (num2.isNegInfty) {
            return true;
        }
        if (this.isNegInfty) {
            return false;
        }

        if (this.value.compareTo(((NumFraction) num2).value) >= 0) {
            return true;
        } else {
            return false;
        }
    }

    public boolean less(Num num2) {
        if (this.isNaN || num2.isNaN) {
            return false;
        }

        if (this.isPosInfty) {
            return false;
        }
        if (num2.isPosInfty) {
            return true;
        }

        if (num2.isNegInfty) {
            return false;
        }
        if (this.isNegInfty) {
            return true;
        }

        if (this.value.compareTo(((NumFraction) num2).value) < 0) {
            return true;
        } else {
            return false;
        }
    }

    public boolean le(Num num2) {
        if (this.isNaN || num2.isNaN) {
            return false;
        }

        if (num2.isPosInfty) {
            return true;
        }
        if (this.isPosInfty) {
            return false;
        }

        if (this.isNegInfty) {
            return true;
        }
        if (num2.isNegInfty) {
            return false;
        }

        if (this.value.compareTo(((NumFraction) num2).value) <= 0) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public double doubleValue() {
        if (this.isNaN) {
            return Double.NaN;
        }
        if (this.isPosInfty) {
            return Double.POSITIVE_INFINITY;
        }
        if (this.isNegInfty) {
            return Double.NEGATIVE_INFINITY;
        }
        return value.doubleValue();
    }

    @Override
    public Num copy() {
        if (this.isNaN) {
            return createNaN();
        }
        if (this.isPosInfty) {
            return createPositiveInfinity();
        }
        if (this.isNegInfty) {
            return createNegativeInfinity();
        }

        return new NumFraction(this.value.getNumerator(), this.value.getDenominator());
    }

    @Override
    public boolean equals(double num2) {
        if (Double.isNaN(num2)) {
            return this.isNaN;
        }
        if (num2 == Double.POSITIVE_INFINITY) {
            return this.isPosInfty;
        }
        if (num2 == Double.NEGATIVE_INFINITY) {
            return this.isNegInfty;
        }

        return equals(new NumFraction(num2));
    }

    public boolean equals(NumFraction num2) {
        if (this.isNaN & num2.isNaN) {
            return true;
        }
        if (this.isPosInfty & num2.isPosInfty) {
            return true;
        }
        if (this.isNegInfty & num2.isNegInfty) {
            return true;
        }

        if (this.value.compareTo(num2.value) == 0) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public boolean equals(Object num2) {
        if (num2 == null) {
            return true;
        }

        NumFraction num2_Num;
        try {
            num2_Num = (NumFraction) num2;
            return equals(num2_Num);
        } catch (ClassCastException e) {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return value.hashCode();
    }

    @Override
    public String toString() {
        if (this.isNaN) {
            return "NaN";
        }
        if (this.isPosInfty) {
            return "Infinity";
        }
        if (this.isNegInfty) {
            return "-Infinity";
        }

        return value.toString();
    }
}