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