blob: 6ef9bce9ae66e598fb02cfd3b768aebab0e672a8 [file] [log] [blame]
/**
* Copyright (c) 2005, 2011, Werner Keil, Ikayzo and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Werner Keil, Ikayzo and others - initial API and implementation
*/
package org.eclipse.uomo.units.impl.converter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import org.eclipse.uomo.units.AbstractConverter;
import javax.measure.UnitConverter;
/**
* <p> This class represents a converter multiplying numeric values by an
* exact scaling factor (represented as the quotient of two
* <code>BigInteger</code> numbers).</p>
*
* <p> Instances of this class are immutable.</p>
*
* @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
* @author <a href="mailto:uomo@catmedia.us">Werner Keil</a>
* @version 1.3 ($Revision: 212 $), $Date: 2010-09-13 23:50:44 +0200 (Mo, 13 Sep 2010) $
*/
public final class RationalConverter extends AbstractConverter {
/** The serialVersionUID */
private static final long serialVersionUID = 5313011404391445406L;
/**
* Holds the converter dividend.
*/
private final BigInteger dividend;
/**
* Holds the converter divisor (always positive).
*/
private final BigInteger divisor;
/**
* Creates a rational converter with the specified dividend and
* divisor.
*
* @param dividend the dividend.
* @param divisor the positive divisor.
* @throws IllegalArgumentException if <code>divisor &lt;= 0</code>
* @throws IllegalArgumentException if <code>dividend == divisor</code>
*/
public RationalConverter(BigInteger dividend, BigInteger divisor) {
if (divisor.compareTo(BigInteger.ZERO) <= 0)
throw new IllegalArgumentException("Negative or zero divisor");
if (dividend.equals(divisor))
throw new IllegalArgumentException("Would result in identity converter");
this.dividend = dividend; // Exact conversion.
this.divisor = divisor; // Exact conversion.
}
/**
* Creates a rational converter with the specified dividend and
* divisor.
*
* @param dividend the dividend.
* @param divisor the positive divisor.
* @throws IllegalArgumentException if <code>divisor &lt;= 0</code>
* @throws IllegalArgumentException if <code>dividend == divisor</code>
*/
public RationalConverter(long dividend, long divisor) {
this(BigInteger.valueOf(dividend), BigInteger.valueOf(divisor));
}
/**
* Returns the integer dividend for this rational converter.
*
* @return this converter dividend.
*/
public BigInteger getDividend() {
return dividend;
}
/**
* Returns the integer (positive) divisor for this rational converter.
*
* @return this converter divisor.
*/
public BigInteger getDivisor() {
return divisor;
}
@Override
public double convert(double value) {
return value * toDouble(dividend) / toDouble(divisor);
}
// Optimization of BigInteger.doubleValue() (implementation too inneficient).
private static double toDouble(BigInteger integer) {
return (integer.bitLength() < 64) ? integer.longValue() : integer.doubleValue();
}
@Override
public BigDecimal convert(BigDecimal value, MathContext ctx) throws ArithmeticException {
BigDecimal decimalDividend = new BigDecimal(dividend, 0);
BigDecimal decimalDivisor = new BigDecimal(divisor, 0);
return value.multiply(decimalDividend, ctx).divide(decimalDivisor, ctx);
}
@Override
public Number convert(Number value) {
if (value instanceof BigDecimal) {
return convert((BigDecimal) value, MathContext.DECIMAL128);
} else {
return convert(value.doubleValue());
}
}
@Override
public UnitConverter concatenate(UnitConverter converter) {
if (converter instanceof RationalConverter) {
RationalConverter that = (RationalConverter) converter;
BigInteger newDividend = this.getDividend().multiply(that.getDividend());
BigInteger newDivisor = this.getDivisor().multiply(that.getDivisor());
BigInteger gcd = newDividend.gcd(newDivisor);
newDividend = newDividend.divide(gcd);
newDivisor = newDivisor.divide(gcd);
return (newDividend.equals(BigInteger.ONE) && newDivisor.equals(BigInteger.ONE))
? IDENTITY : new RationalConverter(newDividend, newDivisor);
} else
return super.concatenate(converter);
}
@Override
public RationalConverter inverse() {
return dividend.signum() == -1 ? new RationalConverter(getDivisor().negate(), getDividend().negate())
: new RationalConverter(getDivisor(), getDividend());
}
@Override
public final String toString() {
return "RationalConverter("+ dividend + "," + divisor + ")";
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof RationalConverter))
return false;
RationalConverter that = (RationalConverter) obj;
return this.dividend.equals(that.dividend) &&
this.divisor.equals(that.divisor);
}
@Override
public int hashCode() {
return dividend.hashCode() + divisor.hashCode();
}
@Override
public boolean isLinear() {
return true;
}
}