001/** 002 * The MIT License (MIT) 003 * 004 * Copyright (c) 2015 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 scaleMetrics2.multiplyByScaleFactor(i1 * i2) + i1 * f2 + i2 * f1 + 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 = scaleMetrics2.multiplyByScaleFactor(i1 * i2) + i1 * f2 + i2 * f1 + 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 i1xi2 = Checked.multiplyLong(i1, i2);//checked 355 final long i1xf2 = i1 * f2;//cannot overflow 356 final long i2xf1 = i2 * f1;//cannot overflow 357 final long f1xf2 = scaleMetrics2.divideByScaleFactor(f1 * f2);//product fits for this scale, hence unchecked 358 //add it all up now, every operation checked 359 long result = scaleMetrics2.multiplyByScaleFactorExact(i1xi2); 360 result = Checked.addLong(result, i1xf2); 361 result = Checked.addLong(result, i2xf1); 362 result = Checked.addLong(result, f1xf2); 363 return result; 364 } else { 365 //use scale9 to split into 2 parts: h (high) and l (low) 366 final ScaleMetrics scaleDiff09 = Scales.getScaleMetrics(scale - 9); 367 final ScaleMetrics scaleDiff18 = Scales.getScaleMetrics(18 - scale); 368 final long h1 = SCALE9F.divideByScaleFactor(uDecimal1); 369 final long h2 = SCALE9F.divideByScaleFactor(uDecimal2); 370 final long l1 = uDecimal1 - SCALE9F.multiplyByScaleFactor(h1); 371 final long l2 = uDecimal2 - SCALE9F.multiplyByScaleFactor(h2); 372 final long h1xh2 = Checked.multiplyLong(h1, h2);//checked 373 final long h1xl2 = h1 * l2;//cannot overflow 374 final long h2xl1 = h2 * l1;//cannot overflow 375 final long l1xl2d = SCALE9F.divideByScaleFactor(l1 * l2);//product fits for scale 9, hence unchecked 376 final long h1xl2d = scaleDiff09.divideByScaleFactor(h1xl2); 377 final long h2xl1d = scaleDiff09.divideByScaleFactor(h2xl1); 378 final long h1xl2r = h1xl2 - scaleDiff09.multiplyByScaleFactor(h1xl2d); 379 final long h2xl1r = h2xl1 - scaleDiff09.multiplyByScaleFactor(h2xl1d); 380 //add it all up now, every operation checked 381 long result = scaleDiff18.multiplyByScaleFactorExact(h1xh2); 382 result = Checked.addLong(result, h1xl2d); 383 result = Checked.addLong(result, h2xl1d); 384 result = Checked.addLong(result, scaleDiff09.divideByScaleFactor(h1xl2r + h2xl1r + l1xl2d)); 385 return result; 386 } 387 } catch (ArithmeticException e) { 388 throw Exceptions.newArithmeticExceptionWithCause("Overflow: " + scaleMetrics1.toString(uDecimal1) + " * " + scaleMetrics2.toString(uDecimal2), e); 389 } 390 } 391 392 /** 393 * Calculates the multiple {@code uDecimal1 * uDecimal2 / scaleFactor} 394 * with rounding. 395 * 396 * @param arith 397 * the arithmetic with access to scale metrics etc. 398 * @param rounding 399 * the rounding to apply for truncated decimals 400 * @param uDecimal1 401 * the first unscaled decimal factor 402 * @param uDecimal2 403 * the second unscaled decimal factor 404 * 405 * @return the multiplication result with rounding and overflow checking 406 */ 407 public static final long multiplyChecked(DecimalArithmetic arith, DecimalRounding rounding, long uDecimal1, long uDecimal2) { 408 final SpecialMultiplicationResult special = SpecialMultiplicationResult.getFor(arith, uDecimal1, uDecimal2); 409 if (special != null) { 410 return special.multiply(arith, uDecimal1, uDecimal2); 411 } 412 final ScaleMetrics scaleMetrics = arith.getScaleMetrics(); 413 return multiplyChecked(rounding, scaleMetrics, uDecimal1, scaleMetrics, uDecimal2); 414 } 415 416 /** 417 * Calculates checked multiplication by an unscaled value with the given 418 * scale with rounding. 419 * 420 * @param arith 421 * the arithmetics associated with {@code uDecimal} 422 * @param rounding 423 * the rounding to apply 424 * @param uDecimal 425 * the unscaled decimal factor 426 * @param unscaled 427 * the second unscaled factor 428 * @param scale 429 * the scale of the second factor 430 * @return the multiplication result with rounding and overflow checks 431 */ 432 public static final long multiplyByUnscaledChecked(DecimalArithmetic arith, DecimalRounding rounding, long uDecimal, long unscaled, int scale) { 433 if (scale > Scales.MAX_SCALE) { 434 throw new IllegalArgumentException("Illegal scale, must be <=" + Scales.MAX_SCALE + " but was " + scale); 435 } 436 if (uDecimal == 0 | unscaled == 0) { 437 return 0; 438 } else if (scale == 0) { 439 return arith.multiplyByLong(uDecimal, unscaled); 440 } else if (scale < 0) { 441 final long unscaledResult = Checked.multiplyLong(uDecimal, unscaled); 442 return Pow10.divideByPowerOf10Checked(arith, rounding, unscaledResult, scale); 443 } 444 final ScaleMetrics scaleMetrics2 = Scales.getScaleMetrics(scale); 445 return multiplyChecked(rounding, arith.getScaleMetrics(), uDecimal, scaleMetrics2, unscaled); 446 } 447 448 /** 449 * Calculates the checked multiple 450 * {@code uDecimal1 * uDecimal2 / scaleFactor2} with rounding. 451 * 452 * @param rounding 453 * the rounding to apply for truncated decimals 454 * @param scaleMetrics1 455 * the scale metrics of the first factor 456 * @param uDecimal1 457 * the first unscaled decimal factor 458 * @param scaleMetrics2 459 * the scale metrics of the second factor 460 * @param uDecimal2 461 * the second unscaled decimal factor 462 * @return the multiplication result with rounding and overflow checking 463 */ 464 private static final long multiplyChecked(DecimalRounding rounding, ScaleMetrics scaleMetrics1, long uDecimal1, ScaleMetrics scaleMetrics2, long uDecimal2) { 465 try { 466 if (doesProductFitInLong(uDecimal1, uDecimal2)) { 467 //product fits in long, just do it 468 return multiply32(rounding, uDecimal1, scaleMetrics2, uDecimal2); 469 } 470 471 final int scale = scaleMetrics2.getScale(); 472 if (scale <= 9) { 473 //use scale to split into 2 parts: i (integral) and f (fractional) 474 //with this scale, the low order product f1*f2 fits in a long 475 final long i1 = scaleMetrics2.divideByScaleFactor(uDecimal1); 476 final long i2 = scaleMetrics2.divideByScaleFactor(uDecimal2); 477 final long f1 = uDecimal1 - scaleMetrics2.multiplyByScaleFactor(i1); 478 final long f2 = uDecimal2 - scaleMetrics2.multiplyByScaleFactor(i2); 479 final long f1xf2 = f1 * f2; 480 final long f1xf2d = scaleMetrics2.divideByScaleFactor(f1xf2); 481 final long f1xf2r = f1xf2 - scaleMetrics2.multiplyByScaleFactor(f1xf2d); 482 483 final long i1xi2 = Checked.multiplyLong(i1, i2);//checked 484 final long i1xf2 = i1 * f2;//cannot overflow 485 final long i2xf1 = i2 * f1;//cannot overflow 486 487 //add it all up now, every operation checked 488 long result = scaleMetrics2.multiplyByScaleFactorExact(i1xi2); 489 result = Checked.addLong(result, i1xf2); 490 result = Checked.addLong(result, i2xf1); 491 result = Checked.addLong(result, f1xf2d); 492 493 return result + Rounding.calculateRoundingIncrement(rounding, result, f1xf2r, scaleMetrics2.getScaleFactor()); 494 } else { 495 //use scale9 to split into 2 parts: h (high) and l (low) 496 final ScaleMetrics scaleDiff09 = Scales.getScaleMetrics(scale - 9); 497 final ScaleMetrics scaleDiff18 = Scales.getScaleMetrics(18 - scale); 498 final long h1 = SCALE9F.divideByScaleFactor(uDecimal1); 499 final long h2 = SCALE9F.divideByScaleFactor(uDecimal2); 500 final long l1 = uDecimal1 - SCALE9F.multiplyByScaleFactor(h1); 501 final long l2 = uDecimal2 - SCALE9F.multiplyByScaleFactor(h2); 502 final long h1xl2 = h1 * l2; 503 final long h2xl1 = h2 * l1; 504 final long l1xl2 = l1 * l2; 505 final long l1xl2d = SCALE9F.divideByScaleFactor(l1xl2); 506 final long h1xl2d = scaleDiff09.divideByScaleFactor(h1xl2); 507 final long h2xl1d = scaleDiff09.divideByScaleFactor(h2xl1); 508 final long h1xl2r = h1xl2 - scaleDiff09.multiplyByScaleFactor(h1xl2d); 509 final long h2xl1r = h2xl1 - scaleDiff09.multiplyByScaleFactor(h2xl1d); 510 final long l1xl2r = l1xl2 - SCALE9F.multiplyByScaleFactor(l1xl2d); 511 final long h1xl2_h2xl1_l1xl1 = h1xl2r + h2xl1r + l1xl2d; 512 final long h1xl2_h2xl1_l1xl1d = scaleDiff09.divideByScaleFactor(h1xl2_h2xl1_l1xl1); 513 final long h1xl2_h2xl1_l1xl1r = h1xl2_h2xl1_l1xl1 - scaleDiff09.multiplyByScaleFactorExact(h1xl2_h2xl1_l1xl1d); 514 515 final long h1xh2 = Checked.multiplyLong(h1, h2);//checked 516 //add it all up now, every operation checked 517 long result = scaleDiff18.multiplyByScaleFactorExact(h1xh2); 518 result = Checked.addLong(result, h1xl2d); 519 result = Checked.addLong(result, h2xl1d); 520 result = Checked.addLong(result, scaleDiff09.divideByScaleFactor(h1xl2r + h2xl1r + l1xl2d));//inner sum cannot overflow 521 522 final long remainder = SCALE9F.multiplyByScaleFactor(h1xl2_h2xl1_l1xl1r) + l1xl2r;//cannot overflow 523 return Checked.addLong(result, Rounding.calculateRoundingIncrement(rounding, result, remainder, scaleMetrics2.getScaleFactor())); 524 } 525 } catch (ArithmeticException e) { 526 Exceptions.rethrowIfRoundingNecessary(e); 527 throw Exceptions.newArithmeticExceptionWithCause("Overflow: " + scaleMetrics1.toString(uDecimal1) + " * " + scaleMetrics2.toString(uDecimal2), e); 528 } 529 } 530 531 //no instances 532 private Mul() { 533 } 534}