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.scale;
025
026import static java.math.RoundingMode.DOWN;
027import static java.math.RoundingMode.FLOOR;
028import static java.math.RoundingMode.HALF_EVEN;
029import static java.math.RoundingMode.HALF_UP;
030import static java.math.RoundingMode.UNNECESSARY;
031import static org.decimal4j.truncate.OverflowMode.CHECKED;
032import static org.decimal4j.truncate.OverflowMode.UNCHECKED;
033
034import java.math.BigDecimal;
035import java.math.BigInteger;
036import java.math.RoundingMode;
037
038import org.decimal4j.api.DecimalArithmetic;
039import org.decimal4j.arithmetic.CheckedScale0fRoundingArithmetic;
040import org.decimal4j.arithmetic.CheckedScale0fTruncatingArithmetic;
041import org.decimal4j.arithmetic.UncheckedScale0fRoundingArithmetic;
042import org.decimal4j.arithmetic.UncheckedScale0fTruncatingArithmetic;
043import org.decimal4j.truncate.DecimalRounding;
044import org.decimal4j.truncate.OverflowMode;
045import org.decimal4j.truncate.TruncationPolicy;
046
047/**
048 * Scale class for decimals with {@link #getScale() scale} 0 and
049 * {@link #getScaleFactor() scale factor} 1. Decimals with scale zero are
050 * essentially longs.
051 */
052public enum Scale0f implements ScaleMetrics {
053
054        /**
055         * The singleton instance for scale 0.
056         */
057        INSTANCE;
058
059        /**
060         * The scale value <code>0</code>.
061         */
062        public static final int SCALE = 0;
063
064        /**
065         * The scale factor <code>10<sup>0</sup></code>.
066         */
067        public static final long SCALE_FACTOR = 1L;
068        
069        /** Long.numberOfLeadingZeros(SCALE_FACTOR)*/
070        private static final int NLZ_SCALE_FACTOR = 63;
071
072        private static final long LONG_MASK = 0xffffffffL;
073
074        private static final DecimalArithmetic[] UNCHECKED_ARITHMETIC = initArithmetic(UNCHECKED);
075        private static final DecimalArithmetic[] CHECKED_ARITHMETIC = initArithmetic(CHECKED);
076
077        private static final DecimalArithmetic DEFAULT_ARITHMETIC = UNCHECKED_ARITHMETIC[HALF_UP.ordinal()];
078        private static final DecimalArithmetic DEFAULT_CHECKED_ARITHMETIC = CHECKED_ARITHMETIC[HALF_UP.ordinal()];
079        private static final DecimalArithmetic ROUNDING_DOWN_ARITHMETIC = UNCHECKED_ARITHMETIC[DOWN.ordinal()];
080        private static final DecimalArithmetic ROUNDING_FLOOR_ARITHMETIC = UNCHECKED_ARITHMETIC[FLOOR.ordinal()];
081        private static final DecimalArithmetic ROUNDING_HALF_EVEN_ARITHMETIC = UNCHECKED_ARITHMETIC[HALF_EVEN.ordinal()];
082        private static final DecimalArithmetic ROUNDING_UNNECESSARY_ARITHMETIC = UNCHECKED_ARITHMETIC[UNNECESSARY.ordinal()];
083
084        private static final DecimalArithmetic[] initArithmetic(OverflowMode overflowMode) {
085                final boolean checked = overflowMode == CHECKED;
086                final DecimalArithmetic[] arith = new DecimalArithmetic[DecimalRounding.VALUES.size()];
087                for (final DecimalRounding dr : DecimalRounding.VALUES) {
088                        final int index = dr.getRoundingMode().ordinal();
089                        if (dr == DecimalRounding.DOWN) {
090                                arith[index] = checked ? CheckedScale0fTruncatingArithmetic.INSTANCE
091                                                : UncheckedScale0fTruncatingArithmetic.INSTANCE;
092                        } else {
093                                arith[index] = checked ? new CheckedScale0fRoundingArithmetic(dr)
094                                                : new UncheckedScale0fRoundingArithmetic(dr);
095                        }
096                }
097                return arith;
098        }
099
100        @Override
101        public final int getScale() {
102                return SCALE;
103        }
104
105        @Override
106        public final long getScaleFactor() {
107                return SCALE_FACTOR;
108        }
109
110        @Override
111        public final int getScaleFactorNumberOfLeadingZeros() {
112                return NLZ_SCALE_FACTOR;
113        }
114
115        @Override
116        public final BigInteger getScaleFactorAsBigInteger() {
117                return BigInteger.ONE;
118        }
119
120        @Override
121        public final BigDecimal getScaleFactorAsBigDecimal() {
122                return BigDecimal.ONE;
123        }
124
125        @Override
126        public final long getMaxIntegerValue() {
127                return Long.MAX_VALUE;
128        }
129
130        @Override
131        public final long getMinIntegerValue() {
132                return Long.MIN_VALUE;
133        }
134
135        @Override
136        public final boolean isValidIntegerValue(long value) {
137                return true;
138        }
139
140        @Override
141        public final long multiplyByScaleFactor(long factor) {
142                return factor;
143        }
144
145        @Override
146        public final long multiplyByScaleFactorExact(long factor) {
147                return factor;
148        }
149
150        @Override
151        public final long mulloByScaleFactor(int factor) {
152                return factor & LONG_MASK;
153        }
154
155        @Override
156        public final long mulhiByScaleFactor(int factor) {
157                return 0;
158        }
159
160        @Override
161        public final long divideByScaleFactor(long dividend) {
162                return dividend;
163        }
164
165        @Override
166        public final long divideUnsignedByScaleFactor(long unsignedDividend) {
167                return unsignedDividend;
168        }
169
170        @Override
171        public final long moduloByScaleFactor(long dividend) {
172                return 0;
173        }
174
175        @Override
176        public final String toString(long value) {
177                return Long.toString(value);
178        }
179
180        @Override
181        public final DecimalArithmetic getDefaultArithmetic() {
182                return DEFAULT_ARITHMETIC;
183        }
184
185        @Override
186        public final DecimalArithmetic getDefaultCheckedArithmetic() {
187                return DEFAULT_CHECKED_ARITHMETIC;
188        }
189
190        @Override
191        public final DecimalArithmetic getRoundingDownArithmetic() {
192                return ROUNDING_DOWN_ARITHMETIC;
193        }
194
195        @Override
196        public final DecimalArithmetic getRoundingFloorArithmetic() {
197                return ROUNDING_FLOOR_ARITHMETIC;
198        }
199
200        @Override
201        public final DecimalArithmetic getRoundingHalfEvenArithmetic() {
202                return ROUNDING_HALF_EVEN_ARITHMETIC;
203        }
204
205        @Override
206        public final DecimalArithmetic getRoundingUnnecessaryArithmetic() {
207                return ROUNDING_UNNECESSARY_ARITHMETIC;
208        }
209
210        @Override
211        public final DecimalArithmetic getArithmetic(RoundingMode roundingMode) {
212                return UNCHECKED_ARITHMETIC[roundingMode.ordinal()];
213        }
214
215        @Override
216        public final DecimalArithmetic getCheckedArithmetic(RoundingMode roundingMode) {
217                return CHECKED_ARITHMETIC[roundingMode.ordinal()];
218        }
219
220        @Override
221        public final DecimalArithmetic getArithmetic(TruncationPolicy truncationPolicy) {
222                final OverflowMode overflow = truncationPolicy.getOverflowMode();
223                final RoundingMode rounding = truncationPolicy.getRoundingMode();
224                return (overflow == UNCHECKED ? UNCHECKED_ARITHMETIC : CHECKED_ARITHMETIC)[rounding.ordinal()];
225        }
226
227        @Override
228        public final String toString() {
229                return "Scale0f";
230        }
231}