001/** 002 * Copyright (c) 2012, 2014, 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 * @see java.lang.Comparable#compareTo(java.lang.Object) 243 */ 244 @Override 245 public int compareTo(MonetaryAmount o) { 246 Objects.requireNonNull(o); 247 int compare = getCurrency().getCurrencyCode().compareTo(o.getCurrency().getCurrencyCode()); 248 if (compare == 0) { 249 compare = getNumber().numberValue(BigDecimal.class).compareTo(o.getNumber().numberValue(BigDecimal.class)); 250 } 251 return compare; 252 } 253 254 /* 255 * (non-Javadoc) 256 * @see java.lang.Object#hashCode() 257 */ 258 @Override 259 public int hashCode() { 260 return Objects.hash(currency, number); 261 } 262 263 /* 264 * (non-Javadoc) 265 * @see java.lang.Object#equals(java.lang.Object) 266 */ 267 @Override 268 public boolean equals(Object obj) { 269 if (obj == this) { 270 return true; 271 } 272 if (obj instanceof FastMoney) { 273 FastMoney other = (FastMoney) obj; 274 return Objects.equals(currency, other.currency) && Objects.equals(number, other.number); 275 } 276 return false; 277 } 278 279 280 /* 281 * (non-Javadoc) 282 * @see javax.money.MonetaryAmount#abs() 283 */ 284 @Override 285 public FastMoney abs() { 286 if (this.isPositiveOrZero()) { 287 return this; 288 } 289 return this.negate(); 290 } 291 292 // Arithmetic Operations 293 294 /* 295 * (non-Javadoc) 296 * @see javax.money.MonetaryAmount#add(javax.money.MonetaryAmount) 297 */ 298 @Override 299 public FastMoney add(MonetaryAmount amount) { 300 checkAmountParameter(amount); 301 if (amount.isZero()) { 302 return this; 303 } 304 return new FastMoney(Math.addExact(this.number, getInternalNumber(amount.getNumber(), false)), getCurrency()); 305 } 306 307 private void checkAmountParameter(MonetaryAmount amount) { 308 MoneyUtils.checkAmountParameter(amount, this.currency); 309 // numeric check for overflow... 310 if (amount.getNumber().getScale() > SCALE) { 311 throw new ArithmeticException("Parameter exceeds maximal scale: " + SCALE); 312 } 313 if (amount.getNumber().getPrecision() > MAX_BD.precision()) { 314 throw new ArithmeticException("Parameter exceeds maximal precision: " + SCALE); 315 } 316 } 317 318 319 /* 320 * (non-Javadoc) 321 * @see javax.money.MonetaryAmount#divide(java.lang.Number) 322 */ 323 @Override 324 public FastMoney divide(Number divisor) { 325 if (Money.isInfinityAndNotNaN(divisor)) { 326 return new FastMoney(0L, getCurrency()); 327 } 328 checkNumber(divisor); 329 if (isOne(divisor)) { 330 return this; 331 } 332 return new FastMoney(Math.round(this.number / divisor.doubleValue()), getCurrency()); 333 } 334 335 /* 336 * (non-Javadoc) 337 * @see javax.money.MonetaryAmount#divideAndRemainder(java.lang.Number) 338 */ 339 @Override 340 public FastMoney[] divideAndRemainder(Number divisor) { 341 if (Money.isInfinityAndNotNaN(divisor)) { 342 FastMoney zero = new FastMoney(0L, getCurrency()); 343 return new FastMoney[]{zero, zero}; 344 } 345 checkNumber(divisor); 346 if (isOne(divisor)) { 347 return new FastMoney[]{this, FastMoney.of(0, getCurrency())}; 348 } 349 BigDecimal div = MoneyUtils.getBigDecimal(divisor); 350 BigDecimal[] res = getBigDecimal().divideAndRemainder(div); 351 return new FastMoney[]{new FastMoney(res[0], getCurrency(), true), new FastMoney(res[1], getCurrency(), true)}; 352 } 353 354 /* 355 * (non-Javadoc) 356 * @see javax.money.MonetaryAmount#divideToIntegralValue(java.lang.Number) 357 */ 358 @Override 359 public FastMoney divideToIntegralValue(Number divisor) { 360 if (Money.isInfinityAndNotNaN(divisor)) { 361 return new FastMoney(0L, getCurrency()); 362 } 363 checkNumber(divisor); 364 if (isOne(divisor)) { 365 return this; 366 } 367 BigDecimal div = MoneyUtils.getBigDecimal(divisor); 368 return new FastMoney(getBigDecimal().divideToIntegralValue(div), getCurrency(), false); 369 } 370 371 @Override 372 public FastMoney multiply(Number multiplicand) { 373 Money.checkNoInfinityOrNaN(multiplicand); 374 checkNumber(multiplicand); 375 if (isOne(multiplicand)) { 376 return this; 377 } 378 return new FastMoney(Math.multiplyExact(this.number, getInternalNumber(multiplicand, false)) / 100000L, 379 getCurrency()); 380 } 381 382 /* 383 * (non-Javadoc) 384 * @see javax.money.MonetaryAmount#negate() 385 */ 386 @Override 387 public FastMoney negate() { 388 return new FastMoney(Math.multiplyExact(this.number, -1), getCurrency()); 389 } 390 391 /* 392 * (non-Javadoc) 393 * @see javax.money.MonetaryAmount#plus() 394 */ 395 @Override 396 public FastMoney plus() { 397 if (this.number >= 0) { 398 return this; 399 } 400 return new FastMoney(Math.multiplyExact(this.number, -1), getCurrency()); 401 } 402 403 /* 404 * (non-Javadoc) 405 * @see javax.money.MonetaryAmount#subtract(javax.money.MonetaryAmount) 406 */ 407 @Override 408 public FastMoney subtract(MonetaryAmount subtrahend) { 409 checkAmountParameter(subtrahend); 410 if (subtrahend.isZero()) { 411 return this; 412 } 413 return new FastMoney(Math.subtractExact(this.number, getInternalNumber(subtrahend.getNumber(), false)), 414 getCurrency()); 415 } 416 417 /* 418 * (non-Javadoc) 419 * @see javax.money.MonetaryAmount#remainder(java.lang.Number) 420 */ 421 @Override 422 public FastMoney remainder(Number divisor) { 423 checkNumber(divisor); 424 if (isOne(divisor)) { 425 return new FastMoney(0, getCurrency()); 426 } 427 return new FastMoney(this.number % getInternalNumber(divisor, false), getCurrency()); 428 } 429 430 private boolean isOne(Number number) { 431 BigDecimal bd = MoneyUtils.getBigDecimal(number); 432 try { 433 return bd.scale() == 0 && bd.longValueExact() == 1L; 434 } catch (Exception e) { 435 // The only way to end up here is that longValueExact throws an ArithmeticException, 436 // so the amount is definitively not equal to 1. 437 return false; 438 } 439 } 440 441 /* 442 * (non-Javadoc) 443 * @see javax.money.MonetaryAmount#scaleByPowerOfTen(int) 444 */ 445 @Override 446 public FastMoney scaleByPowerOfTen(int power) { 447 return new FastMoney(getNumber().numberValue(BigDecimal.class).scaleByPowerOfTen(power), getCurrency(), true); 448 } 449 450 /* 451 * (non-Javadoc) 452 * @see javax.money.MonetaryAmount#isZero() 453 */ 454 @Override 455 public boolean isZero() { 456 return this.number == 0L; 457 } 458 459 /* 460 * (non-Javadoc) 461 * @see javax.money.MonetaryAmount#isPositive() 462 */ 463 @Override 464 public boolean isPositive() { 465 return this.number > 0L; 466 } 467 468 /* 469 * (non-Javadoc) 470 * @see javax.money.MonetaryAmount#isPositiveOrZero() 471 */ 472 @Override 473 public boolean isPositiveOrZero() { 474 return this.number >= 0L; 475 } 476 477 /* 478 * (non-Javadoc) 479 * @see javax.money.MonetaryAmount#isNegative() 480 */ 481 @Override 482 public boolean isNegative() { 483 return this.number < 0L; 484 } 485 486 /* 487 * (non-Javadoc) 488 * @see javax.money.MonetaryAmount#isNegativeOrZero() 489 */ 490 @Override 491 public boolean isNegativeOrZero() { 492 return this.number <= 0L; 493 } 494 495 /* 496 * (non-Javadoc) 497 * @see javax.money.MonetaryAmount#getScale() 498 */ 499 public int getScale() { 500 return FastMoney.SCALE; 501 } 502 503 /* 504 * (non-Javadoc) 505 * @see javax.money.MonetaryAmount#getPrecision() 506 */ 507 public int getPrecision() { 508 return getNumber().numberValue(BigDecimal.class).precision(); 509 } 510 511 /* 512 * (non-Javadoc) 513 * @see javax.money.MonetaryAmount#signum() 514 */ 515 516 @Override 517 public int signum() { 518 if (this.number < 0) { 519 return -1; 520 } 521 if (this.number == 0) { 522 return 0; 523 } 524 return 1; 525 } 526 527 /* 528 * (non-Javadoc) 529 * @see javax.money.MonetaryAmount#lessThan(javax.money.MonetaryAmount) 530 */ 531 @Override 532 public boolean isLessThan(MonetaryAmount amount) { 533 checkAmountParameter(amount); 534 return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) < 0; 535 } 536 537 /* 538 * (non-Javadoc) 539 * @see javax.money.MonetaryAmount#lessThan(java.lang.Number) 540 */ 541 public boolean isLessThan(Number number) { 542 checkNumber(number); 543 return getBigDecimal().compareTo(MoneyUtils.getBigDecimal(number)) < 0; 544 } 545 546 /* 547 * (non-Javadoc) 548 * @see javax.money.MonetaryAmount#lessThanOrEqualTo(javax.money.MonetaryAmount) 549 */ 550 @Override 551 public boolean isLessThanOrEqualTo(MonetaryAmount amount) { 552 checkAmountParameter(amount); 553 return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) <= 0; 554 } 555 556 /* 557 * (non-Javadoc) 558 * @see javax.money.MonetaryAmount#lessThanOrEqualTo(java.lang.Number) 559 */ 560 public boolean isLessThanOrEqualTo(Number number) { 561 checkNumber(number); 562 return getBigDecimal().compareTo(MoneyUtils.getBigDecimal(number)) <= 0; 563 } 564 565 /* 566 * (non-Javadoc) 567 * @see javax.money.MonetaryAmount#greaterThan(javax.money.MonetaryAmount) 568 */ 569 @Override 570 public boolean isGreaterThan(MonetaryAmount amount) { 571 checkAmountParameter(amount); 572 return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) > 0; 573 } 574 575 /* 576 * (non-Javadoc) 577 * @see javax.money.MonetaryAmount#greaterThan(java.lang.Number) 578 */ 579 public boolean isGreaterThan(Number number) { 580 checkNumber(number); 581 return getBigDecimal().compareTo(MoneyUtils.getBigDecimal(number)) > 0; 582 } 583 584 /* 585 * (non-Javadoc) 586 * @see javax.money.MonetaryAmount#greaterThanOrEqualTo(javax.money.MonetaryAmount ) #see 587 */ 588 @Override 589 public boolean isGreaterThanOrEqualTo(MonetaryAmount amount) { 590 checkAmountParameter(amount); 591 return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) >= 0; 592 } 593 594 /* 595 * (non-Javadoc) 596 * @see javax.money.MonetaryAmount#greaterThanOrEqualTo(java.lang.Number) 597 */ 598 public boolean isGreaterThanOrEqualTo(Number number) { 599 checkNumber(number); 600 return getBigDecimal().compareTo(MoneyUtils.getBigDecimal(number)) >= 0; 601 } 602 603 /* 604 * (non-Javadoc) 605 * @see javax.money.MonetaryAmount#isEqualTo(javax.money.MonetaryAmount) 606 */ 607 @Override 608 public boolean isEqualTo(MonetaryAmount amount) { 609 checkAmountParameter(amount); 610 return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) == 0; 611 } 612 613 /* 614 * (non-Javadoc) 615 * @see javax.money.MonetaryAmount#hasSameNumberAs(java.lang.Number) 616 */ 617 public boolean hasSameNumberAs(Number number) { 618 checkNumber(number); 619 try { 620 return this.number == getInternalNumber(number, false); 621 } catch (ArithmeticException e) { 622 return false; 623 } 624 } 625 626 627 /** 628 * Gets the number representation of the numeric value of this item. 629 * 630 * @return The {@link Number} representation matching best. 631 */ 632 @Override 633 public NumberValue getNumber() { 634 return new DefaultNumberValue(getBigDecimal()); 635 } 636 637 @Override 638 public String toString() { 639 return currency.toString() + ' ' + getBigDecimal(); 640 } 641 642 // Internal helper methods 643 644 /** 645 * Internal method to check for correct number parameter. 646 * 647 * @param number the number to be checked, including null.. 648 * @throws NullPointerException If the number is null 649 * @throws java.lang.ArithmeticException If the number exceeds the capabilities of this class. 650 */ 651 private void checkNumber(Number number) { 652 Objects.requireNonNull(number, "Number is required."); 653 // numeric check for overflow... 654 if (number.longValue() > MAX_BD.longValue()) { 655 throw new ArithmeticException("Value exceeds maximal value: " + MAX_BD); 656 } 657 BigDecimal bd = MoneyUtils.getBigDecimal(number); 658 if (bd.precision() > MAX_BD.precision()) { 659 throw new ArithmeticException("Precision exceeds maximal precision: " + MAX_BD.precision()); 660 } 661 if (bd.scale() > SCALE) { 662 if (Boolean.parseBoolean(MonetaryConfig.getConfig() 663 .getOrDefault("org.javamoney.moneta.FastMoney.enforceScaleCompatibility", 664 "false"))) { 665 throw new ArithmeticException("Scale of " + bd + " exceeds maximal scale: " + SCALE); 666 } else { 667 if (LOG.isLoggable(Level.FINEST)) { 668 LOG.finest("Scale exceeds maximal scale of FastMoney (" + SCALE + 669 "), implicit rounding will be applied to " + number); 670 } 671 } 672 } 673 } 674 675 /* 676 * }(non-Javadoc) 677 * @see javax.money.MonetaryAmount#adjust(javax.money.AmountAdjuster) 678 */ 679 @Override 680 public FastMoney with(MonetaryOperator operator) { 681 Objects.requireNonNull(operator); 682 try { 683 return FastMoney.class.cast(operator.apply(this)); 684 } catch (ArithmeticException e) { 685 throw e; 686 } catch (Exception e) { 687 throw new MonetaryException("Operator failed: " + operator, e); 688 } 689 } 690 691 @Override 692 public <R> R query(MonetaryQuery<R> query) { 693 Objects.requireNonNull(query); 694 try { 695 return query.queryFrom(this); 696 } catch (MonetaryException | ArithmeticException e) { 697 throw e; 698 } catch (Exception e) { 699 throw new MonetaryException("Query failed: " + query, e); 700 } 701 } 702 703 public static FastMoney from(MonetaryAmount amount) { 704 if (FastMoney.class.isInstance(amount)) { 705 return FastMoney.class.cast(amount); 706 } 707 return new FastMoney(amount.getNumber(), amount.getCurrency(), false); 708 } 709 710 /** 711 * Obtains an instance of FastMoney from a text string such as 'EUR 25.25'. 712 * 713 * @param text the text to parse not null 714 * @return FastMoney instance 715 * @throws NullPointerException 716 * @throws NumberFormatException 717 * @throws UnknownCurrencyException 718 */ 719 public static FastMoney parse(CharSequence text) { 720 return parse(text, DEFAULT_FORMATTER); 721 } 722 723 /** 724 * Obtains an instance of FastMoney from a text using specific formatter. 725 * 726 * @param text the text to parse not null 727 * @param formatter the formatter to use not null 728 * @return FastMoney instance 729 */ 730 public static FastMoney parse(CharSequence text, MonetaryAmountFormat formatter) { 731 return from(formatter.parse(text)); 732 } 733 734 private static final ToStringMonetaryAmountFormat DEFAULT_FORMATTER = ToStringMonetaryAmountFormat 735 .of(ToStringMonetaryAmountFormatStyle.FAST_MONEY); 736 737 private BigDecimal getBigDecimal() { 738 return BigDecimal.valueOf(this.number).movePointLeft(SCALE); 739 } 740 741 @Override 742 public FastMoney multiply(double multiplicand) { 743 Money.checkNoInfinityOrNaN(multiplicand); 744 if (multiplicand == 1.0) { 745 return this; 746 } 747 if (multiplicand == 0.0) { 748 return new FastMoney(0, this.currency); 749 } 750 return new FastMoney(Math.round(this.number * multiplicand), this.currency); 751 } 752 753 @Override 754 public FastMoney divide(long divisor) { 755 if (divisor == 1L) { 756 return this; 757 } 758 return new FastMoney(this.number / divisor, this.currency); 759 } 760 761 @Override 762 public FastMoney divide(double divisor) { 763 if (Money.isInfinityAndNotNaN(divisor)) { 764 return new FastMoney(0L, getCurrency()); 765 } 766 if (divisor == 1.0d) { 767 return this; 768 } 769 return new FastMoney(Math.round(this.number / divisor), getCurrency()); 770 } 771 772 @Override 773 public FastMoney remainder(long divisor) { 774 return remainder(BigDecimal.valueOf(divisor)); 775 } 776 777 @Override 778 public FastMoney remainder(double divisor) { 779 if (Money.isInfinityAndNotNaN(divisor)) { 780 return new FastMoney(0L, getCurrency()); 781 } 782 return remainder(new BigDecimal(String.valueOf(divisor))); 783 } 784 785 @Override 786 public FastMoney[] divideAndRemainder(long divisor) { 787 return divideAndRemainder(BigDecimal.valueOf(divisor)); 788 } 789 790 @Override 791 public FastMoney[] divideAndRemainder(double divisor) { 792 if (Money.isInfinityAndNotNaN(divisor)) { 793 FastMoney zero = new FastMoney(0L, getCurrency()); 794 return new FastMoney[]{zero, zero}; 795 } else if (divisor == Double.NaN) { 796 throw new ArithmeticException("Not a number: NaN."); 797 } 798 return divideAndRemainder(new BigDecimal(String.valueOf(divisor))); 799 } 800 801 @Override 802 public FastMoney stripTrailingZeros() { 803 return this; 804 } 805 806 @Override 807 public FastMoney multiply(long multiplicand) { 808 if (multiplicand == 1) { 809 return this; 810 } 811 if (multiplicand == 0) { 812 return new FastMoney(0L, this.currency); 813 } 814 return new FastMoney(Math.multiplyExact(multiplicand, this.number), this.currency); 815 } 816 817 @Override 818 public FastMoney divideToIntegralValue(long divisor) { 819 if (divisor == 1) { 820 return this; 821 } 822 return divideToIntegralValue(MoneyUtils.getBigDecimal(divisor)); 823 } 824 825 @Override 826 public FastMoney divideToIntegralValue(double divisor) { 827 if (Money.isInfinityAndNotNaN(divisor)) { 828 return new FastMoney(0L, getCurrency()); 829 } 830 if (divisor == 1.0) { 831 return this; 832 } 833 return divideToIntegralValue(MoneyUtils.getBigDecimal(divisor)); 834 } 835 836 @Override 837 public MonetaryAmountFactory<FastMoney> getFactory() { 838 return new FastMoneyAmountBuilder().setAmount(this); 839 } 840 841}