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.internal.function.calc;
031
032import java.util.Objects;
033
034import tech.units.indriya.function.Calculus;
035import tech.units.indriya.spi.NumberSystem;
036
037/**
038 * Provides arithmetic on Java {@link Number}s utilizing a provided {@link NumberSystem}.    
039 * 
040 * @author Andi Huber
041 * @since 2.0
042 */
043public class Calculator {
044
045    /**
046     * Returns a new instance of a {@code Calculator} initialized with the default {@link NumberSystem}, 
047     * as set at {@link Calculus#currentNumberSystem()}
048     * <p>
049     * This implementation is *not* thread-safe, hence threads should not share instances of this. 
050     * @return a {@code Calculator} initialized with the default {@link NumberSystem} 
051     */
052    protected static Calculator getInstance() {
053        return new Calculator(Calculus.currentNumberSystem());
054    }
055
056    /**
057     * Shortcut for {@code getDefault().load(number)}. See {@link #getInstance()} and {@link #load(Number)}
058     * @param number
059     * @return default {@code Calculator} with {@code number} loaded into its accumulator
060     */
061    public static Calculator of(Number number) {
062        return getInstance().load(number);
063    }
064
065    private final NumberSystem ns;
066    private Number acc = 0;
067    
068    private Calculator(NumberSystem ns) {
069        this.ns = ns;
070    }
071
072    /**
073     * Loads {@code number} into this {@code Calculator}´s accumulator. 
074     * @param number
075     * @return self
076     */
077    public Calculator load(Number number) {
078        Objects.requireNonNull(number);
079        this.acc = ns.narrow(number);
080        return this;
081    }
082    
083    /**
084     * Adds {@code number} to this {@code Calculator}´s accumulator, 
085     * then stores the result in the accumulator.
086     * @param number
087     * @return self
088     */
089    public Calculator add(Number number) {
090        Objects.requireNonNull(number);
091        acc = ns.add(acc, ns.narrow(number));    
092        return this;
093    }
094
095    /**
096     * Subtracts {@code number} from this {@code Calculator}´s accumulator, 
097     * then stores the result in the accumulator.
098     * @param number
099     * @return self
100     */
101    public Calculator subtract(Number number) {
102        Objects.requireNonNull(number);
103        acc = ns.subtract(acc, ns.narrow(number));
104        return this;
105    }
106    
107    /**
108     * Multiplies {@code number} with this {@code Calculator}´s accumulator, 
109     * then stores the result in the accumulator.
110     * @param number
111     * @return self
112     */
113    public Calculator multiply(Number number) {
114        acc = ns.multiply(acc, ns.narrow(number));    
115        return this;
116    }
117
118    /**
119     * Divides this {@code Calculator}´s accumulator by {@code number}, 
120     * then stores the result in the accumulator.
121     * @param number
122     * @return self
123     */
124    public Calculator divide(Number number) {
125        acc = ns.divide(acc, ns.narrow(number));    
126        return this;
127    }
128    
129    /**
130     * Takes this {@code Calculator}´s accumulator to the integer power of {@code exponent},
131     * then stores the result in the accumulator.
132     * @param exponent
133     * @return self
134     */
135    public Calculator power(int exponent) {
136        acc = ns.power(acc, exponent);    
137        return this;
138    }
139    
140    /**
141     * Calculates the absolute value of this {@code Calculator}´s accumulator,
142     * then stores the result in the accumulator.
143     * @return self
144     */
145    public Calculator abs() {
146        acc = ns.abs(acc);
147        return this;
148    }
149
150    /**
151     * Calculates the additive inverse value of this {@code Calculator}´s accumulator,
152     * then stores the result in the accumulator.
153     * @return self
154     */
155    public Calculator negate() {
156        acc = ns.negate(acc);
157        return this;
158    }
159
160    /**
161     * Calculates the multiplicative inverse value of this {@code Calculator}´s accumulator,
162     * then stores the result in the accumulator.
163     * @return self
164     */
165    public Calculator reciprocal() {
166        acc = ns.reciprocal(acc);
167        return this;
168    }
169    
170    /**
171     * Calculates Euler's constant taken to the power of this {@code Calculator}´s accumulator,
172     * then stores the result in the accumulator.
173     * @return self
174     */
175    public Calculator exp() {
176        acc = ns.exp(acc);
177        return this;
178    }
179    
180    /**
181     * Calculates the natural logarithm of this {@code Calculator}´s accumulator,
182     * then stores the result in the accumulator.
183     * @return self
184     */
185    public Calculator log() {
186        acc = ns.log(acc);
187        return this;
188    }
189    
190    // -- TERMINALS
191    
192    /**
193     * Allows to 'peek' at this {@code Calculator}´s accumulator. The {@link Number} returned is narrowed
194     * to best represent the numerical value w/o loss of precision within the {@link NumberSystem} as 
195     * configured for this {@code Calculator} instance.
196     * @return a narrowed version of this {@code Calculator}´s accumulator
197     */
198    public Number peek() {
199        return ns.narrow(acc);
200    }
201    
202    /**
203     * @return whether this {@code Calculator}´s accumulator is less than ONE
204     */
205    public boolean isLessThanOne() {
206        return ns.isLessThanOne(acc);
207    }
208
209  
210    
211}