/* * Copyright (c) 2004, JSR-108 group (http://www.jcp.org/en/jsr/detail?id=108) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - Neither the name of the JSR-108 nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package javax.units; // J2SE direct dependencies import java.io.Serializable; /** *
This class represents a converter of numeric values.
*It is not required for sub-classes to be immutable * (e.g. currency converter).
* * @author Jean-Marie Dautelle */ public abstract class Converter implements Serializable { /** * Holds the identity converter. This converter does nothing * (IDENTITY.convert(x) == x
).
*/
public static final Converter IDENTITY = new Identity();
/**
* Default constructor.
*/
protected Converter() {}
/**
* Returns the inverse of this converter. If x
is a valid
* value, then x == inverse().convert(convert(x))
to within
* the accuracy of computer arithmetic.
*
* @return the inverse of this converter.
*/
public abstract Converter inverse();
/**
* Converts a double value.
*
* @param x the numeric value to convert.
* @return the converted numeric value.
* @throws ConversionException if an error occurs during conversion.
*/
public abstract double convert(double x) throws ConversionException;
/**
* Returns this converter derivative for the specified
* x
value. For linear converters, this method returns
* a constant (the linear factor) for all x
values.
*
* @param x the value for which the derivative is calculated.
* @return the derivative for the specified value.
*/
public abstract double derivative(double x);
/**
* Indicates if this converter is linear. A converter is linear if
* convert(u + v) == convert(u) + convert(v)
and
* convert(r * u) == r * convert(u)
.
*
* @return true
if this converter is linear;
* false
otherwise.
*/
public abstract boolean isLinear();
/**
* Indicates whether some other object is "equal to" this converter.
*
* @param obj the reference object with which to compare.
* @return true
if this object is a linear converter and this
* object is also a linear converter and both have same
* derivatives; false
otherwise.
*/
public boolean equals(Object obj) {
if (obj instanceof Converter) {
Converter that = (Converter) obj;
// Check equality to float precision (allows for some inaccuracies)
return this.isLinear() && that.isLinear() &&
(Float.floatToIntBits((float) this.derivative(0)) ==
Float.floatToIntBits((float) that.derivative(0)));
} else {
return false;
}
}
/**
* Returns a hash code value for this converter. Equals object have equal
* hash codes.
*
* @return this converter hash code value.
* @see #equals
*/
public int hashCode() {
return Float.floatToIntBits((float)derivative(0));
}
/**
* Concatenates this converter with another converter. The resulting
* converter is equivalent to first converting by the other converter,
* and then converting by this converter.
*
* @param converter the other converter.
* @return the concatenation of this converter with the other converter.
*/
public Converter concatenate(Converter converter) {
if (converter == IDENTITY) {
return this;
} else {
return new Compound(converter, this);
}
}
/**
* This inner class represents the identity converter (singleton).
*/
private static final class Identity extends Converter {
// Implements abstract method.
public Converter inverse() {
return this;
}
// Implements abstract method.
public double convert(double x) {
return x;
}
// Implements abstract method.
public double derivative(double x) {
return 1.0;
}
// Implements abstract method.
public boolean isLinear() {
return true;
}
// Overrides.
public Converter concatenate(Converter converter) {
return converter;
}
}
/**
* This inner class represents a compound converter.
*/
private static final class Compound extends Converter {
/**
* Holds the first converter.
*/
private final Converter _first;
/**
* Holds the second converter.
*/
private final Converter _second;
/**
* Creates a compound converter resulting from the combined
* transformation of the specified converters.
*
* @param first the first converter.
* @param second the second converter.
*/
private Compound(Converter first, Converter second) {
_first = first;
_second = second;
}
// Implements abstract method.
public Converter inverse() {
return new Compound(_second.inverse(), _first.inverse());
}
// Implements abstract method.
public double convert(double x) {
return _second.convert(_first.convert(x));
}
// Implements abstract method.
public double derivative(double x) {
return _first.derivative(x) * _second.derivative(_first.convert(x));
}
// Implements abstract method.
public boolean isLinear() {
return _first.isLinear() && _second.isLinear();
}
// Overrides.
public boolean equals(Object obj) {
return super.equals(obj) ||
( (obj instanceof Compound) &&
((Compound)obj)._first.equals(_first) &&
((Compound)obj)._second.equals(_second) );
}
}
}