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.Decimal15f;
034import org.decimal4j.immutable.Decimal16f;
035import org.decimal4j.immutable.Decimal17f;
036import org.decimal4j.immutable.Decimal18f;
037import org.decimal4j.mutable.MutableDecimal0f;
038import org.decimal4j.mutable.MutableDecimal1f;
039import org.decimal4j.mutable.MutableDecimal2f;
040import org.decimal4j.mutable.MutableDecimal3f;
041import org.decimal4j.scale.Scale15f;
042
043/**
044 * A {@code Multipliable15f} encapsulates a Decimal of scale 15 and facilitates
045 * exact typed multiplication. The multipliable object acts as first factor in the multiplication
046 * and provides a set of overloaded methods for different scales. Each one of those methods 
047 * delivers a different result scale which represents the appropriate scale for the product of
048 * an exact multiplication.
049 * <p>
050 * A {@code Multipliable15f} object is returned by {@link Decimal15f#multiplyExact()},
051 * hence an exact typed multiplication can be written as:
052 * <pre>
053 * Decimal15f value = ... //some value
054 * Decimal17f product = value.multiplyExact().by(Decimal2f.FIVE);
055 * </pre>
056 */
057public final class Multipliable15f {
058        
059        private final Decimal<Scale15f> value;
060        
061        /**
062         * Constructor with Decimal value to be encapsulated.
063         * @param value the decimal value to be wrapped as a multipliable object
064         */
065        public Multipliable15f(Decimal<Scale15f> value) {
066                this.value = Objects.requireNonNull(value, "value cannot be null");
067        }
068        
069        /**
070         * Returns the value underlying this Multipliable15f.
071         * @return the Decimal value wrapped by this multipliable object
072         */
073        public Decimal<Scale15f> getValue() {
074                return value;
075        }
076
077        /**
078         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
079         * result is exact and has scale 15 which is the sum of the scales 
080         * of the Decimal that this multipliable object represents and the scale of
081         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
082         * product is out of the possible range for a {@code Decimal15f}.
083         * <p>
084         * Note that the result is <i>always</i> a new instance.
085         * 
086         * @param factor
087         *            the factor to multiply with the Decimal that this multipliable represents
088         * @return <code>(this * factor)</code>
089         * @throws ArithmeticException
090         *             if an overflow occurs and product is out of the possible
091         *             range for a {@code Decimal15f}
092         */
093        public Decimal15f by(Decimal0f factor) {
094                return Decimal15f.valueOf(this.value.multiplyExact(factor));
095        }
096        /**
097         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
098         * result is exact and has scale 15 which is the sum of the scales 
099         * of the Decimal that this multipliable object represents and the scale of
100         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
101         * product is out of the possible range for a {@code Decimal15f}.
102         * <p>
103         * Note that the result is <i>always</i> a new instance.
104         * 
105         * @param factor
106         *            the factor to multiply with the Decimal that this multipliable represents
107         * @return <code>(this * factor)</code>
108         * @throws ArithmeticException
109         *             if an overflow occurs and product is out of the possible
110         *             range for a {@code Decimal15f}
111         */
112        public Decimal15f by(MutableDecimal0f factor) {
113                return Decimal15f.valueOf(this.value.multiplyExact(factor));
114        }
115
116        /**
117         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
118         * result is exact and has scale 16 which is the sum of the scales 
119         * of the Decimal that this multipliable object represents and the scale of
120         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
121         * product is out of the possible range for a {@code Decimal16f}.
122         * <p>
123         * Note that the result is <i>always</i> a new instance.
124         * 
125         * @param factor
126         *            the factor to multiply with the Decimal that this multipliable represents
127         * @return <code>(this * factor)</code>
128         * @throws ArithmeticException
129         *             if an overflow occurs and product is out of the possible
130         *             range for a {@code Decimal16f}
131         */
132        public Decimal16f by(Decimal1f factor) {
133                return Decimal16f.valueOf(this.value.multiplyExact(factor));
134        }
135        /**
136         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
137         * result is exact and has scale 16 which is the sum of the scales 
138         * of the Decimal that this multipliable object represents and the scale of
139         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
140         * product is out of the possible range for a {@code Decimal16f}.
141         * <p>
142         * Note that the result is <i>always</i> a new instance.
143         * 
144         * @param factor
145         *            the factor to multiply with the Decimal that this multipliable represents
146         * @return <code>(this * factor)</code>
147         * @throws ArithmeticException
148         *             if an overflow occurs and product is out of the possible
149         *             range for a {@code Decimal16f}
150         */
151        public Decimal16f by(MutableDecimal1f factor) {
152                return Decimal16f.valueOf(this.value.multiplyExact(factor));
153        }
154
155        /**
156         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
157         * result is exact and has scale 17 which is the sum of the scales 
158         * of the Decimal that this multipliable object represents and the scale of
159         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
160         * product is out of the possible range for a {@code Decimal17f}.
161         * <p>
162         * Note that the result is <i>always</i> a new instance.
163         * 
164         * @param factor
165         *            the factor to multiply with the Decimal that this multipliable represents
166         * @return <code>(this * factor)</code>
167         * @throws ArithmeticException
168         *             if an overflow occurs and product is out of the possible
169         *             range for a {@code Decimal17f}
170         */
171        public Decimal17f by(Decimal2f factor) {
172                return Decimal17f.valueOf(this.value.multiplyExact(factor));
173        }
174        /**
175         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
176         * result is exact and has scale 17 which is the sum of the scales 
177         * of the Decimal that this multipliable object represents and the scale of
178         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
179         * product is out of the possible range for a {@code Decimal17f}.
180         * <p>
181         * Note that the result is <i>always</i> a new instance.
182         * 
183         * @param factor
184         *            the factor to multiply with the Decimal that this multipliable represents
185         * @return <code>(this * factor)</code>
186         * @throws ArithmeticException
187         *             if an overflow occurs and product is out of the possible
188         *             range for a {@code Decimal17f}
189         */
190        public Decimal17f by(MutableDecimal2f factor) {
191                return Decimal17f.valueOf(this.value.multiplyExact(factor));
192        }
193
194        /**
195         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
196         * result is exact and has scale 18 which is the sum of the scales 
197         * of the Decimal that this multipliable object represents and the scale of
198         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
199         * product is out of the possible range for a {@code Decimal18f}.
200         * <p>
201         * Note that the result is <i>always</i> a new instance.
202         * 
203         * @param factor
204         *            the factor to multiply with the Decimal that this multipliable represents
205         * @return <code>(this * factor)</code>
206         * @throws ArithmeticException
207         *             if an overflow occurs and product is out of the possible
208         *             range for a {@code Decimal18f}
209         */
210        public Decimal18f by(Decimal3f factor) {
211                return Decimal18f.valueOf(this.value.multiplyExact(factor));
212        }
213        /**
214         * Returns a {@code Decimal} whose value is {@code (this * factor)}. The
215         * result is exact and has scale 18 which is the sum of the scales 
216         * of the Decimal that this multipliable object represents and the scale of
217         * the {@code factor} argument. An {@link ArithmeticException} is thrown if the 
218         * product is out of the possible range for a {@code Decimal18f}.
219         * <p>
220         * Note that the result is <i>always</i> a new instance.
221         * 
222         * @param factor
223         *            the factor to multiply with the Decimal that this multipliable represents
224         * @return <code>(this * factor)</code>
225         * @throws ArithmeticException
226         *             if an overflow occurs and product is out of the possible
227         *             range for a {@code Decimal18f}
228         */
229        public Decimal18f by(MutableDecimal3f factor) {
230                return Decimal18f.valueOf(this.value.multiplyExact(factor));
231        }
232
233        
234        /**
235         * Returns a hash code for this <code>Multipliable15f</code> which happens to be the
236         * hash code of the underlying {@code Decimal15f} value.
237         * 
238         * @return a hash code value for this object
239         * @see Decimal#hashCode()
240         */
241        @Override
242        public int hashCode() {
243                return value.hashCode();
244        }
245
246        /**
247         * Compares this Multipliable15f to the specified object. The result is {@code true}
248         * if and only if the argument is a {@code Multipliable15f} with an equal underlying 
249         * {@link #getValue() value}.
250         * 
251         * @param obj
252         *            the object to compare with
253         * @return {@code true} if the argument is a {@code Multipliable15f} and if its value
254         *         is equal to this multipliables's value; {@code false} otherwise
255         * @see #getValue()
256         * @see Decimal#equals(Object)
257         */
258        @Override
259        public boolean equals(Object obj) {
260                if (this == obj) return true;
261                if (obj == null) return false;
262                if (getClass() != obj.getClass()) return false;
263                return value.equals(((Multipliable15f)obj).value);
264        }
265
266        /**
267         * Returns a string representation of this {@code Multipliable15f} which is
268         * simply the string representation of the underlying Decimal {@link #getValue() value}.
269         * 
270         * @return a {@code String} Decimal representation of this {@code Multipliable15f}'s
271         *         value with all the fraction digits (including trailing zeros)
272         * @see #getValue()
273         * @see Decimal#toString()
274         */
275        @Override
276        public String toString() {
277                return value.toString();
278        }
279}