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.DecimalRounding;
028import org.decimal4j.truncate.OverflowMode;
029
030/**
031 * Provides static methods to invert a Decimal number, that is, to calculate
032 * {@code 1/x}.
033 */
034final class Invert {
035
036        /**
037         * Inverts the specified long value truncating the result if necessary.
038         * 
039         * @param lValue
040         *            the long value to invert
041         * @return <code>round<sub>DOWN</sub>(1/lValue)</code>
042         * @throws ArithmeticException
043         *             if {@code lValue == 0}
044         */
045        public static final long invertLong(long lValue) {
046                if (lValue == 0) {
047                        throw new ArithmeticException("Division by zero: " + lValue + "^-1");
048                }
049                if (lValue == 1) {
050                        return 1;
051                }
052                if (lValue == -1) {
053                        return -1;
054                }
055                return 0;
056        }
057
058        /**
059         * Inverts the specified long value rounding the result if necessary.
060         * 
061         * @param rounding
062         *            the rounding to apply if necessary
063         * @param lValue
064         *            the long value to invert
065         * @return <code>round(1/lValue)</code>
066         * @throws ArithmeticException
067         *             if {@code lValue == 0} or if
068         *             {@code roundingMode==UNNECESSARY} and rounding is necessary
069         */
070        public static final long invertLong(DecimalRounding rounding, long lValue) {
071                // special cases first
072                if (lValue == 0) {
073                        throw new ArithmeticException("Division by zero: " + lValue + "^-1");
074                }
075                if (lValue == 1) {
076                        return 1;
077                }
078                if (lValue == -1) {
079                        return -1;
080                }
081                return Rounding.calculateRoundingIncrementForDivision(rounding, 0, 1, lValue);
082        }
083
084        /**
085         * Inverts the specified unscaled decimal value truncating the result if
086         * necessary.
087         * 
088         * @param arith
089         *            the arithmetic associated with the given value
090         * @param uDecimal
091         *            the unscaled decimal value to invert
092         * @return <code>round<sub>DOWN</sub>(1/uDecimal)</code>
093         * @throws ArithmeticException
094         *             if {@code uDecimalDividend} is zero or if an overflow occurs
095         *             and the arithmetics {@link OverflowMode} is set to throw an
096         *             exception
097         * @see DecimalArithmetic#divide(long, long)
098         */
099        public static final long invert(DecimalArithmetic arith, long uDecimal) {
100                // special cases are handled by divide
101                return arith.divide(arith.one(), uDecimal);
102        }
103
104        /**
105         * Inverts the specified unscaled decimal value rounding the result if
106         * necessary.
107         * 
108         * @param arith
109         *            the arithmetic associated with the given value
110         * @param rounding
111         *            the rounding to apply if necessary
112         * @param uDecimal
113         *            the unscaled decimal value to invert
114         * @return <code>round(1/uDecimal)</code>
115         * @throws ArithmeticException
116         *             if {@code uDecimalDividend} is zero, if {@code roundingMode}
117         *             is UNNECESSARY and rounding is necessary or if an overflow
118         *             occurs and the arithmetics {@link OverflowMode} is set to
119         *             throw an exception
120         * @see DecimalArithmetic#divide(long, long)
121         */
122        public static final long invert(DecimalArithmetic arith, DecimalRounding rounding, long uDecimal) {
123                // special cases are handled by divide
124                return arith.divide(arith.one(), uDecimal);
125        }
126
127        // no instances
128        private Invert() {
129                super();
130        }
131}