001/** 002 * Copyright (c) 2012, 2015, Credit Suisse (Anatole Tresch), Werner Keil and others by the @author tag. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 005 * use this file except in compliance with the License. You may obtain a copy of 006 * the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 013 * License for the specific language governing permissions and limitations under 014 * the License. 015 */ 016package org.javamoney.moneta; 017 018import org.javamoney.moneta.ToStringMonetaryAmountFormat.ToStringMonetaryAmountFormatStyle; 019import org.javamoney.moneta.internal.FastMoneyAmountBuilder; 020import org.javamoney.moneta.spi.DefaultNumberValue; 021import org.javamoney.moneta.spi.MonetaryConfig; 022import org.javamoney.moneta.spi.MoneyUtils; 023 024import javax.money.*; 025import javax.money.format.MonetaryAmountFormat; 026 027import java.io.Serializable; 028import java.math.BigDecimal; 029import java.util.Objects; 030import java.util.logging.Level; 031import java.util.logging.Logger; 032 033/** 034 * <code>long</code> based implementation of {@link MonetaryAmount}.This class internally uses a 035 * single long number as numeric representation, which basically is interpreted as minor units.<p> 036 * It suggested to have a performance advantage of a 10-15 times faster compared to {@link Money}, 037 * which internally uses {@link BigDecimal}. Nevertheless this comes with a price of less precision. 038 * As an example performing the following calculation one million times, results in slightly 039 * different results: 040 * </p> 041 * <pre><code> 042 * Money money1 = money1.add(Money.of(1234567.3444, "EUR")); 043 * money1 = money1.subtract(Money.of(232323, "EUR")); 044 * money1 = money1.multiply(3.4); 045 * money1 = money1.divide(5.456); 046 * </code></pre> 047 * <p> 048 * Executed one million (1000000) times this results in {@code EUR 1657407.962529182}, calculated in 049 * 3680 ms, or roughly 3ns/loop. 050 * <p> 051 * whereas 052 * </p> 053 * <pre><code> 054 * FastMoney money1 = money1.add(FastMoney.of(1234567.3444, "EUR")); 055 * money1 = money1.subtract(FastMoney.of(232323, "EUR")); 056 * money1 = money1.multiply(3.4); 057 * money1 = money1.divide(5.456); 058 * </code></pre> 059 * <p> 060 * executed one million (1000000) times results in {@code EUR 1657407.96251}, calculated in 179 ms, 061 * which is less than 1ns/loop. 062 * </p><p> 063 * Also note than mixing up types my drastically change the performance behavior. E.g. replacing the 064 * code above with the following: * 065 * </p> 066 * <pre><code> 067 * FastMoney money1 = money1.add(Money.of(1234567.3444, "EUR")); 068 * money1 = money1.subtract(FastMoney.of(232323, "EUR")); 069 * money1 = money1.multiply(3.4); 070 * money1 = money1.divide(5.456); 071 * </code></pre> 072 * <p> 073 * executed one million (1000000) times may execute significantly longer, since monetary amount type 074 * conversion is involved. 075 * </p><p> 076 * Basically, when mixing amount implementations, the performance of the amount, on which most of 077 * the operations are operated, has the most significant impact on the overall performance behavior. 078 * 079 * @author Anatole Tresch 080 * @author Werner Keil 081 * @version 1.0 082 */ 083public final class FastMoney implements MonetaryAmount, Comparable<MonetaryAmount>, Serializable { 084 085 private static final long serialVersionUID = 1L; 086 087 /** 088 * The logger used. 089 */ 090 private static final Logger LOG = Logger.getLogger(FastMoney.class.getName()); 091 092 /** 093 * The currency of this amount. 094 */ 095 private final CurrencyUnit currency; 096 097 /** 098 * The numeric part of this amount. 099 */ 100 private final long number; 101 102 /** 103 * The current scale represented by the number. 104 */ 105 private static final int SCALE = 5; 106 107 /** 108 * the {@link MonetaryContext} used by this instance, e.g. on division. 109 */ 110 private static final MonetaryContext MONETARY_CONTEXT = 111 MonetaryContextBuilder.of(FastMoney.class).setMaxScale(SCALE).setFixedScale(true).setPrecision(19).build(); 112 113 /** 114 * Maximum possible value supported, using XX (no currency). 115 */ 116 public static final FastMoney MAX_VALUE = new FastMoney(Long.MAX_VALUE, Monetary.getCurrency("XXX")); 117 /** 118 * Maximum possible numeric value supported. 119 */ 120 private static final BigDecimal MAX_BD = MAX_VALUE.getBigDecimal(); 121 /** 122 * Minimum possible value supported, using XX (no currency). 123 */ 124 public static final FastMoney MIN_VALUE = new FastMoney(Long.MIN_VALUE, Monetary.getCurrency("XXX")); 125 /** 126 * Minimum possible numeric value supported. 127 */ 128 private static final BigDecimal MIN_BD = MIN_VALUE.getBigDecimal(); 129 130 131 /** 132 * Creates a new instance os {@link FastMoney}. 133 * 134 * @param currency the currency, not null. 135 * @param number the amount, not null. 136 */ 137 private FastMoney(Number number, CurrencyUnit currency, boolean allowInternalRounding) { 138 Objects.requireNonNull(currency, "Currency is required."); 139 this.currency = currency; 140 Objects.requireNonNull(number, "Number is required."); 141 this.number = getInternalNumber(number, allowInternalRounding); 142 } 143 144 /** 145 * Creates a new instance os {@link FastMoney}. 146 * 147 * @param currency the currency, not null. 148 * @param numberValue the numeric value, not null. 149 */ 150 private FastMoney(NumberValue numberValue, CurrencyUnit currency, boolean allowInternalRounding) { 151 Objects.requireNonNull(currency, "Currency is required."); 152 this.currency = currency; 153 Objects.requireNonNull(numberValue, "Number is required."); 154 this.number = getInternalNumber(numberValue.numberValue(BigDecimal.class), allowInternalRounding); 155 } 156 157 /** 158 * Creates a new instance os {@link FastMoney}. 159 * 160 * @param number The format number value 161 * @param currency the currency, not null. 162 */ 163 private FastMoney(long number, CurrencyUnit currency) { 164 Objects.requireNonNull(currency, "Currency is required."); 165 this.currency = currency; 166 this.number = number; 167 } 168 169 /** 170 * Returns the amount’s currency, modelled as {@link CurrencyUnit}. 171 * Implementations may co-variantly change the return type to a more 172 * specific implementation of {@link CurrencyUnit} if desired. 173 * 174 * @return the currency, never {@code null} 175 * @see javax.money.MonetaryAmount#getCurrency() 176 */ 177 @Override 178 public CurrencyUnit getCurrency() { 179 return currency; 180 } 181 182 /** 183 * Access the {@link MonetaryContext} used by this instance. 184 * 185 * @return the {@link MonetaryContext} used, never null. 186 * @see javax.money.MonetaryAmount#getContext() 187 */ 188 @Override 189 public MonetaryContext getContext() { 190 return MONETARY_CONTEXT; 191 } 192 193 private long getInternalNumber(Number number, boolean allowInternalRounding) { 194 BigDecimal bd = MoneyUtils.getBigDecimal(number); 195 if (!allowInternalRounding && bd.scale() > SCALE) { 196 throw new ArithmeticException(number + " can not be represented by this class, scale > " + SCALE); 197 } 198 if (bd.compareTo(MIN_BD) < 0) { 199 throw new ArithmeticException("Overflow: " + number + " < " + MIN_BD); 200 } else if (bd.compareTo(MAX_BD) > 0) { 201 throw new ArithmeticException("Overflow: " + number + " > " + MAX_BD); 202 } 203 return bd.movePointRight(SCALE).longValue(); 204 } 205 206 207 /** 208 * Static factory method for creating a new instance of {@link FastMoney}. 209 * 210 * @param currency The target currency, not null. 211 * @param numberBinding The numeric part, not null. 212 * @return A new instance of {@link FastMoney}. 213 */ 214 public static FastMoney of(NumberValue numberBinding, CurrencyUnit currency) { 215 return new FastMoney(numberBinding, currency, false); 216 } 217 218 /** 219 * Static factory method for creating a new instance of {@link FastMoney}. 220 * 221 * @param currency The target currency, not null. 222 * @param number The numeric part, not null. 223 * @return A new instance of {@link FastMoney}. 224 */ 225 public static FastMoney of(Number number, CurrencyUnit currency) { 226 return new FastMoney(number, currency, false); 227 } 228 229 /** 230 * Static factory method for creating a new instance of {@link FastMoney}. 231 * 232 * @param currencyCode The target currency as currency code. 233 * @param number The numeric part, not null. 234 * @return A new instance of {@link FastMoney}. 235 */ 236 public static FastMoney of(Number number, String currencyCode) { 237 CurrencyUnit currency = Monetary.getCurrency(currencyCode); 238 return of(number, currency); 239 } 240 241 /** 242 * Obtains an instance of {@link FastMoney} representing zero. 243 * @param currency 244 * @return an instance of {@link FastMoney} representing zero. 245 * @since 1.0.1 246 */ 247 public static FastMoney zero(CurrencyUnit currency) { 248 return of(BigDecimal.ZERO, currency); 249 } 250 251 /** 252 * Obtains an instance of {@code FastMoney} from an amount in minor units. 253 * For example, {@code ofMinor(USD, 1234)} creates the instance {@code USD 12.34}. 254 * @param currency the currency, not null 255 * @param amountMinor the amount of money in the minor division of the currency 256 * @return the monetary amount from minor units 257 * @see {@link CurrencyUnit#getDefaultFractionDigits()} 258 * @see {@link FastMoney#ofMinor(CurrencyUnit, long, int)} 259 * @throws NullPointerException when the currency is null 260 * @throws IllegalArgumentException when {@link CurrencyUnit#getDefaultFractionDigits()} is lesser than zero. 261 * @since 1.0.1 262 */ 263 public static FastMoney ofMinor(CurrencyUnit currency, long amountMinor) { 264 return ofMinor(currency, amountMinor, currency.getDefaultFractionDigits()); 265 } 266 267 /** 268 * Obtains an instance of {@code FastMoney} from an amount in minor units. 269 * For example, {@code ofMinor(USD, 1234, 2)} creates the instance {@code USD 12.34}. 270 * @param currency the currency, not null 271 * @param amountMinor the amount of money in the minor division of the currency 272 * @param factionDigits number of digits 273 * @return the monetary amount from minor units 274 * @see {@link CurrencyUnit#getDefaultFractionDigits()} 275 * @see {@link FastMoney#ofMinor(CurrencyUnit, long, int)} 276 * @throws NullPointerException when the currency is null 277 * @throws IllegalArgumentException when the factionDigits is negative 278 * @since 1.0.1 279 */ 280 public static FastMoney ofMinor(CurrencyUnit currency, long amountMinor, int factionDigits) { 281 if(factionDigits < 0) { 282 throw new IllegalArgumentException("The factionDigits cannot be negative"); 283 } 284 return of(BigDecimal.valueOf(amountMinor, factionDigits), currency); 285 } 286 287 @Override 288 public int compareTo(MonetaryAmount o) { 289 Objects.requireNonNull(o); 290 int compare = getCurrency().getCurrencyCode().compareTo(o.getCurrency().getCurrencyCode()); 291 if (compare == 0) { 292 compare = getNumber().numberValue(BigDecimal.class).compareTo(o.getNumber().numberValue(BigDecimal.class)); 293 } 294 return compare; 295 } 296 297 @Override 298 public int hashCode() { 299 return Objects.hash(currency, number); 300 } 301 302 @Override 303 public boolean equals(Object obj) { 304 if (obj == this) { 305 return true; 306 } 307 if (obj instanceof FastMoney) { 308 FastMoney other = (FastMoney) obj; 309 return Objects.equals(currency, other.currency) && Objects.equals(number, other.number); 310 } 311 return false; 312 } 313 314 315 @Override 316 public FastMoney abs() { 317 if (this.isPositiveOrZero()) { 318 return this; 319 } 320 return this.negate(); 321 } 322 323 @Override 324 public FastMoney add(MonetaryAmount amount) { 325 checkAmountParameter(amount); 326 if (amount.isZero()) { 327 return this; 328 } 329 return new FastMoney(Math.addExact(this.number, getInternalNumber(amount.getNumber(), false)), getCurrency()); 330 } 331 332 private void checkAmountParameter(MonetaryAmount amount) { 333 MoneyUtils.checkAmountParameter(amount, this.currency); 334 // numeric check for overflow... 335 if (amount.getNumber().getScale() > SCALE) { 336 throw new ArithmeticException("Parameter exceeds maximal scale: " + SCALE); 337 } 338 if (amount.getNumber().getPrecision() > MAX_BD.precision()) { 339 throw new ArithmeticException("Parameter exceeds maximal precision: " + SCALE); 340 } 341 } 342 343 344 @Override 345 public FastMoney divide(Number divisor) { 346 if (NumberVerifier.isInfinityAndNotNaN(divisor)) { 347 return new FastMoney(0L, getCurrency()); 348 } 349 checkNumber(divisor); 350 if (isOne(divisor)) { 351 return this; 352 } 353 return new FastMoney(Math.round(this.number / divisor.doubleValue()), getCurrency()); 354 } 355 356 @Override 357 public FastMoney[] divideAndRemainder(Number divisor) { 358 if (NumberVerifier.isInfinityAndNotNaN(divisor)) { 359 FastMoney zero = new FastMoney(0L, getCurrency()); 360 return new FastMoney[]{zero, zero}; 361 } 362 checkNumber(divisor); 363 BigDecimal div = MoneyUtils.getBigDecimal(divisor); 364 BigDecimal[] res = getBigDecimal().divideAndRemainder(div); 365 return new FastMoney[]{new FastMoney(res[0], getCurrency(), true), new FastMoney(res[1], getCurrency(), true)}; 366 } 367 368 @Override 369 public FastMoney divideToIntegralValue(Number divisor) { 370 if (NumberVerifier.isInfinityAndNotNaN(divisor)) { 371 return new FastMoney(0L, getCurrency()); 372 } 373 checkNumber(divisor); 374 if (isOne(divisor)) { 375 return this; 376 } 377 BigDecimal div = MoneyUtils.getBigDecimal(divisor); 378 return new FastMoney(getBigDecimal().divideToIntegralValue(div), getCurrency(), false); 379 } 380 381 @Override 382 public FastMoney multiply(Number multiplicand) { 383 NumberVerifier.checkNoInfinityOrNaN(multiplicand); 384 checkNumber(multiplicand); 385 if (isOne(multiplicand)) { 386 return this; 387 } 388 return new FastMoney(Math.multiplyExact(this.number, getInternalNumber(multiplicand, false)) / 100000L, 389 getCurrency()); 390 } 391 392 @Override 393 public FastMoney negate() { 394 return new FastMoney(Math.multiplyExact(this.number, -1), getCurrency()); 395 } 396 397 @Override 398 public FastMoney plus() { 399 return this; 400 } 401 402 @Override 403 public FastMoney subtract(MonetaryAmount subtrahend) { 404 checkAmountParameter(subtrahend); 405 if (subtrahend.isZero()) { 406 return this; 407 } 408 return new FastMoney(Math.subtractExact(this.number, getInternalNumber(subtrahend.getNumber(), false)), 409 getCurrency()); 410 } 411 412 @Override 413 public FastMoney remainder(Number divisor) { 414 checkNumber(divisor); 415 return new FastMoney(this.number % getInternalNumber(divisor, false), getCurrency()); 416 } 417 418 private boolean isOne(Number number) { 419 BigDecimal bd = MoneyUtils.getBigDecimal(number); 420 try { 421 return bd.scale() == 0 && bd.longValueExact() == 1L; 422 } catch (Exception e) { 423 // The only way to end up here is that longValueExact throws an ArithmeticException, 424 // so the amount is definitively not equal to 1. 425 return false; 426 } 427 } 428 429 @Override 430 public FastMoney scaleByPowerOfTen(int power) { 431 return new FastMoney(getNumber().numberValue(BigDecimal.class).scaleByPowerOfTen(power), getCurrency(), true); 432 } 433 434 @Override 435 public boolean isZero() { 436 return this.number == 0L; 437 } 438 439 @Override 440 public boolean isPositive() { 441 return this.number > 0L; 442 } 443 444 @Override 445 public boolean isPositiveOrZero() { 446 return this.number >= 0L; 447 } 448 449 @Override 450 public boolean isNegative() { 451 return this.number < 0L; 452 } 453 454 @Override 455 public boolean isNegativeOrZero() { 456 return this.number <= 0L; 457 } 458 459 public int getScale() { 460 return FastMoney.SCALE; 461 } 462 463 public int getPrecision() { 464 return getNumber().numberValue(BigDecimal.class).precision(); 465 } 466 467 @Override 468 public int signum() { 469 if (this.number < 0) { 470 return -1; 471 } 472 if (this.number == 0) { 473 return 0; 474 } 475 return 1; 476 } 477 478 @Override 479 public boolean isLessThan(MonetaryAmount amount) { 480 checkAmountParameter(amount); 481 return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) < 0; 482 } 483 484 public boolean isLessThan(Number number) { 485 checkNumber(number); 486 return getBigDecimal().compareTo(MoneyUtils.getBigDecimal(number)) < 0; 487 } 488 489 @Override 490 public boolean isLessThanOrEqualTo(MonetaryAmount amount) { 491 checkAmountParameter(amount); 492 return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) <= 0; 493 } 494 495 public boolean isLessThanOrEqualTo(Number number) { 496 checkNumber(number); 497 return getBigDecimal().compareTo(MoneyUtils.getBigDecimal(number)) <= 0; 498 } 499 500 501 @Override 502 public boolean isGreaterThan(MonetaryAmount amount) { 503 checkAmountParameter(amount); 504 return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) > 0; 505 } 506 507 public boolean isGreaterThan(Number number) { 508 checkNumber(number); 509 return getBigDecimal().compareTo(MoneyUtils.getBigDecimal(number)) > 0; 510 } 511 512 @Override 513 public boolean isGreaterThanOrEqualTo(MonetaryAmount amount) { 514 checkAmountParameter(amount); 515 return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) >= 0; 516 } 517 518 public boolean isGreaterThanOrEqualTo(Number number) { 519 checkNumber(number); 520 return getBigDecimal().compareTo(MoneyUtils.getBigDecimal(number)) >= 0; 521 } 522 523 @Override 524 public boolean isEqualTo(MonetaryAmount amount) { 525 checkAmountParameter(amount); 526 return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) == 0; 527 } 528 529 public boolean hasSameNumberAs(Number number) { 530 checkNumber(number); 531 try { 532 return this.number == getInternalNumber(number, false); 533 } catch (ArithmeticException e) { 534 return false; 535 } 536 } 537 538 539 /** 540 * Gets the number representation of the numeric value of this item. 541 * 542 * @return The {@link Number} representation matching best. 543 */ 544 @Override 545 public NumberValue getNumber() { 546 return new DefaultNumberValue(getBigDecimal()); 547 } 548 549 @Override 550 public String toString() { 551 return currency.toString() + ' ' + getBigDecimal(); 552 } 553 554 // Internal helper methods 555 556 /** 557 * Internal method to check for correct number parameter. 558 * 559 * @param number the number to be checked, including null.. 560 * @throws NullPointerException If the number is null 561 * @throws java.lang.ArithmeticException If the number exceeds the capabilities of this class. 562 */ 563 protected void checkNumber(Number number) { 564 Objects.requireNonNull(number, "Number is required."); 565 // numeric check for overflow... 566 if (number.longValue() > MAX_BD.longValue()) { 567 throw new ArithmeticException("Value exceeds maximal value: " + MAX_BD); 568 } 569 BigDecimal bd = MoneyUtils.getBigDecimal(number); 570 if (bd.precision() > MAX_BD.precision()) { 571 throw new ArithmeticException("Precision exceeds maximal precision: " + MAX_BD.precision()); 572 } 573 if (bd.scale() > SCALE) { 574 if (Boolean.parseBoolean(MonetaryConfig.getConfig() 575 .getOrDefault("org.javamoney.moneta.FastMoney.enforceScaleCompatibility", 576 "false"))) { 577 throw new ArithmeticException("Scale of " + bd + " exceeds maximal scale: " + SCALE); 578 } else { 579 if (LOG.isLoggable(Level.FINEST)) { 580 LOG.finest("Scale exceeds maximal scale of FastMoney (" + SCALE + 581 "), implicit rounding will be applied to " + number); 582 } 583 } 584 } 585 } 586 587 @Override 588 public FastMoney with(MonetaryOperator operator) { 589 Objects.requireNonNull(operator); 590 try { 591 return FastMoney.class.cast(operator.apply(this)); 592 } catch (ArithmeticException e) { 593 throw e; 594 } catch (Exception e) { 595 throw new MonetaryException("Operator failed: " + operator, e); 596 } 597 } 598 599 @Override 600 public <R> R query(MonetaryQuery<R> query) { 601 Objects.requireNonNull(query); 602 try { 603 return query.queryFrom(this); 604 } catch (MonetaryException | ArithmeticException e) { 605 throw e; 606 } catch (Exception e) { 607 throw new MonetaryException("Query failed: " + query, e); 608 } 609 } 610 611 public static FastMoney from(MonetaryAmount amount) { 612 if (FastMoney.class.isInstance(amount)) { 613 return FastMoney.class.cast(amount); 614 } 615 return new FastMoney(amount.getNumber(), amount.getCurrency(), false); 616 } 617 618 /** 619 * Obtains an instance of FastMoney from a text string such as 'EUR 25.25'. 620 * 621 * @param text the text to parse not null 622 * @return FastMoney instance 623 * @throws NullPointerException 624 * @throws NumberFormatException 625 * @throws UnknownCurrencyException 626 */ 627 public static FastMoney parse(CharSequence text) { 628 return parse(text, DEFAULT_FORMATTER); 629 } 630 631 /** 632 * Obtains an instance of FastMoney from a text using specific formatter. 633 * 634 * @param text the text to parse not null 635 * @param formatter the formatter to use not null 636 * @return FastMoney instance 637 */ 638 public static FastMoney parse(CharSequence text, MonetaryAmountFormat formatter) { 639 return from(formatter.parse(text)); 640 } 641 642 private static final ToStringMonetaryAmountFormat DEFAULT_FORMATTER = ToStringMonetaryAmountFormat 643 .of(ToStringMonetaryAmountFormatStyle.FAST_MONEY); 644 645 private BigDecimal getBigDecimal() { 646 return BigDecimal.valueOf(this.number).movePointLeft(SCALE); 647 } 648 649 @Override 650 public FastMoney multiply(double multiplicand) { 651 NumberVerifier.checkNoInfinityOrNaN(multiplicand); 652 if (multiplicand == 1.0) { 653 return this; 654 } 655 if (multiplicand == 0.0) { 656 return new FastMoney(0, this.currency); 657 } 658 return new FastMoney(Math.round(this.number * multiplicand), this.currency); 659 } 660 661 @Override 662 public FastMoney divide(long divisor) { 663 if (divisor == 1L) { 664 return this; 665 } 666 return new FastMoney(this.number / divisor, this.currency); 667 } 668 669 @Override 670 public FastMoney divide(double divisor) { 671 if (NumberVerifier.isInfinityAndNotNaN(divisor)) { 672 return new FastMoney(0L, getCurrency()); 673 } 674 if (divisor == 1.0d) { 675 return this; 676 } 677 return new FastMoney(Math.round(this.number / divisor), getCurrency()); 678 } 679 680 @Override 681 public FastMoney remainder(long divisor) { 682 return remainder(BigDecimal.valueOf(divisor)); 683 } 684 685 @Override 686 public FastMoney remainder(double divisor) { 687 if (NumberVerifier.isInfinityAndNotNaN(divisor)) { 688 return new FastMoney(0L, getCurrency()); 689 } 690 return remainder(new BigDecimal(String.valueOf(divisor))); 691 } 692 693 @Override 694 public FastMoney[] divideAndRemainder(long divisor) { 695 return divideAndRemainder(BigDecimal.valueOf(divisor)); 696 } 697 698 @Override 699 public FastMoney[] divideAndRemainder(double divisor) { 700 if (NumberVerifier.isInfinityAndNotNaN(divisor)) { 701 FastMoney zero = new FastMoney(0L, getCurrency()); 702 return new FastMoney[]{zero, zero}; 703 } else if (divisor == Double.NaN) { 704 throw new ArithmeticException("Not a number: NaN."); 705 } 706 return divideAndRemainder(new BigDecimal(String.valueOf(divisor))); 707 } 708 709 @Override 710 public FastMoney stripTrailingZeros() { 711 return this; 712 } 713 714 @Override 715 public FastMoney multiply(long multiplicand) { 716 if (multiplicand == 1) { 717 return this; 718 } 719 if (multiplicand == 0) { 720 return new FastMoney(0L, this.currency); 721 } 722 return new FastMoney(Math.multiplyExact(multiplicand, this.number), this.currency); 723 } 724 725 @Override 726 public FastMoney divideToIntegralValue(long divisor) { 727 if (divisor == 1) { 728 return this; 729 } 730 return divideToIntegralValue(MoneyUtils.getBigDecimal(divisor)); 731 } 732 733 @Override 734 public FastMoney divideToIntegralValue(double divisor) { 735 if (NumberVerifier.isInfinityAndNotNaN(divisor)) { 736 return new FastMoney(0L, getCurrency()); 737 } 738 if (divisor == 1.0) { 739 return this; 740 } 741 return divideToIntegralValue(MoneyUtils.getBigDecimal(divisor)); 742 } 743 744 @Override 745 public MonetaryAmountFactory<FastMoney> getFactory() { 746 return new FastMoneyAmountBuilder().setAmount(this); 747 } 748 749}