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.arithmetic; 025 026import org.decimal4j.api.DecimalArithmetic; 027import org.decimal4j.truncate.OverflowMode; 028 029/** 030 * Helper class used by division and inversion methods to handle special cases. 031 */ 032enum SpecialDivisionResult { 033 /** 034 * {@code a/b} with {@code a==0, b!=0} leading to {@code 0/b=0} 035 */ 036 DIVIDEND_IS_ZERO { 037 @Override 038 final long divide(DecimalArithmetic arithmetic, long uDecimalDividend, long uDecimalDivisor) { 039 return 0; 040 } 041 }, 042 /** 043 * {@code a/b} with {@code b==0} leading to an arithmetic exception 044 */ 045 DIVISOR_IS_ZERO { 046 @Override 047 final long divide(DecimalArithmetic arithmetic, long uDecimalDividend, long uDecimalDivisor) { 048 throw new ArithmeticException("Division by zero: " + arithmetic.toString(uDecimalDividend) + " / " 049 + arithmetic.toString(uDecimalDivisor)); 050 } 051 }, 052 /** 053 * {@code a/b} with {@code b==1} leading to {@code a/1=a} 054 */ 055 DIVISOR_IS_ONE { 056 @Override 057 final long divide(DecimalArithmetic arithmetic, long uDecimalDividend, long uDecimalDivisor) { 058 return uDecimalDividend; 059 } 060 }, 061 /** 062 * {@code a/b} with {@code b==-1} resulting in {@code a/-1=-a} 063 */ 064 DIVISOR_IS_MINUS_ONE { 065 @Override 066 final long divide(DecimalArithmetic arithmetic, long uDecimalDividend, long uDecimalDivisor) { 067 return arithmetic.negate(uDecimalDividend);// we must go through 068 // arithmetic because 069 // overflow is possible 070 } 071 }, 072 /** 073 * {@code a/b} with {@code a==b} resulting in {@code a/a=b/b=1} 074 */ 075 DIVISOR_EQUALS_DIVIDEND { 076 @Override 077 final long divide(DecimalArithmetic arithmetic, long uDecimalDividend, long uDecimalDivisor) { 078 return arithmetic.one(); 079 } 080 }, 081 /** 082 * {@code a/b} with {@code a==-b} resulting in {@code a/-a=-b/b=-1} 083 */ 084 DIVISOR_EQUALS_MINUS_DIVIDEND { 085 @Override 086 final long divide(DecimalArithmetic arithmetic, long uDecimalDividend, long uDecimalDivisor) { 087 return -arithmetic.one(); 088 } 089 }; 090 091 /** 092 * Performs the division for this special division result. The arithmetics 093 * overflow mode is considered. 094 * 095 * @param arithmetic 096 * the arithmetic associated with the values 097 * @param uDecimalDividend 098 * the dividend 099 * @param uDecimalDivisor 100 * the divisor 101 * @return <tt>uDecimalDividend / uDecimalDivisor</tt> 102 * @throws ArithmeticException 103 * if {@code this==DIVISOR_IS_ZERO} or if an overflow occurs and 104 * the arithmetic's {@link OverflowMode} is set to throw an 105 * exception 106 */ 107 abstract long divide(DecimalArithmetic arithmetic, long uDecimalDividend, long uDecimalDivisor); 108 109 /** 110 * Returns the special division case if it is one and null otherwise. 111 * 112 * @param arithmetic 113 * the arithmetic object 114 * @param uDecimalDividend 115 * the dividend 116 * @param uDecimalDivisor 117 * the divisor 118 * @return the special case if it is one and null otherwise 119 */ 120 static final SpecialDivisionResult getFor(DecimalArithmetic arithmetic, long uDecimalDividend, long uDecimalDivisor) { 121 // NOTE: this must be the first case because 0/0 must also throw an 122 // exception! 123 if (uDecimalDivisor == 0) { 124 return DIVISOR_IS_ZERO; 125 } 126 if (uDecimalDividend == 0) { 127 return DIVIDEND_IS_ZERO; 128 } 129 final long one = arithmetic.one(); 130 if (uDecimalDivisor == one) { 131 return DIVISOR_IS_ONE; 132 } 133 if (uDecimalDivisor == -one) { 134 return DIVISOR_IS_MINUS_ONE; 135 } 136 if (uDecimalDividend == uDecimalDivisor) { 137 return DIVISOR_EQUALS_DIVIDEND; 138 } 139 if (uDecimalDividend == -uDecimalDivisor) { 140 return DIVISOR_EQUALS_MINUS_DIVIDEND; 141 } 142 return null; 143 } 144}