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