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; 027 028/** 029 * Helper class for arithmetic operations with overflow checks. 030 */ 031final class Checked { 032 033 /** 034 * Returns true if the addition {@code long1 + long2 = result} has resulted 035 * in an overflow. 036 * 037 * @param long1 038 * the first summand 039 * @param long2 040 * the second summand 041 * @param result 042 * the sum 043 * @return true if the calculation resulted in an overflow 044 */ 045 static final boolean isAddOverflow(long long1, long long2, long result) { 046 return (long1 ^ long2) >= 0 & (long1 ^ result) < 0; 047 } 048 049 /** 050 * Returns true if the subtraction {@code minuend - subtrahend = result} has 051 * resulted in an overflow. 052 * 053 * @param minuend 054 * the minuend to subtract from 055 * @param subtrahend 056 * the subtrahend to subtract 057 * @param result 058 * the difference 059 * @return true if the calculation resulted in an overflow 060 */ 061 static final boolean isSubtractOverflow(long minuend, long subtrahend, long result) { 062 return (minuend ^ subtrahend) < 0 & (minuend ^ result) < 0; 063 } 064 065 /** 066 * Returns true if the quotient {@code dividend / divisor} will result in an 067 * overflow. 068 * 069 * @param dividend 070 * the dividend 071 * @param divisor 072 * the divisor 073 * @return true if the calculation will result in an overflow 074 */ 075 static final boolean isDivideOverflow(long dividend, long divisor) { 076 return dividend == Long.MIN_VALUE & divisor == -1; 077 } 078 079 /** 080 * Returns the sum {@code (long1 + long2)} of the two {@code long} values 081 * throwing an exception if an overflow occurs. 082 * 083 * @param long1 084 * the first summand 085 * @param long2 086 * the second summand 087 * @return the sum of the two values 088 * @throws ArithmeticException 089 * if the calculation results in an overflow 090 */ 091 public static final long addLong(long long1, long long2) { 092 final long result = long1 + long2; 093 if (isAddOverflow(long1, long2, result)) { 094 throw new ArithmeticException("Overflow: " + long1 + " + " + long2 + " = " + result); 095 } 096 return result; 097 } 098 099 /** 100 * Returns the sum {@code (uDecimal1 + uDecimal2)} of the two unsigned 101 * decimal values throwing an exception if an overflow occurs. 102 * 103 * @param arith 104 * the arithmetic associated with the two unsigned decimals 105 * @param uDecimal1 106 * the first summand 107 * @param uDecimal2 108 * the second summand 109 * @return the sum of the two values 110 * @throws ArithmeticException 111 * if the calculation results in an overflow 112 */ 113 public static final long add(DecimalArithmetic arith, long uDecimal1, long uDecimal2) { 114 final long result = uDecimal1 + uDecimal2; 115 if ((uDecimal1 ^ uDecimal2) >= 0 & (uDecimal1 ^ result) < 0) { 116 throw new ArithmeticException("Overflow: " + arith.toString(uDecimal1) + " + " + arith.toString(uDecimal2) 117 + " = " + arith.toString(result)); 118 } 119 return result; 120 } 121 122 /** 123 * Returns the difference {@code (lMinuend - lSubtrahend)} of the two 124 * {@code long} values throwing an exception if an overflow occurs. 125 * 126 * @param lMinuend 127 * the minuend 128 * @param lSubtrahend 129 * the subtrahend 130 * @return the difference of the two values 131 * @throws ArithmeticException 132 * if the calculation results in an overflow 133 */ 134 public static final long subtractLong(long lMinuend, long lSubtrahend) { 135 final long result = lMinuend - lSubtrahend; 136 if (isSubtractOverflow(lMinuend, lSubtrahend, result)) { 137 throw new ArithmeticException("Overflow: " + lMinuend + " - " + lSubtrahend + " = " + result); 138 } 139 return result; 140 } 141 142 /** 143 * Returns the difference {@code (uDecimalMinuend - uDecimalSubtrahend)} of 144 * the two unscaled decimal values throwing an exception if an overflow 145 * occurs. 146 * 147 * @param arith 148 * the arithmetic associated with the two unsigned decimals 149 * @param uDecimalMinuend 150 * the minuend 151 * @param uDecimalSubtrahend 152 * the subtrahend 153 * @return the difference of the two values 154 * @throws ArithmeticException 155 * if the calculation results in an overflow 156 */ 157 public static final long subtract(DecimalArithmetic arith, long uDecimalMinuend, long uDecimalSubtrahend) { 158 final long result = uDecimalMinuend - uDecimalSubtrahend; 159 if (isSubtractOverflow(uDecimalMinuend, uDecimalSubtrahend, result)) { 160 throw new ArithmeticException("Overflow: " + arith.toString(uDecimalMinuend) + " - " 161 + arith.toString(uDecimalSubtrahend) + " = " + arith.toString(result)); 162 } 163 return result; 164 } 165 166 /** 167 * Returns the product {@code (lValue1 * lValue2)} of the two {@code long} 168 * values throwing an exception if an overflow occurs. 169 * 170 * @param lValue1 171 * the first factor 172 * @param lValue2 173 * the second factor 174 * @return the product of the two values 175 * @throws ArithmeticException 176 * if the calculation results in an overflow 177 */ 178 public static final long multiplyLong(long lValue1, long lValue2) { 179 // Hacker's Delight, Section 2-12 180 final int leadingZeros = Long.numberOfLeadingZeros(lValue1) + Long.numberOfLeadingZeros(~lValue1) 181 + Long.numberOfLeadingZeros(lValue2) + Long.numberOfLeadingZeros(~lValue2); 182 /* 183 * If leadingZeros > Long.SIZE + 1 it's definitely fine, if it's < 184 * Long.SIZE it's definitely bad. We do the leadingZeros check to avoid 185 * the division below if at all possible. 186 * 187 * Otherwise, if b == Long.MIN_VALUE, then the only allowed values of a 188 * are 0 and 1. We take care of all a < 0 with their own check, because 189 * in particular, the case a == -1 will incorrectly pass the division 190 * check below. 191 * 192 * In all other cases, we check that either a is 0 or the result is 193 * consistent with division. 194 */ 195 final long result = lValue1 * lValue2; 196 if (leadingZeros > Long.SIZE + 1) { 197 return result; 198 } 199 if (leadingZeros < Long.SIZE || (lValue1 < 0 & lValue2 == Long.MIN_VALUE) 200 || (lValue1 != 0 && (result / lValue1) != lValue2)) { 201 throw new ArithmeticException("Overflow: " + lValue1 + " * " + lValue2 + " = " + result); 202 } 203 return result; 204 } 205 206 /** 207 * Returns the product {@code (uDecimal * lValue)} of an unsigned decimal 208 * value and a {@code long} value throwing an exception if an overflow 209 * occurs. 210 * 211 * @param arith 212 * the arithmetic associated with the first unsigned decimal 213 * argument 214 * @param uDecimal 215 * the first factor 216 * @param lValue 217 * the second factor 218 * @return the product of the two values 219 * @throws ArithmeticException 220 * if the calculation results in an overflow 221 */ 222 public static final long multiplyByLong(DecimalArithmetic arith, long uDecimal, long lValue) { 223 // Hacker's Delight, Section 2-12 224 final int leadingZeros = Long.numberOfLeadingZeros(uDecimal) + Long.numberOfLeadingZeros(~uDecimal) 225 + Long.numberOfLeadingZeros(lValue) + Long.numberOfLeadingZeros(~lValue); 226 /* 227 * If leadingZeros > Long.SIZE + 1 it's definitely fine, if it's < 228 * Long.SIZE it's definitely bad. We do the leadingZeros check to avoid 229 * the division below if at all possible. 230 * 231 * Otherwise, if b == Long.MIN_VALUE, then the only allowed values of a 232 * are 0 and 1. We take care of all a < 0 with their own check, because 233 * in particular, the case a == -1 will incorrectly pass the division 234 * check below. 235 * 236 * In all other cases, we check that either a is 0 or the result is 237 * consistent with division. 238 */ 239 final long result = uDecimal * lValue; 240 if (leadingZeros > Long.SIZE + 1) { 241 return result; 242 } 243 if (leadingZeros < Long.SIZE || (uDecimal < 0 & lValue == Long.MIN_VALUE) 244 || (uDecimal != 0 && (result / uDecimal) != lValue)) { 245 throw new ArithmeticException( 246 "Overflow: " + arith.toString(uDecimal) + " * " + lValue + " = " + arith.toString(result)); 247 } 248 return result; 249 } 250 251 /** 252 * Returns the quotient {@code (lDividend / lDivisor)} of the two 253 * {@code long} values throwing an exception if an overflow occurs. 254 * 255 * @param lDividend 256 * the dividend to divide 257 * @param lDivisor 258 * the divisor to divide by 259 * @return the quotient of the two values 260 * @throws ArithmeticException 261 * if the calculation results in an overflow 262 */ 263 public static final long divideLong(long lDividend, long lDivisor) { 264 if (lDivisor == -1 & lDividend == Long.MIN_VALUE) { 265 throw new ArithmeticException("Overflow: " + lDividend + " / " + lDivisor + " = " + Long.MIN_VALUE); 266 } 267 return lDividend / lDivisor; 268 } 269 270 /** 271 * Returns the quotient {@code (uDecimalDividend / lDivisor)} of an unscaled 272 * decimal value and a {@code long} value throwing an exception if an 273 * overflow occurs. 274 * 275 * @param arith 276 * the arithmetic associated with the first unsigned decimal 277 * argument 278 * @param uDecimalDividend 279 * the dividend to divide 280 * @param lDivisor 281 * the divisor to divide by 282 * @return the quotient of the two values 283 * @throws ArithmeticException 284 * if the calculation results in an overflow 285 */ 286 public static final long divideByLong(DecimalArithmetic arith, long uDecimalDividend, long lDivisor) { 287 if (lDivisor == 0) { 288 throw new ArithmeticException("Division by zero: " + arith.toString(uDecimalDividend) + " / " + lDivisor); 289 } 290 if (lDivisor == -1 & uDecimalDividend == Long.MIN_VALUE) { 291 throw new ArithmeticException("Overflow: " + arith.toString(uDecimalDividend) + " / " + lDivisor + " = " 292 + arith.toString(Long.MIN_VALUE)); 293 } 294 return uDecimalDividend / lDivisor; 295 } 296 297 /** 298 * Returns the absolute value {@code |value|} throwing an exception if an 299 * overflow occurs. 300 * 301 * @param arith 302 * the arithmetic associated with the value 303 * @param value 304 * the number whose absolute value to return 305 * @return the absolute of the specified value 306 * @throws ArithmeticException 307 * if the calculation results in an overflow 308 */ 309 public static final long abs(DecimalArithmetic arith, long value) { 310 final long abs = Math.abs(value); 311 if (abs < 0) { 312 throw new ArithmeticException("Overflow: abs(" + arith.toString(value) + ") = " + abs); 313 } 314 return abs; 315 } 316 317 /** 318 * Returns the negation {@code (-value)} throwing an exception if an 319 * overflow occurs. 320 * 321 * @param arith 322 * the arithmetic associated with the value 323 * @param value 324 * the number to negate 325 * @return the negation of the specified value 326 * @throws ArithmeticException 327 * if the calculation results in an overflow 328 */ 329 public static final long negate(DecimalArithmetic arith, long value) { 330 final long neg = -value; 331 if (value != 0 & (value ^ neg) >= 0) { 332 throw new ArithmeticException("Overflow: -" + arith.toString(value) + " = " + neg); 333 } 334 return neg; 335 } 336 337 // no instances 338 private Checked() { 339 } 340 341}