001/* 002 * Units of Measurement Reference Implementation 003 * Copyright (c) 2005-2020, Units of Measurement project. 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 static javax.measure.Quantity.Scale.ABSOLUTE; 033import static javax.measure.Quantity.Scale.RELATIVE; 034 035import java.util.function.BinaryOperator; 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.AddConverter; 044import tech.units.indriya.internal.function.calc.Calculator; 045 046/** 047 * Implementation of {@link ComparableQuantity} that holds a Java {@link Number}, 048 * which represented this quantity's amount. 049 * <p> 050 * This object is immutable. 051 * <p> 052 * 053 * @see AbstractQuantity 054 * @see Quantity 055 * @see ComparableQuantity 056 * @param <Q> 057 * The type of the quantity. 058 * @author Andi Huber 059 * @author Werner Keil 060 * @version 1.2 061 * @since 1.0 062 * 063 */ 064public class NumberQuantity<Q extends Quantity<Q>> extends AbstractQuantity<Q> { 065 066 private static final long serialVersionUID = -6494337491031528402L; 067 068 private final Number value; 069 070 /** 071 * @since 2.0 072 */ 073 protected NumberQuantity(Number number, Unit<Q> unit, Scale sc) { 074 super(unit, sc); 075 value = number; 076 } 077 078 protected NumberQuantity(Number number, Unit<Q> unit) { 079 this(number, unit, ABSOLUTE); 080 } 081 082 @Override 083 public ComparableQuantity<Q> add(Quantity<Q> that) { 084 return addition(that, (thisValueInSystemUnit, thatValueInSystemUnit) -> 085 Calculator 086 .of(thisValueInSystemUnit) 087 .add(thatValueInSystemUnit) 088 .peek()); 089 } 090 091 @Override 092 public ComparableQuantity<Q> subtract(Quantity<Q> that) { 093 return addition(that, (thisValueInSystemUnit, thatValueInSystemUnit) -> 094 Calculator 095 .of(thisValueInSystemUnit) 096 .subtract(thatValueInSystemUnit) 097 .peek()); 098 } 099 100 @Override 101 public ComparableQuantity<?> divide(Quantity<?> that) { 102 final Number resultValueInThisUnit = Calculator 103 .of(getValue()) 104 .divide(that.getValue()) 105 .peek(); 106 return Quantities.getQuantity(resultValueInThisUnit, getUnit().divide(that.getUnit())); 107 } 108 109 @Override 110 public ComparableQuantity<Q> divide(Number divisor) { 111 final Number resultValueInThisUnit = Calculator 112 .of(getValue()) 113 .divide(divisor) 114 .peek(); 115 return Quantities.getQuantity(resultValueInThisUnit, getUnit()); 116 } 117 118 @Override 119 public ComparableQuantity<?> multiply(Quantity<?> that) { 120 final Number resultValueInThisUnit = Calculator 121 .of(getValue()) 122 .multiply(that.getValue()) 123 .peek(); 124 return Quantities.getQuantity(resultValueInThisUnit, getUnit().multiply(that.getUnit())); 125 } 126 127 @Override 128 public ComparableQuantity<Q> multiply(Number multiplier) { 129 final Number resultValueInThisUnit = Calculator 130 .of(getValue()) 131 .multiply(multiplier) 132 .peek(); 133 return Quantities.getQuantity(resultValueInThisUnit, getUnit()); 134 } 135 136 @Override 137 public ComparableQuantity<?> inverse() { 138 final Number resultValueInThisUnit = Calculator 139 .of(getValue()) 140 .reciprocal() 141 .peek(); 142 return Quantities.getQuantity(resultValueInThisUnit, getUnit().inverse()); 143 } 144 145 @Override 146 public Quantity<Q> negate() { 147 final Number resultValueInThisUnit = Calculator 148 .of(getValue()) 149 .negate() 150 .peek(); 151 return Quantities.getQuantity(resultValueInThisUnit, getUnit()); 152 } 153 154 @Override 155 public Number getValue() { 156 return value; 157 } 158 159 // -- HELPER 160 161 private ComparableQuantity<Q> addition(Quantity<Q> that, BinaryOperator<Number> operator) { 162 163 final Unit<Q> systemUnit = getUnit().getSystemUnit(); 164 final UnitConverter c1 = this.getUnit().getConverterTo(systemUnit); 165 final UnitConverter c2 = that.getUnit().getConverterTo(systemUnit); 166 167 boolean shouldConvertThis = shouldConvertQuantityForAddition(c1, getScale()); 168 boolean shouldConvertThat = shouldConvertQuantityForAddition(c2, that.getScale()); 169 final Number thisValueInSystemUnit = shouldConvertThis ? c1.convert(this.getValue()) : this.getValue(); 170 final Number thatValueInSystemUnit = shouldConvertThat ? c2.convert(that.getValue()) : this.getValue(); 171 172 final Number resultValueInSystemUnit = 173 operator.apply(thisValueInSystemUnit, thatValueInSystemUnit); 174 175 final Number resultValueInThisUnit = 176 shouldConvertThis || shouldConvertThat ? c1.inverse().convert(resultValueInSystemUnit) : resultValueInSystemUnit; 177 //TODO[220] scale not handled at all !!! 178 if (getScale().equals(that.getScale())) { 179 return Quantities.getQuantity(resultValueInThisUnit, getUnit(), getScale()); 180 } else { 181 return Quantities.getQuantity(resultValueInThisUnit, getUnit()); // becomes ABSOLUTE TODO, should it be ABSOLUTE? 182 } 183 } 184 185 private boolean shouldConvertQuantityForAddition(UnitConverter c1, Scale scale) { 186 return !(c1 instanceof AddConverter && scale.equals(RELATIVE)); 187 } 188 189}