001/**
002 * The MIT License (MIT)
003 *
004 * Copyright (c) 2015-2016 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 division and inversion methods to handle special cases.
031 */
032enum SpecialDivisionResult {
033        /**
034         * {@code a/b} with {@code a==0, b!=0} leading to {@code 0/b=0}
035         */
036        DIVIDEND_IS_ZERO {
037                @Override
038                final long divide(DecimalArithmetic arithmetic, long uDecimalDividend, long uDecimalDivisor) {
039                        return 0;
040                }
041        },
042        /**
043         * {@code a/b} with {@code b==0} leading to an arithmetic exception
044         */
045        DIVISOR_IS_ZERO {
046                @Override
047                final long divide(DecimalArithmetic arithmetic, long uDecimalDividend, long uDecimalDivisor) {
048                        throw new ArithmeticException("Division by zero: " + arithmetic.toString(uDecimalDividend) + " / "
049                                        + arithmetic.toString(uDecimalDivisor));
050                }
051        },
052        /**
053         * {@code a/b} with {@code b==1} leading to {@code a/1=a}
054         */
055        DIVISOR_IS_ONE {
056                @Override
057                final long divide(DecimalArithmetic arithmetic, long uDecimalDividend, long uDecimalDivisor) {
058                        return uDecimalDividend;
059                }
060        },
061        /**
062         * {@code a/b} with {@code b==-1} resulting in {@code a/-1=-a}
063         */
064        DIVISOR_IS_MINUS_ONE {
065                @Override
066                final long divide(DecimalArithmetic arithmetic, long uDecimalDividend, long uDecimalDivisor) {
067                        return arithmetic.negate(uDecimalDividend);// we must go through
068                                                                                                                // arithmetic because
069                                                                                                                // overflow is possible
070                }
071        },
072        /**
073         * {@code a/b} with {@code a==b} resulting in {@code a/a=b/b=1}
074         */
075        DIVISOR_EQUALS_DIVIDEND {
076                @Override
077                final long divide(DecimalArithmetic arithmetic, long uDecimalDividend, long uDecimalDivisor) {
078                        return arithmetic.one();
079                }
080        },
081        /**
082         * {@code a/b} with {@code a==-b} resulting in {@code a/-a=-b/b=-1}
083         */
084        DIVISOR_EQUALS_MINUS_DIVIDEND {
085                @Override
086                final long divide(DecimalArithmetic arithmetic, long uDecimalDividend, long uDecimalDivisor) {
087                        return -arithmetic.one();
088                }
089        };
090
091        /**
092         * Performs the division for this special division result. The arithmetics
093         * overflow mode is considered.
094         * 
095         * @param arithmetic
096         *            the arithmetic associated with the values
097         * @param uDecimalDividend
098         *            the dividend
099         * @param uDecimalDivisor
100         *            the divisor
101         * @return <tt>uDecimalDividend / uDecimalDivisor</tt>
102         * @throws ArithmeticException
103         *             if {@code this==DIVISOR_IS_ZERO} or if an overflow occurs and
104         *             the arithmetic's {@link OverflowMode} is set to throw an
105         *             exception
106         */
107        abstract long divide(DecimalArithmetic arithmetic, long uDecimalDividend, long uDecimalDivisor);
108
109        /**
110         * Returns the special division case if it is one and null otherwise.
111         * 
112         * @param arithmetic
113         *            the arithmetic object
114         * @param uDecimalDividend
115         *            the dividend
116         * @param uDecimalDivisor
117         *            the divisor
118         * @return the special case if it is one and null otherwise
119         */
120        static final SpecialDivisionResult getFor(DecimalArithmetic arithmetic, long uDecimalDividend, long uDecimalDivisor) {
121                // NOTE: this must be the first case because 0/0 must also throw an
122                // exception!
123                if (uDecimalDivisor == 0) {
124                        return DIVISOR_IS_ZERO;
125                }
126                if (uDecimalDividend == 0) {
127                        return DIVIDEND_IS_ZERO;
128                }
129                final long one = arithmetic.one();
130                if (uDecimalDivisor == one) {
131                        return DIVISOR_IS_ONE;
132                }
133                if (uDecimalDivisor == -one) {
134                        return DIVISOR_IS_MINUS_ONE;
135                }
136                if (uDecimalDividend == uDecimalDivisor) {
137                        return DIVISOR_EQUALS_DIVIDEND;
138                }
139                if (uDecimalDividend == -uDecimalDivisor) {
140                        return DIVISOR_EQUALS_MINUS_DIVIDEND;
141                }
142                return null;
143        }
144}