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