001/*
002 * The MIT License (MIT)
003 *
004 * Copyright (c) 2015-2023 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.arithmetic;
025
026import org.decimal4j.api.DecimalArithmetic;
027import org.decimal4j.truncate.OverflowMode;
028
029/**
030 * Helper class used by multiplication methods to handle special cases.
031 */
032enum SpecialMultiplicationResult {
033        /**
034         * {@code a*b} with {@code a==0} or {@code b==0} leading to {@code 0}
035         */
036        FACTOR_IS_ZERO {
037                @Override
038                final long multiply(DecimalArithmetic arithmetic, long uDecimal1, long uDecimal2) {
039                        return 0;
040                }
041        },
042        /**
043         * {@code a*b} with {@code a==1} leading to {@code b}
044         */
045        FACTOR_1_IS_ONE {
046                @Override
047                final long multiply(DecimalArithmetic arithmetic, long uDecimal1, long uDecimal2) {
048                        return uDecimal2;
049                }
050        },
051        /**
052         * {@code a*b} with {@code b==1} leading to {@code a}
053         */
054        FACTOR_2_IS_ONE {
055                @Override
056                final long multiply(DecimalArithmetic arithmetic, long uDecimal1, long uDecimal2) {
057                        return uDecimal1;
058                }
059        },
060        /**
061         * {@code a*b} with {@code a==-1} leading to {@code -b}
062         */
063        FACTOR_1_IS_MINUS_ONE {
064                @Override
065                final long multiply(DecimalArithmetic arithmetic, long uDecimal1, long uDecimal2) {
066                        return arithmetic.negate(uDecimal2);// we must go through arithmetic
067                                                                                                // because overflow is possible
068                }
069        },
070        /**
071         * {@code a*b} with {@code b==-1} leading to {@code -a}
072         */
073        FACTOR_2_IS_MINUS_ONE {
074                @Override
075                final long multiply(DecimalArithmetic arithmetic, long uDecimal1, long uDecimal2) {
076                        return arithmetic.negate(uDecimal1);// we must go through arithmetic
077                                                                                                // because overflow is possible
078                }
079        },
080        /**
081         * {@code a*b} with {@code a==b} leading to {@code a^2}
082         */
083        FACTORS_ARE_EQUAL {
084                @Override
085                final long multiply(DecimalArithmetic arithmetic, long uDecimal1, long uDecimal2) {
086                        return arithmetic.square(uDecimal1);
087                }
088        };
089
090        /**
091         * Performs the multiplication for this special multiplication result. The
092         * arithmetics overflow mode is considered.
093         * 
094         * @param arithmetic
095         *            the arithmetic associated with the values
096         * @param uDecimal1
097         *            the first factor
098         * @param uDecimal2
099         *            the second factor
100         * @return <code>uDecimal1 * uDecimal2</code>
101         * @throws ArithmeticException
102         *             if an overflow occurs and the arithmetic's
103         *             {@link OverflowMode} is set to throw an exception
104         */
105        abstract long multiply(DecimalArithmetic arithmetic, long uDecimal1, long uDecimal2);
106
107        /**
108         * Returns the special multiplication case if it is one and null otherwise.
109         * 
110         * @param arithmetic
111         *            the arithmetic object
112         * @param uDecimal1
113         *            the first factor
114         * @param uDecimal2
115         *            the second factor
116         * @return special case if found one and null otherwise
117         */
118        static final SpecialMultiplicationResult getFor(DecimalArithmetic arithmetic, long uDecimal1, long uDecimal2) {
119                if (uDecimal1 == 0 | uDecimal2 == 0) {
120                        return FACTOR_IS_ZERO;
121                }
122                final long one = arithmetic.one();
123                if (uDecimal1 == one) {
124                        return FACTOR_1_IS_ONE;
125                }
126                if (uDecimal2 == one) {
127                        return FACTOR_2_IS_ONE;
128                }
129                if (uDecimal1 == -one) {
130                        return FACTOR_1_IS_MINUS_ONE;
131                }
132                if (uDecimal2 == -one) {
133                        return FACTOR_2_IS_MINUS_ONE;
134                }
135                if (uDecimal1 == uDecimal2) {
136                        return FACTORS_ARE_EQUAL;
137                }
138                return null;
139        }
140}