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.quantity;
031
032import java.io.Serializable;
033import java.math.BigDecimal;
034import java.math.BigInteger;
035import java.util.Objects;
036
037import javax.measure.Quantity;
038import javax.measure.UnconvertibleException;
039import javax.measure.Unit;
040import javax.measure.UnitConverter;
041
042import tech.units.indriya.AbstractQuantity;
043import tech.units.indriya.ComparableQuantity;
044import tech.units.indriya.function.Calculus;
045
046/**
047 * An amount of quantity, implementation of {@link ComparableQuantity} that keep {@link Number} as possible otherwise converts to
048 * {@link DecimalQuantity}, this object is immutable.
049 *
050 * @see AbstractQuantity
051 * @see Quantity
052 * @see ComparableQuantity
053 * @param <Q>
054 *          The type of the quantity.
055 * @author otaviojava
056 * @author <a href="mailto:units@catmedia.us">Werner Keil</a>
057 * @version 1.0.1, $Date: 2017-05-28 $
058 * @since 1.0
059 */
060@SuppressWarnings({ "rawtypes", "unchecked" })
061public class NumberQuantity<Q extends Quantity<Q>> extends AbstractQuantity<Q> implements Serializable {
062
063  private static final long serialVersionUID = 7312161895652321241L;
064
065  private final Number value;
066
067  /**
068   * Indicates if this quantity is big.
069   */
070  private final boolean isBig;
071
072  protected NumberQuantity(Number number, Unit<Q> unit) {
073    super(unit);
074    value = number;
075    isBig = number instanceof BigDecimal || number instanceof BigInteger;
076  }
077
078  @Override
079  public double doubleValue(Unit<Q> unit) {
080    Unit<Q> myUnit = getUnit();
081    try {
082      UnitConverter converter = myUnit.getConverterTo(unit);
083      return converter.convert(getValue().doubleValue());
084    } catch (UnconvertibleException e) {
085      throw e;
086    }
087  }
088
089  @Override
090  public Number getValue() {
091    return value;
092  }
093
094  /**
095   * Indicates if this measured amount is a big number, i.E. BigDecimal or BigInteger. In all other cases this would be false.
096   *
097   * @return <code>true</code> if this quantity is big; <code>false</code> otherwise.
098   */
099  @Override
100  public boolean isBig() {
101    return isBig;
102  }
103
104  @Override
105  public ComparableQuantity<Q> add(Quantity<Q> that) {
106    return toDecimalQuantity().add(that);
107  }
108
109  @Override
110  public ComparableQuantity<?> multiply(Quantity<?> that) {
111    return toDecimalQuantity().multiply(that);
112  }
113
114  @Override
115  public ComparableQuantity<Q> multiply(Number that) {
116    return toDecimalQuantity().multiply(that);
117  }
118
119  @Override
120  public ComparableQuantity<?> divide(Quantity<?> that) {
121    return toDecimalQuantity().divide(that);
122  }
123
124  @Override
125  public ComparableQuantity<Q> divide(Number that) {
126    return toDecimalQuantity().divide(that);
127  }
128
129  @Override
130  public ComparableQuantity<Q> inverse() {
131
132    return new NumberQuantity((getValue() instanceof BigDecimal ? BigDecimal.ONE.divide((BigDecimal) getValue()) : 1d / getValue().doubleValue()),
133        getUnit().inverse());
134  }
135
136  @Override
137  public BigDecimal decimalValue(Unit<Q> unit) throws ArithmeticException {
138    return Calculus.toBigDecimal(value);
139  }
140
141  @Override
142  public ComparableQuantity<Q> subtract(Quantity<Q> that) {
143    return toDecimalQuantity().subtract(that);
144  }
145
146  private DecimalQuantity<Q> toDecimalQuantity() {
147    return new DecimalQuantity<>(BigDecimal.valueOf(value.doubleValue()), getUnit());
148  }
149
150  /**
151   * Returns the scalar quantity for the specified <code>long</code> stated in the specified unit.
152   *
153   * @param longValue
154   *          the quantity value.
155   * @param unit
156   *          the measurement unit.
157   * @return the corresponding <code>int</code> quantity.
158   */
159  public static <Q extends Quantity<Q>> AbstractQuantity<Q> of(long longValue, Unit<Q> unit) {
160    return new LongQuantity<Q>(longValue, unit);
161  }
162
163  /**
164   * Returns the scalar quantity for the specified <code>int</code> stated in the specified unit.
165   *
166   * @param intValue
167   *          the quantity value.
168   * @param unit
169   *          the measurement unit.
170   * @return the corresponding <code>int</code> quantity.
171   */
172  public static <Q extends Quantity<Q>> AbstractQuantity<Q> of(int intValue, Unit<Q> unit) {
173    return new IntegerQuantity<Q>(intValue, unit);
174  }
175
176  /**
177   * Returns the scalar quantity for the specified <code>short</code> stated in the specified unit.
178   *
179   * @param value
180   *          the quantity value.
181   * @param unit
182   *          the measurement unit.
183   * @return the corresponding <code>short</code> quantity.
184   */
185  public static <Q extends Quantity<Q>> AbstractQuantity<Q> of(short value, Unit<Q> unit) {
186    return new ShortQuantity<Q>(value, unit);
187  }
188
189  /**
190   * Returns the scalar quantity for the specified <code>byte</code> stated in the specified unit.
191   *
192   * @param value
193   *          the quantity value.
194   * @param unit
195   *          the measurement unit.
196   * @return the corresponding <code>byte</code> quantity.
197   */
198  public static <Q extends Quantity<Q>> AbstractQuantity<Q> of(byte value, Unit<Q> unit) {
199    return new ByteQuantity<Q>(value, unit);
200  }
201
202  /**
203   * Returns the scalar quantity for the specified <code>float</code> stated in the specified unit.
204   *
205   * @param floatValue
206   *          the measurement value.
207   * @param unit
208   *          the measurement unit.
209   * @return the corresponding <code>float</code> quantity.
210   */
211  public static <Q extends Quantity<Q>> AbstractQuantity<Q> of(float floatValue, Unit<Q> unit) {
212    return new FloatQuantity<Q>(floatValue, unit);
213  }
214
215  /**
216   * Returns the scalar quantity for the specified <code>double</code> stated in the specified unit.
217   *
218   * @param doubleValue
219   *          the measurement value.
220   * @param unit
221   *          the measurement unit.
222   * @return the corresponding <code>double</code> quantity.
223   */
224  public static <Q extends Quantity<Q>> AbstractQuantity<Q> of(double doubleValue, Unit<Q> unit) {
225    return new DoubleQuantity<Q>(doubleValue, unit);
226  }
227
228  @Override
229  public boolean equals(Object obj) {
230    if (this == obj) {
231      return true;
232    }
233    if (obj instanceof Quantity<?>) {
234      Quantity<?> that = (Quantity<?>) obj;
235      return Objects.equals(getUnit(), that.getUnit()) && Equalizer.hasEquality(value, that.getValue());
236    }
237    return false;
238  }
239
240}