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.truncate; 025 026import java.math.RoundingMode; 027import java.util.Collections; 028import java.util.EnumSet; 029import java.util.Set; 030 031/** 032 * Provides rounding constants implementing {@link TruncationPolicy} for 033 * {@link OverflowMode#CHECKED}. The constants are equivalent to the constants 034 * defined by {@link RoundingMode}; the policy's {@link #getOverflowMode()} 035 * method always returns {@link OverflowMode#CHECKED CHECKED} overflow mode. 036 */ 037public enum CheckedRounding implements TruncationPolicy { 038 /** 039 * Checked truncation policy with rounding mode to round away from zero. 040 * Always increments the digit prior to a non-zero discarded fraction. Note 041 * that this rounding mode never decreases the magnitude of the calculated 042 * value. 043 * 044 * @see RoundingMode#UP 045 */ 046 UP { 047 @Override 048 public final RoundingMode getRoundingMode() { 049 return RoundingMode.UP; 050 } 051 @Override 052 public final UncheckedRounding toUncheckedRounding() { 053 return UncheckedRounding.UP; 054 } 055 }, 056 057 /** 058 * Checked truncation policy with rounding mode to round towards zero. Never 059 * increments the digit prior to a discarded fraction (i.e., truncates). 060 * Note that this rounding mode never increases the magnitude of the 061 * calculated value. 062 * 063 * @see RoundingMode#DOWN 064 */ 065 DOWN { 066 @Override 067 public final RoundingMode getRoundingMode() { 068 return RoundingMode.DOWN; 069 } 070 @Override 071 public final UncheckedRounding toUncheckedRounding() { 072 return UncheckedRounding.DOWN; 073 } 074 }, 075 076 /** 077 * Checked truncation policy with rounding mode to round towards positive 078 * infinity. If the result is positive, behaves as for 079 * {@code RoundingMode.UP}; if negative, behaves as for 080 * {@code RoundingMode.DOWN}. Note that this rounding mode never decreases 081 * the calculated value. 082 * 083 * @see RoundingMode#CEILING 084 */ 085 CEILING { 086 @Override 087 public final RoundingMode getRoundingMode() { 088 return RoundingMode.CEILING; 089 } 090 @Override 091 public final UncheckedRounding toUncheckedRounding() { 092 return UncheckedRounding.CEILING; 093 } 094 }, 095 096 /** 097 * Checked truncation policy with rounding mode to round towards negative 098 * infinity. If the result is positive, behave as for 099 * {@code RoundingMode.DOWN}; if negative, behave as for 100 * {@code RoundingMode.UP}. Note that this rounding mode never increases the 101 * calculated value. 102 * 103 * @see RoundingMode#FLOOR 104 */ 105 FLOOR { 106 @Override 107 public final RoundingMode getRoundingMode() { 108 return RoundingMode.FLOOR; 109 } 110 @Override 111 public final UncheckedRounding toUncheckedRounding() { 112 return UncheckedRounding.FLOOR; 113 } 114 }, 115 116 /** 117 * Checked truncation policy with rounding mode to round towards 118 * {@literal "nearest neighbor"} unless both neighbors are equidistant, in 119 * which case round up. Behaves as for {@code RoundingMode.UP} if the 120 * discarded fraction is ≥ 0.5; otherwise, behaves as for 121 * {@code RoundingMode.DOWN}. Note that this is the rounding mode commonly 122 * taught at school. 123 * 124 * @see RoundingMode#HALF_UP 125 */ 126 HALF_UP { 127 @Override 128 public final RoundingMode getRoundingMode() { 129 return RoundingMode.HALF_UP; 130 } 131 @Override 132 public final UncheckedRounding toUncheckedRounding() { 133 return UncheckedRounding.HALF_UP; 134 } 135 }, 136 137 /** 138 * Checked truncation policy with rounding mode to round towards 139 * {@literal "nearest neighbor"} unless both neighbors are equidistant, in 140 * which case round down. Behaves as for {@code RoundingMode.UP} if the 141 * discarded fraction is > 0.5; otherwise, behaves as for 142 * {@code RoundingMode.DOWN}. 143 * 144 * @see RoundingMode#HALF_DOWN 145 */ 146 HALF_DOWN { 147 @Override 148 public final RoundingMode getRoundingMode() { 149 return RoundingMode.HALF_DOWN; 150 } 151 @Override 152 public final UncheckedRounding toUncheckedRounding() { 153 return UncheckedRounding.HALF_DOWN; 154 } 155 }, 156 157 /** 158 * Checked truncation policy with rounding mode to round towards the 159 * {@literal "nearest neighbor"} unless both neighbors are equidistant, in 160 * which case, round towards the even neighbor. Behaves as for 161 * {@code RoundingMode.HALF_UP} if the digit to the left of the discarded 162 * fraction is odd; behaves as for {@code RoundingMode.HALF_DOWN} if it's 163 * even. Note that this is the rounding mode that statistically minimizes 164 * cumulative error when applied repeatedly over a sequence of calculations. 165 * It is sometimes known as {@literal "Banker's rounding,"} and is chiefly 166 * used in the USA. This rounding mode is analogous to the rounding policy 167 * used for {@code float} and {@code double} arithmetic in Java. 168 * 169 * @see RoundingMode#HALF_EVEN 170 */ 171 HALF_EVEN { 172 @Override 173 public final RoundingMode getRoundingMode() { 174 return RoundingMode.HALF_EVEN; 175 } 176 @Override 177 public final UncheckedRounding toUncheckedRounding() { 178 return UncheckedRounding.HALF_EVEN; 179 } 180 }, 181 182 /** 183 * Checked truncation policy with rounding mode to assert that the requested 184 * operation has an exact result, hence no rounding is necessary. If this 185 * rounding mode is specified on an operation that yields an inexact result, 186 * an {@code ArithmeticException} is thrown. 187 * 188 * @see RoundingMode#UNNECESSARY 189 */ 190 UNNECESSARY { 191 @Override 192 public final RoundingMode getRoundingMode() { 193 return RoundingMode.UNNECESSARY; 194 } 195 @Override 196 public final UncheckedRounding toUncheckedRounding() { 197 return UncheckedRounding.UNNECESSARY; 198 } 199 }; 200 201 /** 202 * Returns {@link OverflowMode#CHECKED}. 203 * 204 * @return CHECKED overflow mode 205 */ 206 @Override 207 public final OverflowMode getOverflowMode() { 208 return OverflowMode.CHECKED; 209 } 210 211 /** 212 * Returns the policy with the same {@link #getRoundingMode() rounding mode} 213 * as this checked rounding policy but for {@link OverflowMode#UNCHECKED 214 * UNCHECKED} {@link #getOverflowMode() overflow mode}. 215 * 216 * @return the {@link UncheckedRounding} counterpart to this policy. 217 */ 218 abstract public UncheckedRounding toUncheckedRounding(); 219 220 /** 221 * Returns "CHECKED/(name)" where {@code (name)} stands for the {@link #name()} of this constant. 222 * 223 * @return a string like "CHECKED/HALF_UP" 224 */ 225 @Override 226 public final String toString() { 227 return "CHECKED/" + name(); 228 } 229 230 /** 231 * Immutable set with all values of this enum. Avoids object creation in 232 * contrast to {@link #values()}. 233 */ 234 public static final Set<CheckedRounding> VALUES = Collections.unmodifiableSet(EnumSet.allOf(CheckedRounding.class)); 235 236 /** 237 * Returns the checked rounding constant for the given rounding mode. 238 * 239 * @param roundingMode 240 * the rounding mode 241 * @return the constant corresponding to the given rounding mode 242 */ 243 public static final CheckedRounding valueOf(RoundingMode roundingMode) { 244 return ByRoundingMode.VALUES_BY_ROUNDING_MODE_ORDINAL[roundingMode.ordinal()]; 245 } 246 247 private static class ByRoundingMode { 248 private static final CheckedRounding[] VALUES_BY_ROUNDING_MODE_ORDINAL = sortByRoundingModeOrdinal(); 249 250 private static final CheckedRounding[] sortByRoundingModeOrdinal() { 251 final CheckedRounding[] sorted = new CheckedRounding[VALUES.size()]; 252 for (final CheckedRounding dr : VALUES) { 253 sorted[dr.getRoundingMode().ordinal()] = dr; 254 } 255 return sorted; 256 } 257 } 258}