blob: 0b6cc706add02070974ab68b81a7254761b42794 [file] [log] [blame]
/*
* $Header: /cvshome/build/org.osgi.util.measurement/src/org/osgi/util/measurement/Measurement.java,v 1.14 2006/07/11 00:54:06 hargrave Exp $
*
* Copyright (c) OSGi Alliance (2002, 2006). All Rights Reserved.
*
* Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.osgi.util.measurement;
/**
* Represents a value with an error, a unit and a time-stamp.
*
* <p>
* A <code>Measurement</code> object is used for maintaining the tuple of value,
* error, unit and time-stamp. The value and error are represented as doubles
* and the time is measured in milliseconds since midnight, January 1, 1970 UTC.
*
* <p>
* Mathematic methods are provided that correctly calculate taking the error
* into account. A runtime error will occur when two measurements are used in an
* incompatible way. E.g., when a speed (m/s) is added to a distance (m). The
* measurement class will correctly track changes in unit during multiplication
* and division, always coercing the result to the most simple form. See
* {@link Unit} for more information on the supported units.
*
* <p>
* Errors in the measurement class are absolute errors. Measurement errors
* should use the P95 rule. Actual values must fall in the range value +/- error
* 95% or more of the time.
*
* <p>
* A <code>Measurement</code> object is immutable in order to be easily shared.
*
* <p>
* Note: This class has a natural ordering that is inconsistent with equals. See
* {@link #compareTo}.
*
* @version $Revision: 1.14 $
*/
public class Measurement implements Comparable {
/* package private so it can be accessed by Unit */
final double value;
final double error;
final long time;
final Unit unit;
private transient String name;
/**
* Create a new <code>Measurement</code> object.
*
* @param value The value of the <code>Measurement</code>.
* @param error The error of the <code>Measurement</code>.
* @param unit The <code>Unit</code> object in which the value is measured. If
* this argument is <code>null</code>, then the unit will be set to
* {@link Unit#unity}.
* @param time The time measured in milliseconds since midnight, January 1,
* 1970 UTC.
*/
public Measurement(double value, double error, Unit unit, long time) {
this.value = value;
this.error = Math.abs(error);
this.unit = (unit != null) ? unit : Unit.unity;
this.time = time;
}
/**
* Create a new <code>Measurement</code> object with a time of zero.
*
* @param value The value of the <code>Measurement</code>.
* @param error The error of the <code>Measurement</code>.
* @param unit The <code>Unit</code> object in which the value is measured. If
* this argument is <code>null</code>, then the unit will be set to
* {@link Unit#unity}.
*/
public Measurement(double value, double error, Unit unit) {
this(value, error, unit, 0l);
}
/**
* Create a new <code>Measurement</code> object with an error of 0.0 and a
* time of zero.
*
* @param value The value of the <code>Measurement</code>.
* @param unit The <code>Unit</code> in which the value is measured. If this
* argument is <code>null</code>, then the unit will be set to
* {@link Unit#unity}.
*/
public Measurement(double value, Unit unit) {
this(value, 0.0d, unit, 0l);
}
/**
* Create a new <code>Measurement</code> object with an error of 0.0, a unit
* of {@link Unit#unity} and a time of zero.
*
* @param value The value of the <code>Measurement</code>.
*/
public Measurement(double value) {
this(value, 0.0d, null, 0l);
}
/**
* Returns the value of this <code>Measurement</code> object.
*
* @return The value of this <code>Measurement</code> object as a double.
*/
public final double getValue() {
return value;
}
/**
* Returns the error of this <code>Measurement</code> object. The error is
* always a positive value.
*
* @return The error of this <code>Measurement</code> as a double.
*/
public final double getError() {
return error;
}
/**
* Returns the <code>Unit</code> object of this <code>Measurement</code> object.
*
* @return The <code>Unit</code> object of this <code>Measurement</code> object.
*
* @see Unit
*/
public final Unit getUnit() {
return unit;
}
/**
* Returns the time at which this <code>Measurement</code> object was taken.
* The time is measured in milliseconds since midnight, January 1, 1970 UTC,
* or zero when not defined.
*
* @return The time at which this <code>Measurement</code> object was taken or
* zero.
*/
public final long getTime() {
return time;
}
/**
* Returns a new <code>Measurement</code> object that is the product of this
* object multiplied by the specified object.
*
* @param m The <code>Measurement</code> object that will be multiplied with
* this object.
* @return A new <code>Measurement</code> that is the product of this object
* multiplied by the specified object. The error and unit of the new
* object are computed. The time of the new object is set to the
* time of this object.
* @throws ArithmeticException If the <code>Unit</code> objects of this object
* and the specified object cannot be multiplied.
* @see Unit
*/
public Measurement mul(Measurement m) {
double mvalue = m.value;
return new Measurement(value * mvalue, Math.abs(value) * m.error
+ error * Math.abs(mvalue), unit.mul(m.unit), time);
}
/**
* Returns a new <code>Measurement</code> object that is the product of this
* object multiplied by the specified value.
*
* @param d The value that will be multiplied with this object.
* @param u The <code>Unit</code> of the specified value.
* @return A new <code>Measurement</code> object that is the product of this
* object multiplied by the specified value. The error and unit of
* the new object are computed. The time of the new object is set to
* the time of this object.
* @throws ArithmeticException If the units of this object and the specified
* value cannot be multiplied.
* @see Unit
*/
public Measurement mul(double d, Unit u) {
return new Measurement(value * d, error * Math.abs(d), unit.mul(u),
time);
}
/**
* Returns a new <code>Measurement</code> object that is the product of this
* object multiplied by the specified value.
*
* @param d The value that will be multiplied with this object.
* @return A new <code>Measurement</code> object that is the product of this
* object multiplied by the specified value. The error of the new
* object is computed. The unit and time of the new object is set to
* the unit and time of this object.
*/
public Measurement mul(double d) {
return new Measurement(value * d, error * Math.abs(d), unit, time);
}
/**
* Returns a new <code>Measurement</code> object that is the quotient of this
* object divided by the specified object.
*
* @param m The <code>Measurement</code> object that will be the divisor of
* this object.
* @return A new <code>Measurement</code> object that is the quotient of this
* object divided by the specified object. The error and unit of the
* new object are computed. The time of the new object is set to the
* time of this object.
* @throws ArithmeticException If the <code>Unit</code> objects of this object
* and the specified object cannot be divided.
* @see Unit
*/
public Measurement div(Measurement m) {
double mvalue = m.value;
return new Measurement(value / mvalue,
(Math.abs(value) * m.error + error * Math.abs(mvalue))
/ (mvalue * mvalue), unit.div(m.unit), time);
}
/**
* Returns a new <code>Measurement</code> object that is the quotient of this
* object divided by the specified value.
*
* @param d The value that will be the divisor of this object.
* @param u The <code>Unit</code> object of the specified value.
* @return A new <code>Measurement</code> that is the quotient of this object
* divided by the specified value. The error and unit of the new
* object are computed. The time of the new object is set to the
* time of this object.
* @throws ArithmeticException If the <code>Unit</code> objects of this object
* and the specified object cannot be divided.
* @see Unit
*/
public Measurement div(double d, Unit u) {
return new Measurement(value / d, error / Math.abs(d), unit.div(u),
time);
}
/**
* Returns a new <code>Measurement</code> object that is the quotient of this
* object divided by the specified value.
*
* @param d The value that will be the divisor of this object.
* @return A new <code>Measurement</code> object that is the quotient of this
* object divided by the specified value. The error of the new
* object is computed. The unit and time of the new object is set to
* the <code>Unit</code> and time of this object.
*/
public Measurement div(double d) {
return new Measurement(value / d, error / Math.abs(d), unit, time);
}
/**
* Returns a new <code>Measurement</code> object that is the sum of this
* object added to the specified object.
*
* The error and unit of the new object are computed. The time of the new
* object is set to the time of this object.
*
* @param m The <code>Measurement</code> object that will be added with this
* object.
* @return A new <code>Measurement</code> object that is the sum of this and
* m.
* @see Unit
* @throws ArithmeticException If the <code>Unit</code> objects of this object
* and the specified object cannot be added.
*/
public Measurement add(Measurement m) {
return new Measurement(value + m.value, error + m.error, unit
.add(m.unit), time);
}
/**
* Returns a new <code>Measurement</code> object that is the sum of this
* object added to the specified value.
*
* @param d The value that will be added with this object.
* @param u The <code>Unit</code> object of the specified value.
* @return A new <code>Measurement</code> object that is the sum of this
* object added to the specified value. The unit of the new object
* is computed. The error and time of the new object is set to the
* error and time of this object.
* @throws ArithmeticException If the <code>Unit</code> objects of this object
* and the specified value cannot be added.
* @see Unit
*/
public Measurement add(double d, Unit u) {
return new Measurement(value + d, error, unit.add(u), time);
}
/**
* Returns a new <code>Measurement</code> object that is the sum of this
* object added to the specified value.
*
* @param d The value that will be added with this object.
* @return A new <code>Measurement</code> object that is the sum of this
* object added to the specified value. The error, unit, and time of
* the new object is set to the error, <code>Unit</code> and time of
* this object.
*/
public Measurement add(double d) {
return new Measurement(value + d, error, unit, time);
}
/**
* Returns a new <code>Measurement</code> object that is the subtraction of
* the specified object from this object.
*
* @param m The <code>Measurement</code> object that will be subtracted from
* this object.
* @return A new <code>Measurement</code> object that is the subtraction of
* the specified object from this object. The error and unit of the
* new object are computed. The time of the new object is set to the
* time of this object.
* @throws ArithmeticException If the <code>Unit</code> objects of this object
* and the specified object cannot be subtracted.
* @see Unit
*/
public Measurement sub(Measurement m) {
return new Measurement(value - m.value, error + m.error, unit
.sub(m.unit), time);
}
/**
* Returns a new <code>Measurement</code> object that is the subtraction of
* the specified value from this object.
*
* @param d The value that will be subtracted from this object.
* @param u The <code>Unit</code> object of the specified value.
* @return A new <code>Measurement</code> object that is the subtraction of
* the specified value from this object. The unit of the new object
* is computed. The error and time of the new object is set to the
* error and time of this object.
* @throws ArithmeticException If the <code>Unit</code> objects of this object
* and the specified object cannot be subtracted.
* @see Unit
*/
public Measurement sub(double d, Unit u) {
return new Measurement(value - d, error, unit.sub(u), time);
}
/**
* Returns a new <code>Measurement</code> object that is the subtraction of
* the specified value from this object.
*
* @param d The value that will be subtracted from this object.
* @return A new <code>Measurement</code> object that is the subtraction of
* the specified value from this object. The error, unit and time of
* the new object is set to the error, <code>Unit</code> object and
* time of this object.
*/
public Measurement sub(double d) {
return new Measurement(value - d, error, unit, time);
}
/**
* Returns a <code>String</code> object representing this <code>Measurement</code>
* object.
*
* @return a <code>String</code> object representing this <code>Measurement</code>
* object.
*/
public String toString() {
if (name == null) {
StringBuffer sb = new StringBuffer();
sb.append(value);
if (error != 0.0d) {
sb.append(" +/- ");
sb.append(error);
}
String u = unit.toString();
if (u.length() > 0) {
sb.append(" ");
sb.append(u);
}
name = sb.toString();
}
return name;
}
/**
* Compares this object with the specified object for order. Returns a
* negative integer, zero, or a positive integer if this object is less
* than, equal to, or greater than the specified object.
*
* <p>
* Note: This class has a natural ordering that is inconsistent with equals.
* For this method, another <code>Measurement</code> object is considered
* equal if there is some <code>x</code> such that
*
* <pre>
* getValue() - getError() &lt;= x &lt;= getValue() + getError()
* </pre>
*
* for both <code>Measurement</code> objects being compared.
*
* @param obj The object to be compared.
* @return A negative integer, zero, or a positive integer if this object is
* less than, equal to, or greater than the specified object.
*
* @throws ClassCastException If the specified object is not of type
* <code>Measurement</code>.
* @throws ArithmeticException If the unit of the specified
* <code>Measurement</code> object is not equal to the <code>Unit</code>
* object of this object.
*/
public int compareTo(Object obj) {
if (this == obj) {
return 0;
}
Measurement that = (Measurement) obj;
if (!unit.equals(that.unit)) {
throw new ArithmeticException("Cannot compare " + this + " and "
+ that);
}
if (value == that.value) {
return 0;
}
if (value < that.value) {
if ((value + error) >= (that.value - that.error)) {
return 0;
}
else {
return -1;
}
}
else {
if ((value - error) <= (that.value + that.error)) {
return 0;
}
else {
return 1;
}
}
}
/**
* Returns a hash code value for this object.
*
* @return A hash code value for this object.
*/
public int hashCode() {
long bits = Double.doubleToLongBits(value + error);
return ((int) (bits ^ (bits >>> 32))) ^ unit.hashCode();
}
/**
* Returns whether the specified object is equal to this object. Two
* <code>Measurement</code> objects are equal if they have same value, error
* and <code>Unit</code>.
*
* <p>
* Note: This class has a natural ordering that is inconsistent with equals.
* See {@link #compareTo}.
*
* @param obj The object to compare with this object.
* @return <code>true</code> if this object is equal to the specified object;
* <code>false</code> otherwise.
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Measurement)) {
return false;
}
Measurement that = (Measurement) obj;
return (value == that.value) && (error == that.error)
&& unit.equals(that.unit);
}
}