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.scale.ScaleMetrics;
027import org.decimal4j.truncate.DecimalRounding;
028
029/**
030 * Contains methods to convert from and to long.
031 */
032final class LongConversion {
033
034        /**
035         * Converts the specified long value to an unscaled value of the scale
036         * defined by the given {@code scaleMetrics}. Performs no overflow checks.
037         * 
038         * @param scaleMetrics
039         *            the scale metrics defining the result scale
040         * @param value
041         *            the long value to convert
042         * @return the value converted to the scale defined by {@code scaleMetrics}
043         */
044        public static final long longToUnscaledUnchecked(ScaleMetrics scaleMetrics, long value) {
045                return scaleMetrics.multiplyByScaleFactor(value);
046        }
047
048        /**
049         * Converts the specified long value to an unscaled value of the scale
050         * defined by the given {@code scaleMetrics}. An exception is thrown if an
051         * overflow occurs.
052         * 
053         * @param scaleMetrics
054         *            the scale metrics defining the result scale
055         * @param value
056         *            the long value to convert
057         * @return the value converted to the scale defined by {@code scaleMetrics}
058         * @throws IllegalArgumentException
059         *             if {@code value} is too large to be represented as a Decimal
060         *             with the scale of this factory
061         */
062        public static final long longToUnscaled(ScaleMetrics scaleMetrics, long value) {
063                if (scaleMetrics.isValidIntegerValue(value)) {
064                        return scaleMetrics.multiplyByScaleFactor(value);
065                }
066                throw new IllegalArgumentException(
067                                "Overflow: cannot convert " + value + " to Decimal with scale " + scaleMetrics.getScale());
068        }
069
070        /**
071         * Converts the specified unscaled value to a long truncating the result if
072         * necessary.
073         * 
074         * @param scaleMetrics
075         *            the scale metrics associated with {@code uDecimal}
076         * @param uDecimal
077         *            the unscaled decimal value to convert
078         * @return <code>round<sub>DOWN</sub>(uDecimal)</code>
079         */
080        public static final long unscaledToLong(ScaleMetrics scaleMetrics, long uDecimal) {
081                return scaleMetrics.divideByScaleFactor(uDecimal);
082        }
083
084        /**
085         * Converts the specified unscaled value to a long rounding the result if
086         * necessary.
087         * 
088         * @param scaleMetrics
089         *            the scale metrics associated with {@code uDecimal}
090         * @param rounding
091         *            the rounding to apply during the conversion if necessary
092         * @param uDecimal
093         *            the unscaled decimal value to convert
094         * @return <code>round(uDecimal)</code>
095         * @throws ArithmeticException
096         *             if {@code roundingMode==UNNECESSARY} and rounding is
097         *             necessary
098         */
099        public static final long unscaledToLong(ScaleMetrics scaleMetrics, DecimalRounding rounding, long uDecimal) {
100                final long truncated = scaleMetrics.divideByScaleFactor(uDecimal);
101                final long remainder = uDecimal - scaleMetrics.multiplyByScaleFactor(truncated);
102                return truncated
103                                + Rounding.calculateRoundingIncrement(rounding, truncated, remainder, scaleMetrics.getScaleFactor());
104        }
105
106        // no instances
107        private LongConversion() {
108                super();
109        }
110}