All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.osgi.util.measurement.Measurement Maven / Gradle / Ivy

/*
 * Copyright (c) OSGi Alliance (2002, 2013). 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.
 * 
 * 

* A {@code Measurement} 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. * *

* 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. * *

* 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. * *

* A {@code Measurement} object is immutable in order to be easily shared. * *

* Note: This class has a natural ordering that is inconsistent with equals. See * {@link #compareTo(Object)}. * * @Immutable * @author $Id: 5d6be0f87b34d62ad5671e13710ef52ea36abf0c $ */ public class Measurement implements Comparable { private final double value; private final double error; private final long time; private final Unit unit; private transient String name; private transient int hashCode; /** * Create a new {@code Measurement} object. * * @param value The value of the {@code Measurement}. * @param error The error of the {@code Measurement}. * @param unit The {@code Unit} object in which the value is measured. If * this argument is {@code null}, 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; name = null; hashCode = 0; } /** * Create a new {@code Measurement} object with a time of zero. * * @param value The value of the {@code Measurement}. * @param error The error of the {@code Measurement}. * @param unit The {@code Unit} object in which the value is measured. If * this argument is {@code null}, 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} object with an error of 0.0 and a time * of zero. * * @param value The value of the {@code Measurement}. * @param unit The {@code Unit} in which the value is measured. If this * argument is {@code null}, 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} 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}. */ public Measurement(double value) { this(value, 0.0d, null, 0l); } /** * Returns the value of this {@code Measurement} object. * * @return The value of this {@code Measurement} object as a double. */ public final double getValue() { return value; } /** * Returns the error of this {@code Measurement} object. The error is always * a positive value. * * @return The error of this {@code Measurement} as a double. */ public final double getError() { return error; } /** * Returns the {@code Unit} object of this {@code Measurement} object. * * @return The {@code Unit} object of this {@code Measurement} object. * * @see Unit */ public final Unit getUnit() { return unit; } /** * Returns the time at which this {@code Measurement} 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} object was taken or * zero. */ public final long getTime() { return time; } /** * Returns a new {@code Measurement} object that is the product of this * object multiplied by the specified object. * * @param m The {@code Measurement} object that will be multiplied with this * object. * @return A new {@code Measurement} 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} 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} 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} of the specified value. * @return A new {@code Measurement} 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} 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} 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} object that is the quotient of this * object divided by the specified object. * * @param m The {@code Measurement} object that will be the divisor of this * object. * @return A new {@code Measurement} 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} 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} 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} object of the specified value. * @return A new {@code Measurement} 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} 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} 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} 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} 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} 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} object that will be added with this * object. * @return A new {@code Measurement} object that is the sum of this and m. * @see Unit * @throws ArithmeticException If the {@code Unit} 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} 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} object of the specified value. * @return A new {@code Measurement} 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} 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} 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} 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} and time of this * object. */ public Measurement add(double d) { return new Measurement(value + d, error, unit, time); } /** * Returns a new {@code Measurement} object that is the subtraction of the * specified object from this object. * * @param m The {@code Measurement} object that will be subtracted from this * object. * @return A new {@code Measurement} 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} 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} 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} object of the specified value. * @return A new {@code Measurement} 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} 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} 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} 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} object and time of * this object. */ public Measurement sub(double d) { return new Measurement(value - d, error, unit, time); } /** * Returns a {@code String} object representing this {@code Measurement} * object. * * @return a {@code String} object representing this {@code Measurement} * object. */ public String toString() { String result = name; if (result == 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); } result = sb.toString(); name = result; } return result; } /** * 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. * *

* Note: This class has a natural ordering that is inconsistent with equals. * For this method, another {@code Measurement} object is considered equal * if there is some {@code x} such that * *

	 * getValue() - getError() <= x <= getValue() + getError()
	 * 
* * for both {@code Measurement} 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}. * @throws ArithmeticException If the unit of the specified * {@code Measurement} object is not equal to the {@code Unit} * 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); } int result = Double.compare(value, that.value); if (result == 0) { return 0; } if (result < 0) { if (Double.compare(value + error, that.value - that.error) >= 0) { return 0; } return -1; } if (Double.compare(value - error, that.value + that.error) <= 0) { return 0; } return 1; } /** * Returns a hash code value for this object. * * @return A hash code value for this object. */ public int hashCode() { int h = hashCode; if (h == 0) { long bits = Double.doubleToLongBits(value); h = 31 * 17 + ((int) (bits ^ (bits >>> 32))); bits = Double.doubleToLongBits(error); h = 31 * h + ((int) (bits ^ (bits >>> 32))); h = 31 * h + unit.hashCode(); hashCode = h; } return h; } /** * Returns whether the specified object is equal to this object. Two * {@code Measurement} objects are equal if they have same value, error and * {@code Unit}. * *

* Note: This class has a natural ordering that is inconsistent with equals. * See {@link #compareTo(Object)}. * * @param obj The object to compare with this object. * @return {@code true} if this object is equal to the specified object; * {@code false} otherwise. */ public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof Measurement)) { return false; } Measurement that = (Measurement) obj; return (Double.compare(value, that.value) == 0) && (Double.compare(error, that.error) == 0) && unit.equals(that.unit); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy