org.javamoney.moneta.FastMoney Maven / Gradle / Ivy
Show all versions of moneta-bp Show documentation
/**
* Copyright (c) 2012, 2014, Credit Suisse (Anatole Tresch), Werner Keil and others by the @author tag.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.javamoney.moneta;
import javax.money.CurrencyUnit;
import javax.money.Monetary;
import javax.money.MonetaryAmount;
import javax.money.MonetaryAmountFactory;
import javax.money.MonetaryContext;
import javax.money.MonetaryContextBuilder;
import javax.money.MonetaryException;
import javax.money.MonetaryOperator;
import javax.money.MonetaryQuery;
import javax.money.NumberValue;
import javax.money.format.MonetaryAmountFormat;
import org.javamoney.moneta.internal.FastMoneyAmountBuilder;
import org.javamoney.moneta.spi.DefaultNumberValue;
import org.javamoney.moneta.spi.MonetaryConfig;
import org.javamoney.moneta.spi.MoneyUtils;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* long
based implementation of {@link MonetaryAmount}.This class internally uses a
* single long number as numeric representation, which basically is interpreted as minor units.
* It suggested to have a performance advantage of a 10-15 times faster compared to {@link Money},
* which internally uses {@link BigDecimal}. Nevertheless this comes with a price of less precision.
* As an example performing the following calculation one million times, results in slightly
* different results:
*
*
* Money money1 = money1.add(Money.of("EUR", 1234567.3444));
* money1 = money1.subtract(Money.of("EUR", 232323));
* money1 = money1.multiply(3.4);
* money1 = money1.divide(5.456);
*
*
* Executed one million (1000000) times this results in {@code EUR 1657407.962529182}, calculated in
* 3680 ms, or roughly 3ns/loop.
*
* whereas
*
*
* FastMoney money1 = money1.add(FastMoney.of("EUR", 1234567.3444));
* money1 = money1.subtract(FastMoney.of("EUR", 232323));
* money1 = money1.multiply(3.4);
* money1 = money1.divide(5.456);
*
*
* executed one million (1000000) times results in {@code EUR 1657407.96251}, calculated in 179 ms,
* which is less than 1ns/loop.
*
* Also note than mixing up types my drastically change the performance behavior. E.g. replacing the
* code above with the following: *
*
*
* FastMoney money1 = money1.add(Money.of("EUR", 1234567.3444));
* money1 = money1.subtract(FastMoney.of("EUR", 232323));
* money1 = money1.multiply(3.4);
* money1 = money1.divide(5.456);
*
*
* executed one million (1000000) times may execute significantly longer, since monetary amount type
* conversion is involved.
*
* Basically, when mixing amount implementations, the performance of the amount, on which most of
* the operations are operated, has the most significant impact on the overall performance behavior.
*
* @author Anatole Tresch
* @author Werner Keil
* @version 0.5.2
*/
public final class FastMoney implements MonetaryAmount, Comparable, Serializable {
private static final long serialVersionUID = 1L;
/**
* The logger used.
*/
private static final Logger LOG = Logger.getLogger(FastMoney.class.getName());
/**
* The currency of this amount.
*/
private final CurrencyUnit currency;
/**
* The numeric part of this amount.
*/
private final long number;
/**
* The current scale represented by the number.
*/
private static final int SCALE = 5;
/**
* the {@link MonetaryContext} used by this instance, e.g. on division.
*/
private static final MonetaryContext MONETARY_CONTEXT =
MonetaryContextBuilder.of(FastMoney.class).setMaxScale(SCALE).setFixedScale(true).setPrecision(19).build();
/**
* Maximum possible value supported, using XX (no currency).
*/
public static final FastMoney MAX_VALUE = new FastMoney(Long.MAX_VALUE, Monetary.getCurrency("XXX"));
/**
* Maximum possible numeric value supported.
*/
private static final BigDecimal MAX_BD = MAX_VALUE.getBigDecimal();
/**
* Minimum possible value supported, using XX (no currency).
*/
public static final FastMoney MIN_VALUE = new FastMoney(Long.MIN_VALUE, Monetary.getCurrency("XXX"));
/**
* Minimum possible numeric value supported.
*/
private static final BigDecimal MIN_BD = MIN_VALUE.getBigDecimal();
/**
* Creates a new instance os {@link FastMoney}.
*
* @param currency the currency, not null.
* @param number the amount, not null.
*/
private FastMoney(Number number, CurrencyUnit currency, boolean allowInternalRounding) {
Objects.requireNonNull(currency, "Currency is required.");
this.currency = currency;
Objects.requireNonNull(number, "Number is required.");
this.number = getInternalNumber(number, allowInternalRounding);
}
/**
* Creates a new instance os {@link FastMoney}.
*
* @param currency the currency, not null.
* @param numberValue the numeric value, not null.
*/
private FastMoney(NumberValue numberValue, CurrencyUnit currency, boolean allowInternalRounding) {
Objects.requireNonNull(currency, "Currency is required.");
this.currency = currency;
Objects.requireNonNull(numberValue, "Number is required.");
this.number = getInternalNumber(numberValue.numberValue(BigDecimal.class), allowInternalRounding);
}
/**
* Creates a new instance os {@link FastMoney}.
*
* @param number The format number value
* @param currency the currency, not null.
*/
private FastMoney(long number, CurrencyUnit currency) {
Objects.requireNonNull(currency, "Currency is required.");
this.currency = currency;
this.number = number;
}
/**
* Returns the amount’s currency, modelled as {@link CurrencyUnit}.
* Implementations may co-variantly change the return type to a more
* specific implementation of {@link CurrencyUnit} if desired.
*
* @return the currency, never {@code null}
* @see javax.money.MonetaryAmount#getCurrency()
*/
@Override
public CurrencyUnit getCurrency() {
return currency;
}
/**
* Access the {@link MonetaryContext} used by this instance.
*
* @return the {@link MonetaryContext} used, never null.
* @see javax.money.MonetaryAmount#getContext()
*/
@Override
public MonetaryContext getContext() {
return MONETARY_CONTEXT;
}
private long getInternalNumber(Number number, boolean allowInternalRounding) {
BigDecimal bd = MoneyUtils.getBigDecimal(number);
if (!allowInternalRounding && bd.scale() > SCALE) {
throw new ArithmeticException(number + " can not be represented by this class, scale > " + SCALE);
}
if (bd.compareTo(MIN_BD) < 0) {
throw new ArithmeticException("Overflow: " + number + " < " + MIN_BD);
} else if (bd.compareTo(MAX_BD) > 0) {
throw new ArithmeticException("Overflow: " + number + " > " + MAX_BD);
}
return bd.movePointRight(SCALE).longValue();
}
/**
* Static factory method for creating a new instance of {@link FastMoney}.
*
* @param currency The target currency, not null.
* @param numberBinding The numeric part, not null.
* @return A new instance of {@link FastMoney}.
*/
public static FastMoney of(NumberValue numberBinding, CurrencyUnit currency) {
return new FastMoney(numberBinding, currency, false);
}
/**
* Static factory method for creating a new instance of {@link FastMoney}.
*
* @param currency The target currency, not null.
* @param number The numeric part, not null.
* @return A new instance of {@link FastMoney}.
*/
public static FastMoney of(Number number, CurrencyUnit currency) {
return new FastMoney(number, currency, false);
}
/**
* Static factory method for creating a new instance of {@link FastMoney}.
*
* @param currencyCode The target currency as currency code.
* @param number The numeric part, not null.
* @return A new instance of {@link FastMoney}.
*/
public static FastMoney of(Number number, String currencyCode) {
CurrencyUnit currency = Monetary.getCurrency(currencyCode);
return of(number, currency);
}
/*
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override
public int compareTo(MonetaryAmount o) {
Objects.requireNonNull(o);
int compare = getCurrency().getCurrencyCode().compareTo(o.getCurrency().getCurrencyCode());
if (compare == 0) {
compare = getNumber().numberValue(BigDecimal.class).compareTo(o.getNumber().numberValue(BigDecimal.class));
}
return compare;
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return Objects.hash(currency, number);
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof FastMoney) {
FastMoney other = (FastMoney) obj;
return Objects.equals(currency, other.currency) && Objects.equals(number, other.number);
}
return false;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#abs()
*/
@Override
public FastMoney abs() {
if (this.isPositiveOrZero()) {
return this;
}
return this.negate();
}
// Arithmetic Operations
/*
* (non-Javadoc)
* @see MonetaryAmount#add(MonetaryAmount)
*/
@Override
public FastMoney add(MonetaryAmount amount) {
checkAmountParameter(amount);
if (amount.isZero()) {
return this;
}
return new FastMoney(addExact(this.number, getInternalNumber(amount.getNumber(), false)), getCurrency());
}
private long addExact(long num1, long num2) {
if(num1==0){
return num2;
}
if(num2==0){
return num1;
}
boolean pos = num1>0 && num2 >0;
boolean neg = num1<0 && num2 <0;
long exact = num1 + num2;
if(pos && exact <=0){
throw new ArithmeticException("Long evaluation positive overflow.");
}
if(neg && exact >=0){
throw new ArithmeticException("Long evaluation negative overflow.");
}
return exact;
}
private void checkAmountParameter(MonetaryAmount amount) {
MoneyUtils.checkAmountParameter(amount, this.currency);
// numeric check for overflow...
if (amount.getNumber().getScale() > SCALE) {
throw new ArithmeticException("Parameter exceeds maximal scale: " + SCALE);
}
if (amount.getNumber().getPrecision() > MAX_BD.precision()) {
throw new ArithmeticException("Parameter exceeds maximal precision: " + SCALE);
}
}
/*
* (non-Javadoc)
* @see MonetaryAmount#divide(java.lang.Number)
*/
@Override
public FastMoney divide(Number divisor) {
if (Money.isInfinityAndNotNaN(divisor)) {
return new FastMoney(0L, getCurrency());
}
checkNumber(divisor);
if (isOne(divisor)) {
return this;
}
return new FastMoney(Math.round(this.number / divisor.doubleValue()), getCurrency());
}
/*
* (non-Javadoc)
* @see MonetaryAmount#divideAndRemainder(java.lang.Number)
*/
@Override
public FastMoney[] divideAndRemainder(Number divisor) {
if (Money.isInfinityAndNotNaN(divisor)) {
FastMoney zero = new FastMoney(0L, getCurrency());
return new FastMoney[]{zero, zero};
}
checkNumber(divisor);
if (isOne(divisor)) {
return new FastMoney[]{this, FastMoney.of(0, getCurrency())};
}
BigDecimal div = MoneyUtils.getBigDecimal(divisor);
BigDecimal[] res = getBigDecimal().divideAndRemainder(div);
return new FastMoney[]{new FastMoney(res[0], getCurrency(), true), new FastMoney(res[1], getCurrency(), true)};
}
/*
* (non-Javadoc)
* @see MonetaryAmount#divideToIntegralValue(java.lang.Number)
*/
@Override
public FastMoney divideToIntegralValue(Number divisor) {
if (Money.isInfinityAndNotNaN(divisor)) {
return new FastMoney(0L, getCurrency());
}
checkNumber(divisor);
if (isOne(divisor)) {
return this;
}
BigDecimal div = MoneyUtils.getBigDecimal(divisor);
return new FastMoney(getBigDecimal().divideToIntegralValue(div), getCurrency(), false);
}
@Override
public FastMoney multiply(Number multiplicand) {
Money.checkNoInfinityOrNaN(multiplicand);
checkNumber(multiplicand);
if (isOne(multiplicand)) {
return this;
}
return new FastMoney(multiplyExact(this.number, getInternalNumber(multiplicand, false)) / 100000L,
getCurrency());
}
private long multiplyExact(long num1, long num2) {
if(num1==0){
return num2;
}
if(num2==0){
return num1;
}
boolean pos = num1>0 && num2 >0;
boolean neg = num1<0 && num2 <0;
long exact = num1 * num2;
if(pos && exact <=0){
throw new ArithmeticException("Long evaluation positive overflow.");
}
if(neg && exact <=0){
throw new ArithmeticException("Long evaluation negative overflow.");
}
if(!neg && !pos && exact >=0){
throw new ArithmeticException("Long negative overflow.");
}
return exact;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#negate()
*/
@Override
public FastMoney negate() {
return new FastMoney(multiplyExact(this.number, -1), getCurrency());
}
/*
* (non-Javadoc)
* @see MonetaryAmount#plus()
*/
@Override
public FastMoney plus() {
if (this.number >= 0) {
return this;
}
return new FastMoney(multiplyExact(this.number, -1), getCurrency());
}
/*
* (non-Javadoc)
* @see MonetaryAmount#subtract(MonetaryAmount)
*/
@Override
public FastMoney subtract(MonetaryAmount subtrahend) {
checkAmountParameter(subtrahend);
if (subtrahend.isZero()) {
return this;
}
return new FastMoney(subtractExact(this.number, getInternalNumber(subtrahend.getNumber(), false)),
getCurrency());
}
private long subtractExact(long num1, long num2) {
if(num2==0){
return num1;
}
if(num1==num2){
return 0;
}
boolean pos = num1>num2;
long exact = num1 - num2;
if(pos && exact <=0){
throw new ArithmeticException("Long evaluation negative overflow.");
}
if(!pos && exact >=0){
throw new ArithmeticException("Long evaluation positive overflow.");
}
return exact;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#remainder(java.lang.Number)
*/
@Override
public FastMoney remainder(Number divisor) {
checkNumber(divisor);
if (isOne(divisor)) {
return new FastMoney(0, getCurrency());
}
return new FastMoney(this.number % getInternalNumber(divisor, false), getCurrency());
}
private boolean isOne(Number number) {
BigDecimal bd = MoneyUtils.getBigDecimal(number);
try {
return bd.scale() == 0 && bd.longValueExact() == 1L;
} catch (Exception e) {
// The only way to end up here is that longValueExact throws an ArithmeticException,
// so the amount is definitively not equal to 1.
return false;
}
}
/*
* (non-Javadoc)
* @see MonetaryAmount#scaleByPowerOfTen(int)
*/
@Override
public FastMoney scaleByPowerOfTen(int n) {
return new FastMoney(getNumber().numberValue(BigDecimal.class).scaleByPowerOfTen(n), getCurrency(), true);
}
/*
* (non-Javadoc)
* @see MonetaryAmount#isZero()
*/
@Override
public boolean isZero() {
return this.number == 0L;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#isPositive()
*/
@Override
public boolean isPositive() {
return this.number > 0L;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#isPositiveOrZero()
*/
@Override
public boolean isPositiveOrZero() {
return this.number >= 0L;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#isNegative()
*/
@Override
public boolean isNegative() {
return this.number < 0L;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#isNegativeOrZero()
*/
@Override
public boolean isNegativeOrZero() {
return this.number <= 0L;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#getScale()
*/
public int getScale() {
return FastMoney.SCALE;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#getPrecision()
*/
public int getPrecision() {
return getNumber().numberValue(BigDecimal.class).precision();
}
/*
* (non-Javadoc)
* @see MonetaryAmount#signum()
*/
@Override
public int signum() {
if (this.number < 0) {
return -1;
}
if (this.number == 0) {
return 0;
}
return 1;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#lessThan(MonetaryAmount)
*/
@Override
public boolean isLessThan(MonetaryAmount amount) {
checkAmountParameter(amount);
return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) < 0;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#lessThan(java.lang.Number)
*/
public boolean isLessThan(Number number) {
checkNumber(number);
return getBigDecimal().compareTo(MoneyUtils.getBigDecimal(number)) < 0;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#lessThanOrEqualTo(MonetaryAmount)
*/
@Override
public boolean isLessThanOrEqualTo(MonetaryAmount amount) {
checkAmountParameter(amount);
return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) <= 0;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#lessThanOrEqualTo(java.lang.Number)
*/
public boolean isLessThanOrEqualTo(Number number) {
checkNumber(number);
return getBigDecimal().compareTo(MoneyUtils.getBigDecimal(number)) <= 0;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#greaterThan(MonetaryAmount)
*/
@Override
public boolean isGreaterThan(MonetaryAmount amount) {
checkAmountParameter(amount);
return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) > 0;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#greaterThan(java.lang.Number)
*/
public boolean isGreaterThan(Number number) {
checkNumber(number);
return getBigDecimal().compareTo(MoneyUtils.getBigDecimal(number)) > 0;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#greaterThanOrEqualTo(MonetaryAmount ) #see
*/
@Override
public boolean isGreaterThanOrEqualTo(MonetaryAmount amount) {
checkAmountParameter(amount);
return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) >= 0;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#greaterThanOrEqualTo(java.lang.Number)
*/
public boolean isGreaterThanOrEqualTo(Number number) {
checkNumber(number);
return getBigDecimal().compareTo(MoneyUtils.getBigDecimal(number)) >= 0;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#isEqualTo(MonetaryAmount)
*/
@Override
public boolean isEqualTo(MonetaryAmount amount) {
checkAmountParameter(amount);
return getBigDecimal().compareTo(amount.getNumber().numberValue(BigDecimal.class)) == 0;
}
/*
* (non-Javadoc)
* @see MonetaryAmount#hasSameNumberAs(java.lang.Number)
*/
public boolean hasSameNumberAs(Number number) {
checkNumber(number);
try {
return this.number == getInternalNumber(number, false);
} catch (ArithmeticException e) {
return false;
}
}
/**
* Gets the number representation of the numeric value of this item.
*
* @return The {@link Number} represention matching best.
*/
@Override
public NumberValue getNumber() {
return new DefaultNumberValue(getBigDecimal());
}
@Override
public String toString() {
return currency.toString() + ' ' + getBigDecimal();
}
// Internal helper methods
/**
* Internal method to check for correct number parameter.
*
* @param number the number to be checked, including null..
* @throws NullPointerException If the number is null
* @throws java.lang.ArithmeticException If the number exceeds the capabilities of this class.
*/
protected void checkNumber(Number number) {
Objects.requireNonNull(number, "Number is required.");
// numeric check for overflow...
if (number.longValue() > MAX_BD.longValue()) {
throw new ArithmeticException("Value exceeds maximal value: " + MAX_BD);
}
BigDecimal bd = MoneyUtils.getBigDecimal(number);
if (bd.precision() > MAX_BD.precision()) {
throw new ArithmeticException("Precision exceeds maximal precision: " + MAX_BD.precision());
}
if (bd.scale() > SCALE) {
String val = MonetaryConfig.getConfig()
.get("FastMoney.enforceScaleCompatibility");
if(val==null){
val = "false";
}
if (Boolean.parseBoolean(val)) {
throw new ArithmeticException("Scale of " + bd + " exceeds maximal scale: " + SCALE);
} else {
if (LOG.isLoggable(Level.FINEST)) {
LOG.finest("Scale exceeds maximal scale of FastMoney (" + SCALE +
"), implicit rounding will be applied to " + number);
}
}
}
}
/*
* }(non-Javadoc)
* @see MonetaryAmount#adjust(org.javamoney.bp.AmountAdjuster)
*/
@Override
public FastMoney with(MonetaryOperator operator) {
Objects.requireNonNull(operator);
try {
return FastMoney.class.cast(operator.apply(this));
} catch (ArithmeticException e) {
throw e;
} catch (Exception e) {
throw new MonetaryException("Operator failed: " + operator, e);
}
}
@Override
public R query(MonetaryQuery query) {
Objects.requireNonNull(query);
try {
return query.queryFrom(this);
} catch (MonetaryException | ArithmeticException e) {
throw e;
} catch (Exception e) {
throw new MonetaryException("Query failed: " + query, e);
}
}
public static FastMoney from(MonetaryAmount amount) {
if (FastMoney.class.isInstance(amount)) {
return FastMoney.class.cast(amount);
}
return new FastMoney(amount.getNumber(), amount.getCurrency(), false);
}
/**
* Obtains an instance of FastMoney from a text string such as 'EUR 25.25'.
*
* @param text the text to parse not null
* @return FastMoney instance
* @throws NullPointerException
* @throws NumberFormatException
* @throws javax.money.UnknownCurrencyException
*/
public static FastMoney parse(CharSequence text) {
return parse(text, DEFAULT_FORMATTER);
}
/**
* Obtains an instance of FastMoney from a text using specific formatter.
*
* @param text the text to parse not null
* @param formatter the formatter to use not null
* @return FastMoney instance
*/
public static FastMoney parse(CharSequence text, MonetaryAmountFormat formatter) {
return from(formatter.parse(text));
}
private static final ToStringMonetaryAmountFormat DEFAULT_FORMATTER = ToStringMonetaryAmountFormat
.of(ToStringMonetaryAmountFormat.ToStringMonetaryAmountFormatStyle.FAST_MONEY);
private BigDecimal getBigDecimal() {
return BigDecimal.valueOf(this.number).movePointLeft(SCALE);
}
@Override
public FastMoney multiply(double amount) {
Money.checkNoInfinityOrNaN(amount);
if (amount == 1.0) {
return this;
}
if (amount == 0.0) {
return new FastMoney(0, this.currency);
}
return new FastMoney(Math.round(this.number * amount), this.currency);
}
@Override
public FastMoney divide(long amount) {
if (amount == 1L) {
return this;
}
return new FastMoney(this.number / amount, this.currency);
}
@Override
public FastMoney divide(double number) {
if (Money.isInfinityAndNotNaN(number)) {
return new FastMoney(0L, getCurrency());
}
if (number == 1.0d) {
return this;
}
return new FastMoney(Math.round(this.number / number), getCurrency());
}
@Override
public FastMoney remainder(long number) {
return remainder(BigDecimal.valueOf(number));
}
@Override
public FastMoney remainder(double amount) {
if (Money.isInfinityAndNotNaN(amount)) {
return new FastMoney(0L, getCurrency());
}
return remainder(new BigDecimal(String.valueOf(amount)));
}
@Override
public FastMoney[] divideAndRemainder(long amount) {
return divideAndRemainder(BigDecimal.valueOf(amount));
}
@Override
public FastMoney[] divideAndRemainder(double amount) {
if (Money.isInfinityAndNotNaN(amount)) {
FastMoney zero = new FastMoney(0L, getCurrency());
return new FastMoney[]{zero, zero};
} else if (Double.isNaN(amount)) {
throw new ArithmeticException("Not a number: NaN.");
}
return divideAndRemainder(new BigDecimal(String.valueOf(amount)));
}
@Override
public FastMoney stripTrailingZeros() {
return this;
}
@Override
public FastMoney multiply(long multiplicand) {
if (multiplicand == 1) {
return this;
}
if (multiplicand == 0) {
return new FastMoney(0L, this.currency);
}
return new FastMoney(multiplyExact(multiplicand, this.number), this.currency);
}
@Override
public FastMoney divideToIntegralValue(long divisor) {
if (divisor == 1) {
return this;
}
return divideToIntegralValue(MoneyUtils.getBigDecimal(divisor));
}
@Override
public FastMoney divideToIntegralValue(double divisor) {
if (Money.isInfinityAndNotNaN(divisor)) {
return new FastMoney(0L, getCurrency());
}
if (divisor == 1.0) {
return this;
}
return divideToIntegralValue(MoneyUtils.getBigDecimal(divisor));
}
@Override
public MonetaryAmountFactory getFactory() {
return new FastMoneyAmountBuilder().setAmount(this);
}
}