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