001/*
002 * The MIT License (MIT)
003 *
004 * Copyright (c) 2015-2024 decimal4j (tools4j), Marco Terzer
005 *
006 * Permission is hereby granted, free of charge, to any person obtaining a copy
007 * of this software and associated documentation files (the "Software"), to deal
008 * in the Software without restriction, including without limitation the rights
009 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
010 * copies of the Software, and to permit persons to whom the Software is
011 * furnished to do so, subject to the following conditions:
012 *
013 * The above copyright notice and this permission notice shall be included in all
014 * copies or substantial portions of the Software.
015 *
016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
019 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
020 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
021 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
022 * SOFTWARE.
023 */
024package org.decimal4j.exact;
025
026import java.util.Objects;
027
028import org.decimal4j.api.Decimal;
029import org.decimal4j.immutable.Decimal0f;
030import org.decimal4j.immutable.Decimal1f;
031import org.decimal4j.immutable.Decimal2f;
032import org.decimal4j.immutable.Decimal3f;
033import org.decimal4j.immutable.Decimal4f;
034import org.decimal4j.immutable.Decimal5f;
035import org.decimal4j.immutable.Decimal13f;
036import org.decimal4j.immutable.Decimal14f;
037import org.decimal4j.immutable.Decimal15f;
038import org.decimal4j.immutable.Decimal16f;
039import org.decimal4j.immutable.Decimal17f;
040import org.decimal4j.immutable.Decimal18f;
041import org.decimal4j.mutable.MutableDecimal0f;
042import org.decimal4j.mutable.MutableDecimal1f;
043import org.decimal4j.mutable.MutableDecimal2f;
044import org.decimal4j.mutable.MutableDecimal3f;
045import org.decimal4j.mutable.MutableDecimal4f;
046import org.decimal4j.mutable.MutableDecimal5f;
047import org.decimal4j.scale.Scale13f;
048
049/**
050 * A {@code Multipliable13f} encapsulates a Decimal of scale 13 and facilitates
051 * exact typed multiplication. The multipliable object acts as first factor in the multiplication
052 * and provides a set of overloaded methods for different scales. Each one of those methods 
053 * delivers a different result scale which represents the appropriate scale for the product of
054 * an exact multiplication.
055 * <p>
056 * A {@code Multipliable13f} object is returned by {@link Decimal13f#multiplyExact()},
057 * hence an exact typed multiplication can be written as:
058 * <pre>
059 * Decimal13f value = ... //some value
060 * Decimal15f product = value.multiplyExact().by(Decimal2f.FIVE);
061 * </pre>
062 */
063public final class Multipliable13f {
064        
065        private final Decimal<Scale13f> value;
066        
067        /**
068         * Constructor with Decimal value to be encapsulated.
069         * @param value the decimal value to be wrapped as a multipliable object
070         */
071        public Multipliable13f(Decimal<Scale13f> value) {
072                this.value = Objects.requireNonNull(value, "value cannot be null");
073        }
074        
075        /**
076         * Returns the value underlying this Multipliable13f.
077         * @return the Decimal value wrapped by this multipliable object
078         */
079        public Decimal<Scale13f> getValue() {
080                return value;
081        }
082
083        /**
084         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
085         * result is exact and has scale 13 which is the sum of the scales 
086         * of the Decimal that this multipliable object represents and the scale of
087         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
088         * product is out of the possible range for a {@code Decimal13f}.
089         * <p>
090         * Note that the result is <i>always</i> a new instance.
091         * 
092         * @param factor
093         *            the factor to multiply with the Decimal that this multipliable represents
094         * @return <code>(this * factor)</code>
095         * @throws ArithmeticException
096         *             if an overflow occurs and product is out of the possible
097         *             range for a {@code Decimal13f}
098         */
099        public Decimal13f by(Decimal0f factor) {
100                return Decimal13f.valueOf(this.value.multiplyExact(factor));
101        }
102        /**
103         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
104         * result is exact and has scale 13 which is the sum of the scales 
105         * of the Decimal that this multipliable object represents and the scale of
106         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
107         * product is out of the possible range for a {@code Decimal13f}.
108         * <p>
109         * Note that the result is <i>always</i> a new instance.
110         * 
111         * @param factor
112         *            the factor to multiply with the Decimal that this multipliable represents
113         * @return <code>(this * factor)</code>
114         * @throws ArithmeticException
115         *             if an overflow occurs and product is out of the possible
116         *             range for a {@code Decimal13f}
117         */
118        public Decimal13f by(MutableDecimal0f factor) {
119                return Decimal13f.valueOf(this.value.multiplyExact(factor));
120        }
121
122        /**
123         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
124         * result is exact and has scale 14 which is the sum of the scales 
125         * of the Decimal that this multipliable object represents and the scale of
126         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
127         * product is out of the possible range for a {@code Decimal14f}.
128         * <p>
129         * Note that the result is <i>always</i> a new instance.
130         * 
131         * @param factor
132         *            the factor to multiply with the Decimal that this multipliable represents
133         * @return <code>(this * factor)</code>
134         * @throws ArithmeticException
135         *             if an overflow occurs and product is out of the possible
136         *             range for a {@code Decimal14f}
137         */
138        public Decimal14f by(Decimal1f factor) {
139                return Decimal14f.valueOf(this.value.multiplyExact(factor));
140        }
141        /**
142         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
143         * result is exact and has scale 14 which is the sum of the scales 
144         * of the Decimal that this multipliable object represents and the scale of
145         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
146         * product is out of the possible range for a {@code Decimal14f}.
147         * <p>
148         * Note that the result is <i>always</i> a new instance.
149         * 
150         * @param factor
151         *            the factor to multiply with the Decimal that this multipliable represents
152         * @return <code>(this * factor)</code>
153         * @throws ArithmeticException
154         *             if an overflow occurs and product is out of the possible
155         *             range for a {@code Decimal14f}
156         */
157        public Decimal14f by(MutableDecimal1f factor) {
158                return Decimal14f.valueOf(this.value.multiplyExact(factor));
159        }
160
161        /**
162         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
163         * result is exact and has scale 15 which is the sum of the scales 
164         * of the Decimal that this multipliable object represents and the scale of
165         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
166         * product is out of the possible range for a {@code Decimal15f}.
167         * <p>
168         * Note that the result is <i>always</i> a new instance.
169         * 
170         * @param factor
171         *            the factor to multiply with the Decimal that this multipliable represents
172         * @return <code>(this * factor)</code>
173         * @throws ArithmeticException
174         *             if an overflow occurs and product is out of the possible
175         *             range for a {@code Decimal15f}
176         */
177        public Decimal15f by(Decimal2f factor) {
178                return Decimal15f.valueOf(this.value.multiplyExact(factor));
179        }
180        /**
181         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
182         * result is exact and has scale 15 which is the sum of the scales 
183         * of the Decimal that this multipliable object represents and the scale of
184         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
185         * product is out of the possible range for a {@code Decimal15f}.
186         * <p>
187         * Note that the result is <i>always</i> a new instance.
188         * 
189         * @param factor
190         *            the factor to multiply with the Decimal that this multipliable represents
191         * @return <code>(this * factor)</code>
192         * @throws ArithmeticException
193         *             if an overflow occurs and product is out of the possible
194         *             range for a {@code Decimal15f}
195         */
196        public Decimal15f by(MutableDecimal2f factor) {
197                return Decimal15f.valueOf(this.value.multiplyExact(factor));
198        }
199
200        /**
201         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
202         * result is exact and has scale 16 which is the sum of the scales 
203         * of the Decimal that this multipliable object represents and the scale of
204         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
205         * product is out of the possible range for a {@code Decimal16f}.
206         * <p>
207         * Note that the result is <i>always</i> a new instance.
208         * 
209         * @param factor
210         *            the factor to multiply with the Decimal that this multipliable represents
211         * @return <code>(this * factor)</code>
212         * @throws ArithmeticException
213         *             if an overflow occurs and product is out of the possible
214         *             range for a {@code Decimal16f}
215         */
216        public Decimal16f by(Decimal3f factor) {
217                return Decimal16f.valueOf(this.value.multiplyExact(factor));
218        }
219        /**
220         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
221         * result is exact and has scale 16 which is the sum of the scales 
222         * of the Decimal that this multipliable object represents and the scale of
223         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
224         * product is out of the possible range for a {@code Decimal16f}.
225         * <p>
226         * Note that the result is <i>always</i> a new instance.
227         * 
228         * @param factor
229         *            the factor to multiply with the Decimal that this multipliable represents
230         * @return <code>(this * factor)</code>
231         * @throws ArithmeticException
232         *             if an overflow occurs and product is out of the possible
233         *             range for a {@code Decimal16f}
234         */
235        public Decimal16f by(MutableDecimal3f factor) {
236                return Decimal16f.valueOf(this.value.multiplyExact(factor));
237        }
238
239        /**
240         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
241         * result is exact and has scale 17 which is the sum of the scales 
242         * of the Decimal that this multipliable object represents and the scale of
243         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
244         * product is out of the possible range for a {@code Decimal17f}.
245         * <p>
246         * Note that the result is <i>always</i> a new instance.
247         * 
248         * @param factor
249         *            the factor to multiply with the Decimal that this multipliable represents
250         * @return <code>(this * factor)</code>
251         * @throws ArithmeticException
252         *             if an overflow occurs and product is out of the possible
253         *             range for a {@code Decimal17f}
254         */
255        public Decimal17f by(Decimal4f factor) {
256                return Decimal17f.valueOf(this.value.multiplyExact(factor));
257        }
258        /**
259         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
260         * result is exact and has scale 17 which is the sum of the scales 
261         * of the Decimal that this multipliable object represents and the scale of
262         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
263         * product is out of the possible range for a {@code Decimal17f}.
264         * <p>
265         * Note that the result is <i>always</i> a new instance.
266         * 
267         * @param factor
268         *            the factor to multiply with the Decimal that this multipliable represents
269         * @return <code>(this * factor)</code>
270         * @throws ArithmeticException
271         *             if an overflow occurs and product is out of the possible
272         *             range for a {@code Decimal17f}
273         */
274        public Decimal17f by(MutableDecimal4f factor) {
275                return Decimal17f.valueOf(this.value.multiplyExact(factor));
276        }
277
278        /**
279         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
280         * result is exact and has scale 18 which is the sum of the scales 
281         * of the Decimal that this multipliable object represents and the scale of
282         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
283         * product is out of the possible range for a {@code Decimal18f}.
284         * <p>
285         * Note that the result is <i>always</i> a new instance.
286         * 
287         * @param factor
288         *            the factor to multiply with the Decimal that this multipliable represents
289         * @return <code>(this * factor)</code>
290         * @throws ArithmeticException
291         *             if an overflow occurs and product is out of the possible
292         *             range for a {@code Decimal18f}
293         */
294        public Decimal18f by(Decimal5f factor) {
295                return Decimal18f.valueOf(this.value.multiplyExact(factor));
296        }
297        /**
298         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
299         * result is exact and has scale 18 which is the sum of the scales 
300         * of the Decimal that this multipliable object represents and the scale of
301         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
302         * product is out of the possible range for a {@code Decimal18f}.
303         * <p>
304         * Note that the result is <i>always</i> a new instance.
305         * 
306         * @param factor
307         *            the factor to multiply with the Decimal that this multipliable represents
308         * @return <code>(this * factor)</code>
309         * @throws ArithmeticException
310         *             if an overflow occurs and product is out of the possible
311         *             range for a {@code Decimal18f}
312         */
313        public Decimal18f by(MutableDecimal5f factor) {
314                return Decimal18f.valueOf(this.value.multiplyExact(factor));
315        }
316
317        
318        /**
319         * Returns a hash code for this <code>Multipliable13f</code> which happens to be the
320         * hash code of the underlying {@code Decimal13f} value.
321         * 
322         * @return a hash code value for this object
323         * @see Decimal#hashCode()
324         */
325        @Override
326        public int hashCode() {
327                return value.hashCode();
328        }
329
330        /**
331         * Compares this Multipliable13f to the specified object. The result is {@code true}
332         * if and only if the argument is a {@code Multipliable13f} with an equal underlying 
333         * {@link #getValue() value}.
334         * 
335         * @param obj
336         *            the object to compare with
337         * @return {@code true} if the argument is a {@code Multipliable13f} and if its value
338         *         is equal to this multipliables's value; {@code false} otherwise
339         * @see #getValue()
340         * @see Decimal#equals(Object)
341         */
342        @Override
343        public boolean equals(Object obj) {
344                if (this == obj) return true;
345                if (obj == null) return false;
346                if (getClass() != obj.getClass()) return false;
347                return value.equals(((Multipliable13f)obj).value);
348        }
349
350        /**
351         * Returns a string representation of this {@code Multipliable13f} which is
352         * simply the string representation of the underlying Decimal {@link #getValue() value}.
353         * 
354         * @return a {@code String} Decimal representation of this {@code Multipliable13f}'s
355         *         value with all the fraction digits (including trailing zeros)
356         * @see #getValue()
357         * @see Decimal#toString()
358         */
359        @Override
360        public String toString() {
361                return value.toString();
362        }
363}