001/*
002 * Units of Measurement Implementation for Java SE
003 * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM.
004 *
005 * All rights reserved.
006 *
007 * Redistribution and use in source and binary forms, with or without modification,
008 * are permitted provided that the following conditions are met:
009 *
010 * 1. Redistributions of source code must retain the above copyright notice,
011 *    this list of conditions and the following disclaimer.
012 *
013 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
014 *    and the following disclaimer in the documentation and/or other materials provided with the distribution.
015 *
016 * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products
017 *    derived from this software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
021 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
023 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
026 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package tec.uom.se;
031
032import java.math.BigDecimal;
033import java.math.BigInteger;
034import java.math.MathContext;
035import java.util.Comparator;
036import java.util.Objects;
037
038import javax.measure.Quantity;
039import javax.measure.Unit;
040import javax.measure.UnitConverter;
041import javax.measure.quantity.Dimensionless;
042
043import tec.uom.lib.common.function.UnitSupplier;
044import tec.uom.lib.common.function.ValueSupplier;
045import tec.uom.se.format.QuantityFormat;
046import tec.uom.se.function.NaturalOrder;
047import tec.uom.se.quantity.Quantities;
048
049/**
050 * <p>
051 * This class represents the immutable result of a scalar measurement stated in a known unit.
052 * </p>
053 *
054 * <p>
055 * To avoid any loss of precision, known exact quantities (e.g. physical constants) should not be created from <code>double</code> constants but from
056 * their decimal representation.<br/>
057 * <code>
058 *         public static final Quantity&lt;Velocity&gt; C = NumberQuantity.parse("299792458 m/s").asType(Velocity.class);
059 *         // Speed of Light (exact).
060 *    </code>
061 * </p>
062 * 
063 * <p>
064 * Quantities can be converted to different units.<br>
065 * <code>
066 *         Quantity&lt;Velocity&gt; milesPerHour = C.to(MILES_PER_HOUR); // Use double implementation (fast).
067 *         System.out.println(milesPerHour);
068 * 
069 *         &gt; 670616629.3843951 m/h
070 *     </code>
071 * </p>
072 * 
073 * <p>
074 * Applications may sub-class {@link AbstractQuantity} for particular quantity types.<br>
075 * <code>
076 *         // Quantity of type Mass based on double primitive types.<br>
077 * public class MassAmount extends AbstractQuantity&lt;Mass&gt; {<br>
078 * private final double kilograms; // Internal SI representation.<br>
079 * private Mass(double kg) { kilograms = kg; }<br>
080 * public static Mass of(double value, Unit&lt;Mass&gt; unit) {<br>
081 * return new Mass(unit.getConverterTo(SI.KILOGRAM).convert(value));<br>
082 * }<br>
083 * public Unit&lt;Mass&gt; getUnit() { return SI.KILOGRAM; }<br>
084 * public Double getValue() { return kilograms; }<br>
085 * ...<br>
086 * }<br>
087 * <p>
088 * // Complex numbers measurements.<br>
089 * public class ComplexQuantity
090 * &lt;Q extends Quantity&gt;extends AbstractQuantity
091 * &lt;Q&gt;{<br>
092 * public Complex getValue() { ... } // Assuming Complex is a Number.<br>
093 * ...<br>
094 * }<br>
095 * <br>
096 * // Specializations of complex numbers measurements.<br>
097 * public final class Current extends ComplexQuantity&lt;ElectricCurrent&gt; {...}<br>
098 * public final class Tension extends ComplexQuantity&lt;ElectricPotential&gt; {...} <br>
099 * </code>
100 * </p>
101 * 
102 * <p>
103 * All instances of this class shall be immutable.
104 * </p>
105 *
106 * @author <a href="mailto:werner@uom.technology">Werner Keil</a>
107 * @version 1.0.5, May 31, 2017
108 * @since 1.0
109 */
110@SuppressWarnings("unchecked")
111public abstract class AbstractQuantity<Q extends Quantity<Q>> implements ComparableQuantity<Q>, UnitSupplier<Q>, ValueSupplier<Number> {
112
113  /**
114     * 
115     */
116  private static final long serialVersionUID = 293852425369811882L;
117
118  private final Unit<Q> unit;
119
120  /**
121   * Holds a dimensionless quantity of none (exact).
122   */
123  public static final Quantity<Dimensionless> NONE = Quantities.getQuantity(0, AbstractUnit.ONE);
124
125  /**
126   * Holds a dimensionless quantity of one (exact).
127   */
128  public static final Quantity<Dimensionless> ONE = Quantities.getQuantity(1, AbstractUnit.ONE);
129
130  /**
131   * constructor.
132   */
133  protected AbstractQuantity(Unit<Q> unit) {
134    this.unit = unit;
135  }
136
137  /**
138   * Returns the numeric value of the quantity.
139   *
140   * @return the quantity value.
141   */
142  @Override
143  public abstract Number getValue();
144
145  /**
146   * Returns the measurement unit.
147   *
148   * @return the measurement unit.
149   */
150  @Override
151  public Unit<Q> getUnit() {
152    return unit;
153  }
154
155  /**
156   * Convenient method equivalent to {@link #to(javax.measure.unit.Unit) to(this.getUnit().toSI())}.
157   *
158   * @return this measure or a new measure equivalent to this measure but stated in SI units.
159   * @throws ArithmeticException
160   *           if the result is inexact and the quotient has a non-terminating decimal expansion.
161   */
162  public Quantity<Q> toSI() {
163    return to(this.getUnit().getSystemUnit());
164  }
165
166  /**
167   * Returns this measure after conversion to specified unit. The default implementation returns <code>Measure.valueOf(doubleValue(unit), unit)</code>
168   * . If this measure is already stated in the specified unit, then this measure is returned and no conversion is performed.
169   *
170   * @param unit
171   *          the unit in which the returned measure is stated.
172   * @return this measure or a new measure equivalent to this measure but stated in the specified unit.
173   * @throws ArithmeticException
174   *           if the result is inexact and the quotient has a non-terminating decimal expansion.
175   */
176  @Override
177  public ComparableQuantity<Q> to(Unit<Q> unit) {
178    if (unit.equals(this.getUnit())) {
179      return this;
180    }
181    UnitConverter t = getUnit().getConverterTo(unit);
182    Number convertedValue = t.convert(getValue());
183    return Quantities.getQuantity(convertedValue, unit);
184  }
185
186  /**
187   * Returns this measure after conversion to specified unit. The default implementation returns
188   * <code>Measure.valueOf(decimalValue(unit, ctx), unit)</code>. If this measure is already stated in the specified unit, then this measure is
189   * returned and no conversion is performed.
190   *
191   * @param unit
192   *          the unit in which the returned measure is stated.
193   * @param ctx
194   *          the math context to use for conversion.
195   * @return this measure or a new measure equivalent to this measure but stated in the specified unit.
196   * @throws ArithmeticException
197   *           if the result is inexact but the rounding mode is <code>UNNECESSARY</code> or <code>mathContext.precision == 0</code> and the quotient
198   *           has a non-terminating decimal expansion.
199   */
200  public Quantity<Q> to(Unit<Q> unit, MathContext ctx) {
201    if (unit.equals(this.getUnit())) {
202      return this;
203    }
204    return Quantities.getQuantity(decimalValue(unit, ctx), unit);
205  }
206
207  @Override
208  public boolean isGreaterThan(Quantity<Q> that) {
209    return this.compareTo(that) > 0;
210  }
211
212  @Override
213  public boolean isGreaterThanOrEqualTo(Quantity<Q> that) {
214    return this.compareTo(that) >= 0;
215  }
216
217  @Override
218  public boolean isLessThan(Quantity<Q> that) {
219    return this.compareTo(that) < 0;
220  }
221
222  @Override
223  public boolean isLessThanOrEqualTo(Quantity<Q> that) {
224    return this.compareTo(that) <= 0;
225  }
226
227  @Override
228  public boolean isEquivalentTo(Quantity<Q> that) {
229    return this.compareTo(that) == 0;
230  }
231
232  /**
233   * Compares this measure to the specified Measurement quantity. The default implementation compares the {@link AbstractQuantity#doubleValue(Unit)}
234   * of both this measure and the specified Measurement stated in the same unit (this measure's {@link #getUnit() unit}).
235   *
236   * @return a negative integer, zero, or a positive integer as this measure is less than, equal to, or greater than the specified Measurement
237   *         quantity.
238   * @see {@link NaturalOrder}
239   */
240  @Override
241  public int compareTo(Quantity<Q> that) {
242    final Comparator<Quantity<Q>> comparator = new NaturalOrder<>();
243    return comparator.compare(this, that);
244  }
245
246  /**
247   * Compares this quantity against the specified object for <b>strict</b> equality (same unit and same amount).
248   *
249   * <p>
250   * Similarly to the {@link BigDecimal#equals} method which consider 2.0 and 2.00 as different objects because of different internal scales,
251   * quantities such as <code>Quantities.getQuantity(3.0, KILOGRAM)</code> <code>Quantities.getQuantity(3, KILOGRAM)</code> and
252   * <code>Quantities.getQuantity("3 kg")</code> might not be considered equals because of possible differences in their implementations.
253   * </p>
254   *
255   * <p>
256   * To compare quantities stated using different units or using different amount implementations the {@link #compareTo compareTo} or
257   * {@link #equals(javax.measure.Quantity, double, javax.measure.unit.Unit) equals(Quantity, epsilon, epsilonUnit)} methods should be used.
258   * </p>
259   *
260   * @param obj
261   *          the object to compare with.
262   * @return <code>this.getUnit.equals(obj.getUnit())
263   *         && this.getValue().equals(obj.getValue())</code>
264   */
265  @Override
266  public boolean equals(Object obj) {
267    if (this == obj) {
268      return true;
269    }
270    if (obj instanceof AbstractQuantity<?>) {
271      AbstractQuantity<?> that = (AbstractQuantity<?>) obj;
272      return Objects.equals(getUnit(), that.getUnit()) && Objects.equals(getValue(), that.getValue());
273    }
274    return false;
275  }
276
277  /**
278   * Compares this quantity and the specified quantity to the given accuracy. Quantities are considered approximately equals if their absolute
279   * differences when stated in the same specified unit is less than the specified epsilon.
280   *
281   * @param that
282   *          the quantity to compare with.
283   * @param epsilon
284   *          the absolute error stated in epsilonUnit.
285   * @param epsilonUnit
286   *          the epsilon unit.
287   * @return <code>abs(this.doubleValue(epsilonUnit) - that.doubleValue(epsilonUnit)) &lt;= epsilon</code>
288   */
289  public boolean equals(AbstractQuantity<Q> that, double epsilon, Unit<Q> epsilonUnit) {
290    return Math.abs(this.doubleValue(epsilonUnit) - that.doubleValue(epsilonUnit)) <= epsilon;
291  }
292
293  /**
294   * Returns the hash code for this quantity.
295   *
296   * @return the hash code value.
297   */
298  @Override
299  public int hashCode() {
300    return Objects.hash(getUnit(), getValue());
301  }
302
303  public abstract boolean isBig();
304
305  /**
306   * Returns the <code>String</code> representation of this quantity. The string produced for a given quantity is always the same; it is not affected
307   * by locale. This means that it can be used as a canonical string representation for exchanging quantity, or as a key for a Hashtable, etc.
308   * Locale-sensitive quantity formatting and parsing is handled by the {@link MeasurementFormat} class and its subclasses.
309   *
310   * @return <code>UnitFormat.getInternational().format(this)</code>
311   */
312  @Override
313  public String toString() {
314    return String.valueOf(getValue()) + " " + String.valueOf(getUnit());
315  }
316
317  public abstract BigDecimal decimalValue(Unit<Q> unit, MathContext ctx) throws ArithmeticException;
318
319  public abstract double doubleValue(Unit<Q> unit) throws ArithmeticException;
320
321  public final int intValue(Unit<Q> unit) throws ArithmeticException {
322    long longValue = longValue(unit);
323    if ((longValue < Integer.MIN_VALUE) || (longValue > Integer.MAX_VALUE)) {
324      throw new ArithmeticException("Cannot convert " + longValue + " to int (overflow)");
325    }
326    return (int) longValue;
327  }
328
329  protected long longValue(Unit<Q> unit) throws ArithmeticException {
330    double result = doubleValue(unit);
331    if ((result < Long.MIN_VALUE) || (result > Long.MAX_VALUE)) {
332      throw new ArithmeticException("Overflow (" + result + ")");
333    }
334    return (long) result;
335  }
336
337  protected final float floatValue(Unit<Q> unit) {
338    return (float) doubleValue(unit);
339  }
340
341  @Override
342  public <T extends Quantity<T>, E extends Quantity<E>> ComparableQuantity<E> divide(Quantity<T> that, Class<E> asTypeQuantity) {
343
344    return divide(Objects.requireNonNull(that)).asType(Objects.requireNonNull(asTypeQuantity));
345
346  }
347
348  @Override
349  public <T extends Quantity<T>, E extends Quantity<E>> ComparableQuantity<E> multiply(Quantity<T> that, Class<E> asTypeQuantity) {
350    return multiply(Objects.requireNonNull(that)).asType(Objects.requireNonNull(asTypeQuantity));
351  }
352
353  @Override
354  public <T extends Quantity<T>> ComparableQuantity<T> inverse(Class<T> quantityClass) {
355    return inverse().asType(quantityClass);
356  }
357
358  /**
359   * Casts this quantity to a parameterized quantity of specified nature or throw a <code>ClassCastException</code> if the dimension of the specified
360   * quantity and its unit's dimension do not match. For example:<br/>
361   * <code>
362   *     Quantity<Length> length = AbstractQuantity.parse("2 km").asType(Length.class);
363   * </code>
364   *
365   * @param type
366   *          the quantity class identifying the nature of the quantity.
367   * @return this quantity parameterized with the specified type.
368   * @throws ClassCastException
369   *           if the dimension of this unit is different from the specified quantity dimension.
370   * @throws UnsupportedOperationException
371   *           if the specified quantity class does not have a public static field named "UNIT" holding the SI unit for the quantity.
372   * @see Unit#asType(Class)
373   */
374  public final <T extends Quantity<T>> ComparableQuantity<T> asType(Class<T> type) throws ClassCastException {
375    this.getUnit().asType(type); // Raises ClassCastException if dimension
376    // mismatches.
377    return (ComparableQuantity<T>) this;
378  }
379
380  /**
381   * Returns the quantity of unknown type corresponding to the specified representation. This method can be used to parse dimensionless quantities.<br/>
382   * <code>
383   *     Quatity<Dimensionless> proportion = AbstractQuantity.parse("0.234").asType(Dimensionless.class);
384   * </code>
385   *
386   * <p>
387   * Note: This method handles only {@link SimpleUnitFormat#getStandard standard} unit format. Locale-sensitive quantity parsing is currently not
388   * supported.
389   * </p>
390   *
391   * @param csq
392   *          the decimal value and its unit (if any) separated by space(s).
393   * @return <code>QuantityFormat.getInstance().parse(csq)</code>
394   */
395  public static Quantity<?> parse(CharSequence csq) {
396    return QuantityFormat.getInstance().parse(csq);
397  }
398
399  /**
400   * Utility class for number comparison and equality
401   */
402  protected static final class Equalizer {
403
404    /**
405     * Converts a number to {@link BigDecimal}
406     *
407     * @param value
408     *          the value to be converted
409     * @return the value converted
410     */
411    public static BigDecimal toBigDecimal(Number value) {
412      if (BigDecimal.class.isInstance(value)) {
413        return BigDecimal.class.cast(value);
414      } else if (BigInteger.class.isInstance(value)) {
415        return new BigDecimal(BigInteger.class.cast(value));
416      }
417      return BigDecimal.valueOf(value.doubleValue());
418    }
419
420    /**
421     * Check if the both value has equality number, in other words, 1 is equals to 1.0000 and 1.0.
422     * 
423     * If the first value is a <type>Number</type> of either <type>Double</type>, <type>Float</type>, <type>Integer</type>, <type>Long</type>,
424     * <type>Short</type> or <type>Byte</type> it is compared using the respective <code>*value()</code> method of <type>Number</type>. Otherwise it
425     * is checked, if {@link BigDecimal#compareTo(Object)} is equal to zero.
426     *
427     * @param valueA
428     *          the value a
429     * @param valueB
430     *          the value B
431     * @return {@link BigDecimal#compareTo(Object)} == zero
432     */
433    public static boolean hasEquality(Number valueA, Number valueB) {
434      Objects.requireNonNull(valueA);
435      Objects.requireNonNull(valueB);
436
437      if (valueA instanceof Double && valueB instanceof Double) {
438        return valueA.doubleValue() == valueB.doubleValue();
439      } else if (valueA instanceof Float && valueB instanceof Float) {
440        return valueA.floatValue() == valueB.floatValue();
441      } else if (valueA instanceof Integer && valueB instanceof Integer) {
442        return valueA.intValue() == valueB.intValue();
443      } else if (valueA instanceof Long && valueB instanceof Long) {
444        return valueA.longValue() == valueB.longValue();
445      } else if (valueA instanceof Short && valueB instanceof Short) {
446        return valueA.shortValue() == valueB.shortValue();
447      } else if (valueA instanceof Byte && valueB instanceof Byte) {
448        return valueA.byteValue() == valueB.byteValue();
449      }
450      return toBigDecimal(valueA).compareTo(toBigDecimal(valueB)) == 0;
451    }
452  }
453}