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