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 static org.decimal4j.arithmetic.Square.SQRT_MAX_VALUE; 027 028import org.decimal4j.api.DecimalArithmetic; 029import org.decimal4j.scale.Scale9f; 030import org.decimal4j.scale.ScaleMetrics; 031import org.decimal4j.scale.Scales; 032import org.decimal4j.truncate.DecimalRounding; 033 034/** 035 * Provides methods to calculate multiplication results. 036 */ 037final class Mul { 038 039 private static final ScaleMetrics SCALE9F = Scale9f.INSTANCE; 040 041 //sufficient (but not necessary) condition that product fits in long 042 private static final boolean doesProductFitInLong(long uDecimal1, long uDecimal2) { 043 if (-SQRT_MAX_VALUE <= uDecimal1 & uDecimal1 <= SQRT_MAX_VALUE & -SQRT_MAX_VALUE <= uDecimal2 & uDecimal2 <= SQRT_MAX_VALUE) { 044 return true; 045 } 046 return false; 047 //NOTE: not worth checking (too much overhead for too few special cases): 048// final int leadingZeros = Long.numberOfLeadingZeros(uDecimal1) + Long.numberOfLeadingZeros(~uDecimal1) + Long.numberOfLeadingZeros(uDecimal2) + Long.numberOfLeadingZeros(~uDecimal2); 049// return leadingZeros > Long.SIZE + 1; 050 } 051 052 /** 053 * Calculates the multiple {@code uDecimal1 * uDecimal2 / scaleFactor} 054 * without rounding. 055 * 056 * @param arith 057 * the arithmetic with access to scale metrics etc. 058 * @param uDecimal1 059 * the first unscaled decimal factor 060 * @param uDecimal2 061 * the second unscaled decimal factor 062 * @return the multiplication result without rounding 063 */ 064 public static final long multiply(DecimalArithmetic arith, long uDecimal1, long uDecimal2) { 065 final SpecialMultiplicationResult special = SpecialMultiplicationResult.getFor(arith, uDecimal1, uDecimal2); 066 if (special != null) { 067 return special.multiply(arith, uDecimal1, uDecimal2); 068 } 069 return multiply(uDecimal1, arith.getScaleMetrics(), uDecimal2); 070 } 071 072 /** 073 * Calculates unchecked multiplication by an unscaled value with the given scale 074 * without rounding. 075 * 076 * @param uDecimal 077 * the unscaled decimal factor 078 * @param unscaled 079 * the second unscaled factor 080 * @param scale 081 * the scale of the second factor 082 * @return the multiplication result without rounding and without overflow checks 083 */ 084 public static final long multiplyByUnscaled(long uDecimal, long unscaled, int scale) { 085 if (scale > Scales.MAX_SCALE) { 086 throw new IllegalArgumentException("Illegal scale, must be <=" + Scales.MAX_SCALE + " but was " + scale); 087 } 088 if (uDecimal == 0 | unscaled == 0) { 089 return 0; 090 } else if (scale == 0) { 091 return uDecimal * unscaled; 092 } else if (scale < 0) { 093 return Pow10.divideByPowerOf10(uDecimal * unscaled, scale); 094 } 095 final ScaleMetrics scaleMetrics = Scales.getScaleMetrics(scale); 096 return multiply(uDecimal, scaleMetrics, unscaled); 097 } 098 099 /** 100 * Calculates the multiple {@code uDecimal1 * uDecimal2 / scaleFactor} 101 * without rounding. 102 * 103 * @param uDecimal1 104 * the first unscaled decimal factor 105 * @param scaleMetrics2 106 * the scale metrics associated with the second factor 107 * @param uDecimal2 108 * the second unscaled decimal factor 109 * @return the multiplication result without rounding 110 */ 111 private static final long multiply(long uDecimal1, ScaleMetrics scaleMetrics2, long uDecimal2) { 112 if (doesProductFitInLong(uDecimal1, uDecimal2)) { 113 //product fits in long, just do it 114 return scaleMetrics2.divideByScaleFactor(uDecimal1 * uDecimal2); 115 } 116 final int scale = scaleMetrics2.getScale(); 117 if (scale <= 9) { 118 //use scale to split into 2 parts: i (integral) and f (fractional) 119 //with this scale, the low order product f1*f2 fits in a long 120 final long i1 = scaleMetrics2.divideByScaleFactor(uDecimal1); 121 final long i2 = scaleMetrics2.divideByScaleFactor(uDecimal2); 122 final long f1 = uDecimal1 - scaleMetrics2.multiplyByScaleFactor(i1); 123 final long f2 = uDecimal2 - scaleMetrics2.multiplyByScaleFactor(i2); 124 return uDecimal1 * i2 + i1 * f2 + scaleMetrics2.divideByScaleFactor(f1 * f2); 125 } else { 126 //use scale9 to split into 2 parts: h (high) and l (low) 127 final ScaleMetrics scaleDiff09 = Scales.getScaleMetrics(scale - 9); 128 final ScaleMetrics scaleDiff18 = Scales.getScaleMetrics(18 - scale); 129 final long h1 = SCALE9F.divideByScaleFactor(uDecimal1); 130 final long h2 = SCALE9F.divideByScaleFactor(uDecimal2); 131 final long l1 = uDecimal1 - SCALE9F.multiplyByScaleFactor(h1); 132 final long l2 = uDecimal2 - SCALE9F.multiplyByScaleFactor(h2); 133 final long h1xl2 = h1 * l2; 134 final long h2xl1 = h2 * l1; 135 final long l1xl2d = SCALE9F.divideByScaleFactor(l1 * l2); 136 final long h1xl2d = scaleDiff09.divideByScaleFactor(h1xl2); 137 final long h2xl1d = scaleDiff09.divideByScaleFactor(h2xl1); 138 final long h1xl2r = h1xl2 - scaleDiff09.multiplyByScaleFactor(h1xl2d); 139 final long h2xl1r = h2xl1 - scaleDiff09.multiplyByScaleFactor(h2xl1d); 140 return scaleDiff18.multiplyByScaleFactor(h1 * h2) + h1xl2d + h2xl1d + scaleDiff09.divideByScaleFactor(h1xl2r + h2xl1r + l1xl2d); 141 } 142 } 143 144 /** 145 * Calculates the multiple {@code uDecimal1 * uDecimal2 / scaleFactor} 146 * applying the specified rounding if necessary. 147 * 148 * @param arith 149 * the arithmetic with access to scale metrics etc. 150 * @param rounding 151 * the rounding to apply if necessary 152 * @param uDecimal1 153 * the first unscaled decimal factor 154 * @param uDecimal2 155 * the second unscaled decimal factor 156 * @return the multiplication result with rounding 157 */ 158 public static final long multiply(DecimalArithmetic arith, DecimalRounding rounding, long uDecimal1, long uDecimal2) { 159 final SpecialMultiplicationResult special = SpecialMultiplicationResult.getFor(arith, uDecimal1, uDecimal2); 160 if (special != null) { 161 return special.multiply(arith, uDecimal1, uDecimal2); 162 } 163 return multiply(rounding, uDecimal1, arith.getScaleMetrics(), uDecimal2); 164 } 165 166 /** 167 * Calculates unchecked multiplication by an unscaled value with the given 168 * scale with rounding. 169 * 170 * @param rounding 171 * the rounding to apply 172 * @param uDecimal 173 * the unscaled decimal factor 174 * @param unscaled 175 * the second unscaled factor 176 * @param scale 177 * the scale of the second factor 178 * @return the multiplication result with rounding and without overflow checks 179 */ 180 public static final long multiplyByUnscaled(DecimalRounding rounding, long uDecimal, long unscaled, int scale) { 181 if (scale > Scales.MAX_SCALE) { 182 throw new IllegalArgumentException("Illegal scale, must be <=" + Scales.MAX_SCALE + " but was " + scale); 183 } 184 if (uDecimal == 0 | unscaled == 0) { 185 return 0; 186 } else if (scale == 0) { 187 return uDecimal * unscaled; 188 } else if (scale < 0) { 189 return Pow10.divideByPowerOf10(rounding, uDecimal * unscaled, scale); 190 } 191 final ScaleMetrics scaleMetrics = Scales.getScaleMetrics(scale); 192 return multiply(rounding, uDecimal, scaleMetrics, unscaled); 193 } 194 195 /** 196 * Calculates unchecked multiplication by an unscaled value with the given 197 * scale with rounding. 198 * 199 * @param rounding 200 * the rounding to apply 201 * @param uDecimal1 202 * the first unscaled decimal factor 203 * @param scaleMetrics2 204 * the scale metrics associated with the second factor 205 * @param uDecimal2 206 * the second unscaled decimal factor 207 * @return the multiplication result with rounding and without overflow checks 208 */ 209 private static final long multiply(DecimalRounding rounding, long uDecimal1, ScaleMetrics scaleMetrics2, long uDecimal2) { 210 if (doesProductFitInLong(uDecimal1, uDecimal2)) { 211 //product fits in long, just do it 212 return multiply32(rounding, uDecimal1, scaleMetrics2, uDecimal2); 213 } 214 215 final int scale = scaleMetrics2.getScale(); 216 if (scale <= 9) { 217 //use scale to split into 2 parts: i (integral) and f (fractional) 218 //with this scale, the low order product f1*f2 fits in a long 219 final long i1 = scaleMetrics2.divideByScaleFactor(uDecimal1); 220 final long i2 = scaleMetrics2.divideByScaleFactor(uDecimal2); 221 final long f1 = uDecimal1 - scaleMetrics2.multiplyByScaleFactor(i1); 222 final long f2 = uDecimal2 - scaleMetrics2.multiplyByScaleFactor(i2); 223 final long f1xf2 = f1 * f2; 224 final long f1xf2d = scaleMetrics2.divideByScaleFactor(f1xf2); 225 final long f1xf2r = f1xf2 - scaleMetrics2.multiplyByScaleFactor(f1xf2d); 226 final long unrounded = uDecimal1 * i2 + i1 * f2 + f1xf2d; 227 return unrounded + Rounding.calculateRoundingIncrement(rounding, unrounded, f1xf2r, scaleMetrics2.getScaleFactor()); 228 } else { 229 //use scale9 to split into 2 parts: h (high) and l (low) 230 final ScaleMetrics scaleDiff09 = Scales.getScaleMetrics(scale - 9); 231 final ScaleMetrics scaleDiff18 = Scales.getScaleMetrics(18 - scale); 232 final long h1 = SCALE9F.divideByScaleFactor(uDecimal1); 233 final long h2 = SCALE9F.divideByScaleFactor(uDecimal2); 234 final long l1 = uDecimal1 - SCALE9F.multiplyByScaleFactor(h1); 235 final long l2 = uDecimal2 - SCALE9F.multiplyByScaleFactor(h2); 236 final long h1xl2 = h1 * l2; 237 final long h2xl1 = h2 * l1; 238 final long l1xl2 = l1 * l2; 239 final long l1xl2d = SCALE9F.divideByScaleFactor(l1xl2); 240 final long h1xl2d = scaleDiff09.divideByScaleFactor(h1xl2); 241 final long h2xl1d = scaleDiff09.divideByScaleFactor(h2xl1); 242 final long h1xl2r = h1xl2 - scaleDiff09.multiplyByScaleFactor(h1xl2d); 243 final long h2xl1r = h2xl1 - scaleDiff09.multiplyByScaleFactor(h2xl1d); 244 final long l1xl2r = l1xl2 - SCALE9F.multiplyByScaleFactor(l1xl2d); 245 final long h1xl2_h2xl1_l1xl1 = h1xl2r + h2xl1r + l1xl2d; 246 final long h1xl2_h2xl1_l1xl1d = scaleDiff09.divideByScaleFactor(h1xl2_h2xl1_l1xl1); 247 final long h1xl2_h2xl1_l1xl1r = h1xl2_h2xl1_l1xl1 - scaleDiff09.multiplyByScaleFactor(h1xl2_h2xl1_l1xl1d); 248 final long unrounded = scaleDiff18.multiplyByScaleFactor(h1 * h2) + h1xl2d + h2xl1d + h1xl2_h2xl1_l1xl1d; 249 final long remainder = SCALE9F.multiplyByScaleFactor(h1xl2_h2xl1_l1xl1r) + l1xl2r; 250 return unrounded + Rounding.calculateRoundingIncrement(rounding, unrounded, remainder, scaleMetrics2.getScaleFactor()); 251 } 252 } 253 254 /** 255 * Calculates {@code round((uDecimal1 * uDecimal2) / scaleFactor2)} treating 256 * the factors as 32 bit values whose product must fit in a long result. 257 * 258 * @param rounding 259 * the rounding to use 260 * @param uDecimal1 261 * the first factor 262 * @param scaleMetrics2 263 * the scale metrics to apply to the product 264 * @param uDecimal2 265 * the second factor 266 * @return the product rounded if necessary 267 */ 268 private static final long multiply32(DecimalRounding rounding, long uDecimal1, ScaleMetrics scaleMetrics2, long uDecimal2) { 269 final long u1xu2 = uDecimal1 * uDecimal2; 270 final long u1xu2d = scaleMetrics2.divideByScaleFactor(u1xu2); 271 final long u1xu2r = u1xu2 - scaleMetrics2.multiplyByScaleFactor(u1xu2d); 272 return u1xu2d + Rounding.calculateRoundingIncrement(rounding, u1xu2d, u1xu2r, scaleMetrics2.getScaleFactor()); 273 } 274 275 /** 276 * Calculates the multiple {@code uDecimal1 * uDecimal2 / scaleFactor} 277 * without rounding checking for overflows. 278 * 279 * @param arith 280 * the arithmetic with access to scale metrics etc. 281 * @param uDecimal1 282 * the first unscaled decimal factor 283 * @param uDecimal2 284 * the second unscaled decimal factor 285 * @return the multiplication result without rounding and with overflow checks 286 */ 287 public static final long multiplyChecked(final DecimalArithmetic arith, final long uDecimal1, final long uDecimal2) { 288 final SpecialMultiplicationResult special = SpecialMultiplicationResult.getFor(arith, uDecimal1, uDecimal2); 289 if (special != null) { 290 return special.multiply(arith, uDecimal1, uDecimal2); 291 } 292 final ScaleMetrics scaleMetrics = arith.getScaleMetrics(); 293 return multiplyChecked(scaleMetrics, uDecimal1, scaleMetrics, uDecimal2); 294 } 295 296 /** 297 * Calculates checked multiplication by an unscaled value with the given scale 298 * without rounding. 299 * 300 * @param arith 301 * the decimal arithmetics associated with the first factor 302 * @param uDecimal 303 * the unscaled decimal factor 304 * @param unscaled 305 * the second unscaled factor 306 * @param scale 307 * the scale of the second factor 308 * @return the multiplication result without rounding and with overflow checks 309 */ 310 public static final long multiplyByUnscaledChecked(DecimalArithmetic arith, long uDecimal, long unscaled, int scale) { 311 if (scale > Scales.MAX_SCALE) { 312 throw new IllegalArgumentException("Illegal scale, must be <=" + Scales.MAX_SCALE + " but was " + scale); 313 } 314 if (uDecimal == 0 | unscaled == 0) { 315 return 0; 316 } else if (scale == 0) { 317 return arith.multiplyByLong(uDecimal, unscaled); 318 } else if (scale < 0) { 319 final long unscaledResult = Checked.multiplyLong(uDecimal, unscaled); 320 return Pow10.divideByPowerOf10Checked(arith, unscaledResult, scale); 321 } 322 final ScaleMetrics scaleMetrics = Scales.getScaleMetrics(scale); 323 return multiplyChecked(arith.getScaleMetrics(), uDecimal, scaleMetrics, unscaled); 324 } 325 326 /** 327 * Calculates checked multiplication by an unscaled value with the given scale 328 * without rounding. 329 * 330 * @param scaleMetrics1 331 * the scale matrics associated with the first factor 332 * @param uDecimal1 333 * the first unscaled decimal factor 334 * @param scaleMetrics2 335 * the scale matrics associated with the second factor 336 * @param uDecimal2 337 * the second unscaled decimal factor 338 * @return the multiplication result without rounding and with overflow checks 339 */ 340 private static final long multiplyChecked(ScaleMetrics scaleMetrics1, long uDecimal1, ScaleMetrics scaleMetrics2, long uDecimal2) { 341 try { 342 if (doesProductFitInLong(uDecimal1, uDecimal2)) { 343 return scaleMetrics2.divideByScaleFactor(uDecimal1 * uDecimal2); 344 } 345 346 final int scale = scaleMetrics2.getScale(); 347 if (scale <= 9) { 348 //use scale to split into 2 parts: i (integral) and f (fractional) 349 //with this scale, the low order product f1*f2 fits in a long 350 final long i1 = scaleMetrics2.divideByScaleFactor(uDecimal1); 351 final long i2 = scaleMetrics2.divideByScaleFactor(uDecimal2); 352 final long f1 = uDecimal1 - scaleMetrics2.multiplyByScaleFactor(i1); 353 final long f2 = uDecimal2 - scaleMetrics2.multiplyByScaleFactor(i2); 354 final long i1xf2 = i1 * f2;//cannot overflow 355 final long f1xf2 = scaleMetrics2.divideByScaleFactor(f1 * f2);//product fits for this scale, hence unchecked 356 //add it all up now, every operation checked 357 long result = Checked.multiplyLong(uDecimal1, i2); 358 result = Checked.addLong(result, i1xf2); 359 result = Checked.addLong(result, f1xf2); 360 return result; 361 } else { 362 //use scale9 to split into 2 parts: h (high) and l (low) 363 final ScaleMetrics scaleDiff09 = Scales.getScaleMetrics(scale - 9); 364 final ScaleMetrics scaleDiff18 = Scales.getScaleMetrics(18 - scale); 365 final long h1 = SCALE9F.divideByScaleFactor(uDecimal1); 366 final long h2 = SCALE9F.divideByScaleFactor(uDecimal2); 367 final long l1 = uDecimal1 - SCALE9F.multiplyByScaleFactor(h1); 368 final long l2 = uDecimal2 - SCALE9F.multiplyByScaleFactor(h2); 369 final long h1xh2 = Checked.multiplyLong(h1, h2);//checked 370 final long h1xl2 = h1 * l2;//cannot overflow 371 final long h2xl1 = h2 * l1;//cannot overflow 372 final long l1xl2d = SCALE9F.divideByScaleFactor(l1 * l2);//product fits for scale 9, hence unchecked 373 final long h1xl2d = scaleDiff09.divideByScaleFactor(h1xl2); 374 final long h2xl1d = scaleDiff09.divideByScaleFactor(h2xl1); 375 final long h1xl2r = h1xl2 - scaleDiff09.multiplyByScaleFactor(h1xl2d); 376 final long h2xl1r = h2xl1 - scaleDiff09.multiplyByScaleFactor(h2xl1d); 377 //add it all up now, every operation checked 378 long result = scaleDiff18.multiplyByScaleFactorExact(h1xh2); 379 result = Checked.addLong(result, h1xl2d); 380 result = Checked.addLong(result, h2xl1d); 381 result = Checked.addLong(result, scaleDiff09.divideByScaleFactor(h1xl2r + h2xl1r + l1xl2d)); 382 return result; 383 } 384 } catch (ArithmeticException e) { 385 throw Exceptions.newArithmeticExceptionWithCause("Overflow: " + scaleMetrics1.toString(uDecimal1) + " * " + scaleMetrics2.toString(uDecimal2), e); 386 } 387 } 388 389 /** 390 * Calculates the multiple {@code uDecimal1 * uDecimal2 / scaleFactor} 391 * with rounding. 392 * 393 * @param arith 394 * the arithmetic with access to scale metrics etc. 395 * @param rounding 396 * the rounding to apply for truncated decimals 397 * @param uDecimal1 398 * the first unscaled decimal factor 399 * @param uDecimal2 400 * the second unscaled decimal factor 401 * 402 * @return the multiplication result with rounding and overflow checking 403 */ 404 public static final long multiplyChecked(DecimalArithmetic arith, DecimalRounding rounding, long uDecimal1, long uDecimal2) { 405 final SpecialMultiplicationResult special = SpecialMultiplicationResult.getFor(arith, uDecimal1, uDecimal2); 406 if (special != null) { 407 return special.multiply(arith, uDecimal1, uDecimal2); 408 } 409 final ScaleMetrics scaleMetrics = arith.getScaleMetrics(); 410 return multiplyChecked(rounding, scaleMetrics, uDecimal1, scaleMetrics, uDecimal2); 411 } 412 413 /** 414 * Calculates checked multiplication by an unscaled value with the given 415 * scale with rounding. 416 * 417 * @param arith 418 * the arithmetics associated with {@code uDecimal} 419 * @param rounding 420 * the rounding to apply 421 * @param uDecimal 422 * the unscaled decimal factor 423 * @param unscaled 424 * the second unscaled factor 425 * @param scale 426 * the scale of the second factor 427 * @return the multiplication result with rounding and overflow checks 428 */ 429 public static final long multiplyByUnscaledChecked(DecimalArithmetic arith, DecimalRounding rounding, long uDecimal, long unscaled, int scale) { 430 if (scale > Scales.MAX_SCALE) { 431 throw new IllegalArgumentException("Illegal scale, must be <=" + Scales.MAX_SCALE + " but was " + scale); 432 } 433 if (uDecimal == 0 | unscaled == 0) { 434 return 0; 435 } else if (scale == 0) { 436 return arith.multiplyByLong(uDecimal, unscaled); 437 } else if (scale < 0) { 438 final long unscaledResult = Checked.multiplyLong(uDecimal, unscaled); 439 return Pow10.divideByPowerOf10Checked(arith, rounding, unscaledResult, scale); 440 } 441 final ScaleMetrics scaleMetrics2 = Scales.getScaleMetrics(scale); 442 return multiplyChecked(rounding, arith.getScaleMetrics(), uDecimal, scaleMetrics2, unscaled); 443 } 444 445 /** 446 * Calculates the checked multiple 447 * {@code uDecimal1 * uDecimal2 / scaleFactor2} with rounding. 448 * 449 * @param rounding 450 * the rounding to apply for truncated decimals 451 * @param scaleMetrics1 452 * the scale metrics of the first factor 453 * @param uDecimal1 454 * the first unscaled decimal factor 455 * @param scaleMetrics2 456 * the scale metrics of the second factor 457 * @param uDecimal2 458 * the second unscaled decimal factor 459 * @return the multiplication result with rounding and overflow checking 460 */ 461 private static final long multiplyChecked(DecimalRounding rounding, ScaleMetrics scaleMetrics1, long uDecimal1, ScaleMetrics scaleMetrics2, long uDecimal2) { 462 try { 463 if (doesProductFitInLong(uDecimal1, uDecimal2)) { 464 //product fits in long, just do it 465 return multiply32(rounding, uDecimal1, scaleMetrics2, uDecimal2); 466 } 467 468 final int scale = scaleMetrics2.getScale(); 469 if (scale <= 9) { 470 //use scale to split into 2 parts: i (integral) and f (fractional) 471 //with this scale, the low order product f1*f2 fits in a long 472 final long i1 = scaleMetrics2.divideByScaleFactor(uDecimal1); 473 final long i2 = scaleMetrics2.divideByScaleFactor(uDecimal2); 474 final long f1 = uDecimal1 - scaleMetrics2.multiplyByScaleFactor(i1); 475 final long f2 = uDecimal2 - scaleMetrics2.multiplyByScaleFactor(i2); 476 final long i1xf2 = i1 * f2;//cannot overflow 477 final long f1xf2 = f1 * f2;//cannot overflow for this scale 478 final long f1xf2d = scaleMetrics2.divideByScaleFactor(f1xf2); 479 final long f1xf2r = f1xf2 - scaleMetrics2.multiplyByScaleFactor(f1xf2d); 480 //add it all up now, every operation checked 481 long result = Checked.multiplyLong(uDecimal1, i2); 482 result = Checked.addLong(result, i1xf2); 483 result = Checked.addLong(result, f1xf2d); 484 485 return result + Rounding.calculateRoundingIncrement(rounding, result, f1xf2r, scaleMetrics2.getScaleFactor()); 486 } else { 487 //use scale9 to split into 2 parts: h (high) and l (low) 488 final ScaleMetrics scaleDiff09 = Scales.getScaleMetrics(scale - 9); 489 final ScaleMetrics scaleDiff18 = Scales.getScaleMetrics(18 - scale); 490 final long h1 = SCALE9F.divideByScaleFactor(uDecimal1); 491 final long h2 = SCALE9F.divideByScaleFactor(uDecimal2); 492 final long l1 = uDecimal1 - SCALE9F.multiplyByScaleFactor(h1); 493 final long l2 = uDecimal2 - SCALE9F.multiplyByScaleFactor(h2); 494 final long h1xl2 = h1 * l2; 495 final long h2xl1 = h2 * l1; 496 final long l1xl2 = l1 * l2; 497 final long l1xl2d = SCALE9F.divideByScaleFactor(l1xl2); 498 final long h1xl2d = scaleDiff09.divideByScaleFactor(h1xl2); 499 final long h2xl1d = scaleDiff09.divideByScaleFactor(h2xl1); 500 final long h1xl2r = h1xl2 - scaleDiff09.multiplyByScaleFactor(h1xl2d); 501 final long h2xl1r = h2xl1 - scaleDiff09.multiplyByScaleFactor(h2xl1d); 502 final long l1xl2r = l1xl2 - SCALE9F.multiplyByScaleFactor(l1xl2d); 503 final long h1xl2_h2xl1_l1xl1 = h1xl2r + h2xl1r + l1xl2d; 504 final long h1xl2_h2xl1_l1xl1d = scaleDiff09.divideByScaleFactor(h1xl2_h2xl1_l1xl1); 505 final long h1xl2_h2xl1_l1xl1r = h1xl2_h2xl1_l1xl1 - scaleDiff09.multiplyByScaleFactorExact(h1xl2_h2xl1_l1xl1d); 506 507 final long h1xh2 = Checked.multiplyLong(h1, h2);//checked 508 //add it all up now, every operation checked 509 long result = scaleDiff18.multiplyByScaleFactorExact(h1xh2); 510 result = Checked.addLong(result, h1xl2d); 511 result = Checked.addLong(result, h2xl1d); 512 result = Checked.addLong(result, scaleDiff09.divideByScaleFactor(h1xl2r + h2xl1r + l1xl2d));//inner sum cannot overflow 513 514 final long remainder = SCALE9F.multiplyByScaleFactor(h1xl2_h2xl1_l1xl1r) + l1xl2r;//cannot overflow 515 return Checked.addLong(result, Rounding.calculateRoundingIncrement(rounding, result, remainder, scaleMetrics2.getScaleFactor())); 516 } 517 } catch (ArithmeticException e) { 518 Exceptions.rethrowIfRoundingNecessary(e); 519 throw Exceptions.newArithmeticExceptionWithCause("Overflow: " + scaleMetrics1.toString(uDecimal1) + " * " + scaleMetrics2.toString(uDecimal2), e); 520 } 521 } 522 523 //no instances 524 private Mul() { 525 } 526}