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