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