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 pow methods to handle special cases. 031 */ 032enum SpecialPowResult { 033 /** 034 * {@code a^n} with {@code n==0} leading to {@code 1} 035 */ 036 EXPONENT_IS_ZERO { 037 @Override 038 final long pow(DecimalArithmetic arithmetic, long uDecimal, int exponent) { 039 return arithmetic.one();// yes 0^0 is also 1 040 } 041 }, 042 /** 043 * {@code a^n} with {@code n==1} leading to {@code a} 044 */ 045 EXPONENT_IS_ONE { 046 @Override 047 final long pow(DecimalArithmetic arithmetic, long uDecimal, int exponent) { 048 return uDecimal; 049 } 050 }, 051 /** 052 * {@code a^n} with {@code a==0} leading to {@code 0} if {@code n>=0} and to 053 * an arithmetic exception if {@code n<0} 054 */ 055 BASE_IS_ZERO { 056 @Override 057 final long pow(DecimalArithmetic arithmetic, long uDecimal, int exponent) { 058 if (exponent >= 0) { 059 // uDecimal == 0 should never happen (0^0 is usually defined as 060 // 1) 061 return 0; 062 } 063 throw new ArithmeticException("Division by zero: " + arithmetic.toString(uDecimal) + "^" + exponent); 064 } 065 }, 066 /** 067 * {@code a^n} with {@code a==1} leading to {@code 1} 068 */ 069 BASE_IS_ONE { 070 @Override 071 final long pow(DecimalArithmetic arithmetic, long uDecimal, int exponent) { 072 return uDecimal;// uDecimal is 1 073 } 074 }, 075 /** 076 * {@code a^n} with {@code a==-1} leading to {@code 1} if {@code n} is even 077 * and to {@code -1} if {@code n} is odd. 078 */ 079 BASE_IS_MINUS_ONE { 080 @Override 081 final long pow(DecimalArithmetic arithmetic, long uDecimal, int exponent) { 082 return ((exponent & 0x1) == 0) ? -uDecimal : uDecimal;// uDecimal is 083 // one and 084 // it's 085 // negation 086 // cannot 087 // overflow 088 } 089 }, 090 /** 091 * {@code a^n} with {@code n==-1} leading to {@code 1/a} 092 */ 093 EXPONENT_IS_MINUS_ONE { 094 @Override 095 final long pow(DecimalArithmetic arithmetic, long uDecimal, int exponent) { 096 return arithmetic.invert(uDecimal); 097 } 098 }, 099 /** 100 * {@code a^n} with {@code n==2} leading to {@code square(a)} 101 */ 102 EXPONENT_IS_TWO { 103 @Override 104 final long pow(DecimalArithmetic arithmetic, long uDecimal, int exponent) { 105 return arithmetic.square(uDecimal); 106 } 107 }; 108 109 /** 110 * Performs the exponentiation for this special pow result. The arithmetics 111 * overflow mode is considered. 112 * 113 * @param arithmetic 114 * the arithmetic associated with the values 115 * @param uDecimal 116 * the base value 117 * @param exponent 118 * the exponent 119 * @return <tt>uDecimal<sup>exponent</sup></tt> 120 * @throws ArithmeticException 121 * if {@code uDecimal==0} and exponent is negative or if an 122 * overflow occurs and the arithmetic's {@link OverflowMode} is 123 * set to throw an exception 124 */ 125 abstract long pow(DecimalArithmetic arithmetic, long uDecimal, int exponent); 126 127 /** 128 * Returns the special power case if it is one and null otherwise. 129 * 130 * @param arithmetic 131 * the arithmetic object 132 * @param uDecimal 133 * the base 134 * @param n 135 * the exponent 136 * @return the special case if it is one and null otherwise 137 */ 138 static final SpecialPowResult getFor(DecimalArithmetic arithmetic, long uDecimal, long n) { 139 if (n == 0) { 140 return EXPONENT_IS_ZERO; 141 } 142 if (n == 1) { 143 return EXPONENT_IS_ONE; 144 } 145 if (uDecimal == 0) { 146 return BASE_IS_ZERO; 147 } 148 final long one = arithmetic.one(); 149 if (uDecimal == one) { 150 return BASE_IS_ONE; 151 } 152 if (uDecimal == -one) { 153 return BASE_IS_MINUS_ONE; 154 } 155 if (n == -1) { 156 return EXPONENT_IS_MINUS_ONE; 157 } 158 if (n == 2) { 159 return EXPONENT_IS_TWO; 160 } 161 return null; 162 } 163}