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.Decimal6f;
036import org.decimal4j.immutable.Decimal12f;
037import org.decimal4j.immutable.Decimal13f;
038import org.decimal4j.immutable.Decimal14f;
039import org.decimal4j.immutable.Decimal15f;
040import org.decimal4j.immutable.Decimal16f;
041import org.decimal4j.immutable.Decimal17f;
042import org.decimal4j.immutable.Decimal18f;
043import org.decimal4j.mutable.MutableDecimal0f;
044import org.decimal4j.mutable.MutableDecimal1f;
045import org.decimal4j.mutable.MutableDecimal2f;
046import org.decimal4j.mutable.MutableDecimal3f;
047import org.decimal4j.mutable.MutableDecimal4f;
048import org.decimal4j.mutable.MutableDecimal5f;
049import org.decimal4j.mutable.MutableDecimal6f;
050import org.decimal4j.scale.Scale12f;
051
052/**
053 * A {@code Multipliable12f} encapsulates a Decimal of scale 12 and facilitates
054 * exact typed multiplication. The multipliable object acts as first factor in the multiplication
055 * and provides a set of overloaded methods for different scales. Each one of those methods 
056 * delivers a different result scale which represents the appropriate scale for the product of
057 * an exact multiplication.
058 * <p>
059 * A {@code Multipliable12f} object is returned by {@link Decimal12f#multiplyExact()},
060 * hence an exact typed multiplication can be written as:
061 * <pre>
062 * Decimal12f value = ... //some value
063 * Decimal14f product = value.multiplyExact().by(Decimal2f.FIVE);
064 * </pre>
065 */
066public final class Multipliable12f {
067        
068        private final Decimal<Scale12f> value;
069        
070        /**
071         * Constructor with Decimal value to be encapsulated.
072         * @param value the decimal value to be wrapped as a multipliable object
073         */
074        public Multipliable12f(Decimal<Scale12f> value) {
075                this.value = Objects.requireNonNull(value, "value cannot be null");
076        }
077        
078        /**
079         * Returns the value underlying this Multipliable12f.
080         * @return the Decimal value wrapped by this multipliable object
081         */
082        public Decimal<Scale12f> getValue() {
083                return value;
084        }
085
086        /**
087         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
088         * result is exact and has scale 12 which is the sum of the scales 
089         * of the Decimal that this multipliable object represents and the scale of
090         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
091         * product is out of the possible range for a {@code Decimal12f}.
092         * <p>
093         * Note that the result is <i>always</i> a new instance.
094         * 
095         * @param factor
096         *            the factor to multiply with the Decimal that this multipliable represents
097         * @return <code>(this * factor)</code>
098         * @throws ArithmeticException
099         *             if an overflow occurs and product is out of the possible
100         *             range for a {@code Decimal12f}
101         */
102        public Decimal12f by(Decimal0f factor) {
103                return Decimal12f.valueOf(this.value.multiplyExact(factor));
104        }
105        /**
106         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
107         * result is exact and has scale 12 which is the sum of the scales 
108         * of the Decimal that this multipliable object represents and the scale of
109         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
110         * product is out of the possible range for a {@code Decimal12f}.
111         * <p>
112         * Note that the result is <i>always</i> a new instance.
113         * 
114         * @param factor
115         *            the factor to multiply with the Decimal that this multipliable represents
116         * @return <code>(this * factor)</code>
117         * @throws ArithmeticException
118         *             if an overflow occurs and product is out of the possible
119         *             range for a {@code Decimal12f}
120         */
121        public Decimal12f by(MutableDecimal0f factor) {
122                return Decimal12f.valueOf(this.value.multiplyExact(factor));
123        }
124
125        /**
126         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
127         * result is exact and has scale 13 which is the sum of the scales 
128         * of the Decimal that this multipliable object represents and the scale of
129         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
130         * product is out of the possible range for a {@code Decimal13f}.
131         * <p>
132         * Note that the result is <i>always</i> a new instance.
133         * 
134         * @param factor
135         *            the factor to multiply with the Decimal that this multipliable represents
136         * @return <code>(this * factor)</code>
137         * @throws ArithmeticException
138         *             if an overflow occurs and product is out of the possible
139         *             range for a {@code Decimal13f}
140         */
141        public Decimal13f by(Decimal1f factor) {
142                return Decimal13f.valueOf(this.value.multiplyExact(factor));
143        }
144        /**
145         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
146         * result is exact and has scale 13 which is the sum of the scales 
147         * of the Decimal that this multipliable object represents and the scale of
148         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
149         * product is out of the possible range for a {@code Decimal13f}.
150         * <p>
151         * Note that the result is <i>always</i> a new instance.
152         * 
153         * @param factor
154         *            the factor to multiply with the Decimal that this multipliable represents
155         * @return <code>(this * factor)</code>
156         * @throws ArithmeticException
157         *             if an overflow occurs and product is out of the possible
158         *             range for a {@code Decimal13f}
159         */
160        public Decimal13f by(MutableDecimal1f factor) {
161                return Decimal13f.valueOf(this.value.multiplyExact(factor));
162        }
163
164        /**
165         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
166         * result is exact and has scale 14 which is the sum of the scales 
167         * of the Decimal that this multipliable object represents and the scale of
168         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
169         * product is out of the possible range for a {@code Decimal14f}.
170         * <p>
171         * Note that the result is <i>always</i> a new instance.
172         * 
173         * @param factor
174         *            the factor to multiply with the Decimal that this multipliable represents
175         * @return <code>(this * factor)</code>
176         * @throws ArithmeticException
177         *             if an overflow occurs and product is out of the possible
178         *             range for a {@code Decimal14f}
179         */
180        public Decimal14f by(Decimal2f factor) {
181                return Decimal14f.valueOf(this.value.multiplyExact(factor));
182        }
183        /**
184         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
185         * result is exact and has scale 14 which is the sum of the scales 
186         * of the Decimal that this multipliable object represents and the scale of
187         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
188         * product is out of the possible range for a {@code Decimal14f}.
189         * <p>
190         * Note that the result is <i>always</i> a new instance.
191         * 
192         * @param factor
193         *            the factor to multiply with the Decimal that this multipliable represents
194         * @return <code>(this * factor)</code>
195         * @throws ArithmeticException
196         *             if an overflow occurs and product is out of the possible
197         *             range for a {@code Decimal14f}
198         */
199        public Decimal14f by(MutableDecimal2f factor) {
200                return Decimal14f.valueOf(this.value.multiplyExact(factor));
201        }
202
203        /**
204         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
205         * result is exact and has scale 15 which is the sum of the scales 
206         * of the Decimal that this multipliable object represents and the scale of
207         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
208         * product is out of the possible range for a {@code Decimal15f}.
209         * <p>
210         * Note that the result is <i>always</i> a new instance.
211         * 
212         * @param factor
213         *            the factor to multiply with the Decimal that this multipliable represents
214         * @return <code>(this * factor)</code>
215         * @throws ArithmeticException
216         *             if an overflow occurs and product is out of the possible
217         *             range for a {@code Decimal15f}
218         */
219        public Decimal15f by(Decimal3f factor) {
220                return Decimal15f.valueOf(this.value.multiplyExact(factor));
221        }
222        /**
223         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
224         * result is exact and has scale 15 which is the sum of the scales 
225         * of the Decimal that this multipliable object represents and the scale of
226         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
227         * product is out of the possible range for a {@code Decimal15f}.
228         * <p>
229         * Note that the result is <i>always</i> a new instance.
230         * 
231         * @param factor
232         *            the factor to multiply with the Decimal that this multipliable represents
233         * @return <code>(this * factor)</code>
234         * @throws ArithmeticException
235         *             if an overflow occurs and product is out of the possible
236         *             range for a {@code Decimal15f}
237         */
238        public Decimal15f by(MutableDecimal3f factor) {
239                return Decimal15f.valueOf(this.value.multiplyExact(factor));
240        }
241
242        /**
243         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
244         * result is exact and has scale 16 which is the sum of the scales 
245         * of the Decimal that this multipliable object represents and the scale of
246         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
247         * product is out of the possible range for a {@code Decimal16f}.
248         * <p>
249         * Note that the result is <i>always</i> a new instance.
250         * 
251         * @param factor
252         *            the factor to multiply with the Decimal that this multipliable represents
253         * @return <code>(this * factor)</code>
254         * @throws ArithmeticException
255         *             if an overflow occurs and product is out of the possible
256         *             range for a {@code Decimal16f}
257         */
258        public Decimal16f by(Decimal4f factor) {
259                return Decimal16f.valueOf(this.value.multiplyExact(factor));
260        }
261        /**
262         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
263         * result is exact and has scale 16 which is the sum of the scales 
264         * of the Decimal that this multipliable object represents and the scale of
265         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
266         * product is out of the possible range for a {@code Decimal16f}.
267         * <p>
268         * Note that the result is <i>always</i> a new instance.
269         * 
270         * @param factor
271         *            the factor to multiply with the Decimal that this multipliable represents
272         * @return <code>(this * factor)</code>
273         * @throws ArithmeticException
274         *             if an overflow occurs and product is out of the possible
275         *             range for a {@code Decimal16f}
276         */
277        public Decimal16f by(MutableDecimal4f factor) {
278                return Decimal16f.valueOf(this.value.multiplyExact(factor));
279        }
280
281        /**
282         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
283         * result is exact and has scale 17 which is the sum of the scales 
284         * of the Decimal that this multipliable object represents and the scale of
285         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
286         * product is out of the possible range for a {@code Decimal17f}.
287         * <p>
288         * Note that the result is <i>always</i> a new instance.
289         * 
290         * @param factor
291         *            the factor to multiply with the Decimal that this multipliable represents
292         * @return <code>(this * factor)</code>
293         * @throws ArithmeticException
294         *             if an overflow occurs and product is out of the possible
295         *             range for a {@code Decimal17f}
296         */
297        public Decimal17f by(Decimal5f factor) {
298                return Decimal17f.valueOf(this.value.multiplyExact(factor));
299        }
300        /**
301         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
302         * result is exact and has scale 17 which is the sum of the scales 
303         * of the Decimal that this multipliable object represents and the scale of
304         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
305         * product is out of the possible range for a {@code Decimal17f}.
306         * <p>
307         * Note that the result is <i>always</i> a new instance.
308         * 
309         * @param factor
310         *            the factor to multiply with the Decimal that this multipliable represents
311         * @return <code>(this * factor)</code>
312         * @throws ArithmeticException
313         *             if an overflow occurs and product is out of the possible
314         *             range for a {@code Decimal17f}
315         */
316        public Decimal17f by(MutableDecimal5f factor) {
317                return Decimal17f.valueOf(this.value.multiplyExact(factor));
318        }
319
320        /**
321         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
322         * result is exact and has scale 18 which is the sum of the scales 
323         * of the Decimal that this multipliable object represents and the scale of
324         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
325         * product is out of the possible range for a {@code Decimal18f}.
326         * <p>
327         * Note that the result is <i>always</i> a new instance.
328         * 
329         * @param factor
330         *            the factor to multiply with the Decimal that this multipliable represents
331         * @return <code>(this * factor)</code>
332         * @throws ArithmeticException
333         *             if an overflow occurs and product is out of the possible
334         *             range for a {@code Decimal18f}
335         */
336        public Decimal18f by(Decimal6f factor) {
337                return Decimal18f.valueOf(this.value.multiplyExact(factor));
338        }
339        /**
340         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
341         * result is exact and has scale 18 which is the sum of the scales 
342         * of the Decimal that this multipliable object represents and the scale of
343         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
344         * product is out of the possible range for a {@code Decimal18f}.
345         * <p>
346         * Note that the result is <i>always</i> a new instance.
347         * 
348         * @param factor
349         *            the factor to multiply with the Decimal that this multipliable represents
350         * @return <code>(this * factor)</code>
351         * @throws ArithmeticException
352         *             if an overflow occurs and product is out of the possible
353         *             range for a {@code Decimal18f}
354         */
355        public Decimal18f by(MutableDecimal6f factor) {
356                return Decimal18f.valueOf(this.value.multiplyExact(factor));
357        }
358
359        
360        /**
361         * Returns a hash code for this <code>Multipliable12f</code> which happens to be the
362         * hash code of the underlying {@code Decimal12f} value.
363         * 
364         * @return a hash code value for this object
365         * @see Decimal#hashCode()
366         */
367        @Override
368        public int hashCode() {
369                return value.hashCode();
370        }
371
372        /**
373         * Compares this Multipliable12f to the specified object. The result is {@code true}
374         * if and only if the argument is a {@code Multipliable12f} with an equal underlying 
375         * {@link #getValue() value}.
376         * 
377         * @param obj
378         *            the object to compare with
379         * @return {@code true} if the argument is a {@code Multipliable12f} and if its value
380         *         is equal to this multipliables's value; {@code false} otherwise
381         * @see #getValue()
382         * @see Decimal#equals(Object)
383         */
384        @Override
385        public boolean equals(Object obj) {
386                if (this == obj) return true;
387                if (obj == null) return false;
388                if (getClass() != obj.getClass()) return false;
389                return value.equals(((Multipliable12f)obj).value);
390        }
391
392        /**
393         * Returns a string representation of this {@code Multipliable12f} which is
394         * simply the string representation of the underlying Decimal {@link #getValue() value}.
395         * 
396         * @return a {@code String} Decimal representation of this {@code Multipliable12f}'s
397         *         value with all the fraction digits (including trailing zeros)
398         * @see #getValue()
399         * @see Decimal#toString()
400         */
401        @Override
402        public String toString() {
403                return value.toString();
404        }
405}