/**
* The contents of this file are subject to the OpenMRS Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://license.openmrs.org
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* Copyright (C) OpenMRS, LLC. All Rights Reserved.
*/
package org.openmrs.module.reporting.common;
import java.io.Serializable;
import java.text.NumberFormat;
/**
* Represents a Fractional Number
*/
public class Fraction extends Number implements Comparable<Fraction>, Serializable {
public static final long serialVersionUID = 1L;
//***** PROPERTIES *****
private final int numerator;
private final int denominator;
//***** CONSTRUCTORS *****
/**
* Default Constructor
*/
public Fraction(int numerator, int denominator) {
this.numerator = numerator;
this.denominator = denominator;
}
//***** PROPERTY ACCESS *****
/**
* @return the numerator
*/
public int getNumerator() {
return numerator;
}
/**
* @return the denominator
*/
public int getDenominator() {
return denominator;
}
//***** STATIC METHODS *****
/**
* @should return the greatest common divisor between 2 numbers
*/
public static int gcd(int n1, int n2) {
if (n2 == 0) { return n1; }
return gcd(n2, n1 % n2);
}
//***** INSTANCE METHODS *****
/**
* @should return a new fraction reduced to lowest form
*/
public Fraction reduce() {
int gcd = gcd(numerator, denominator);
return new Fraction((int)numerator/gcd, (int)denominator/gcd);
}
/**
* @param decimalPlaces the number of decimal points to include
* @return this Fraction formatted as a percentage
* @should return a percentage to the correct precision
*/
public String toPercentString(int decimalPlaces) {
if (denominator == 0) { return "N/A"; }
NumberFormat nf = NumberFormat.getPercentInstance();
nf.setMaximumFractionDigits(decimalPlaces);
return nf.format(doubleValue());
}
/**
* @see Number#doubleValue()
*/
@Override
public double doubleValue() {
return (double)numerator / (double)denominator;
}
/**
* @see Number#floatValue()
*/
@Override
public float floatValue() {
return (float)doubleValue();
}
/**
* @see Number#intValue()
*/
@Override
public int intValue() {
return (int)doubleValue();
}
/**
* @see Number#longValue()
*/
@Override
public long longValue() {
return (long)doubleValue();
}
/**
* @see Comparable#compareTo(Object)
* @should compare two fractions numerically
*/
public int compareTo(Fraction that) {
long n1 = this.numerator * that.denominator;
long n2 = this.denominator * that.numerator;
return ((n1 < n2) ? -1 : (n1 > n2 ? 1 : 0));
}
/**
* @see Object#equals(Object)
* @should return true if two fractions represent the same numerical value
*/
@Override
public boolean equals(Object that) {
if (this == that) { return true; }
if (that != null && that instanceof Fraction) {
return this.compareTo((Fraction)that) == 0;
}
return false;
}
/**
* @see Object#hashCode()
*/
@Override
public int hashCode() {
Fraction f = this.reduce();
return 31 * (31 * 7 + f.getNumerator()) + f.getDenominator();
}
/**
* @see Object#toString()
* @should return a string representation of the fraction
* @should allow representation of fractions with 0 denominators
*/
@Override
public String toString() {
return toPercentString(1) + " (" + numerator + " / " + denominator + ")";
}
}