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