| /* |
| * Copyright (c) OSGi Alliance (2002, 2016). 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} 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} 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(Object)}. |
| * |
| * @Immutable |
| * @author $Id$ |
| */ |
| public class Measurement implements Comparable<Object> { |
| 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. |
| */ |
| @Override |
| public String toString() { |
| String result = name; |
| if (result == null) { |
| StringBuilder sb = new StringBuilder(); |
| 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. |
| * |
| * <p> |
| * 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 |
| * |
| * <pre> |
| * getValue() - getError() <= x <= getValue() + getError() |
| * </pre> |
| * |
| * 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. |
| */ |
| @Override |
| 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. |
| */ |
| @Override |
| 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}. |
| * |
| * <p> |
| * 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. |
| */ |
| @Override |
| 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); |
| } |
| } |