LANG-1408: Rounding utilities for converting to BigDecimal
This commit is contained in:
parent
08aa21f921
commit
b31877a460
|
@ -71,6 +71,7 @@ The <action> type attribute can be add,update,fix,remove.
|
|||
<action issue="LANG-1392" type="add" dev="pschumacher" due-to="Jeff Nelson">Methods for getting first non empty or non blank value</action>
|
||||
<action issue="LANG-1405" type="update" dev="ggregory" due-to="Lars Grefer">Remove checks for java versions below the minimum supported one</action>
|
||||
<action issue="LANG-1402" type="update" dev="chtompki" due-to="Mark Dacek">Null/index safe get methods for ArrayUtils</action>
|
||||
<action issue="LANG-1408" type="add" dev="chtompki">Rounding utilities for converting to BigDecimal</action>
|
||||
</release>
|
||||
|
||||
<release version="3.7" date="2017-11-04" description="New features and bug fixes. Requires Java 7, supports Java 8, 9, 10.">
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.lang.reflect.Array;
|
|||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
|
@ -40,6 +41,8 @@ public class NumberUtils {
|
|||
public static final Integer INTEGER_ZERO = Integer.valueOf(0);
|
||||
/** Reusable Integer constant for one. */
|
||||
public static final Integer INTEGER_ONE = Integer.valueOf(1);
|
||||
/** Reusable Integer constant for two */
|
||||
public static final Integer INTEGER_TWO = Integer.valueOf(2);
|
||||
/** Reusable Integer constant for minus one. */
|
||||
public static final Integer INTEGER_MINUS_ONE = Integer.valueOf(-1);
|
||||
/** Reusable Short constant for zero. */
|
||||
|
@ -298,7 +301,7 @@ public class NumberUtils {
|
|||
* <code>0.0d</code> if the <code>BigDecimal</code> is <code>null</code>.
|
||||
* @since 3.8
|
||||
*/
|
||||
public static double toDouble(BigDecimal value) {
|
||||
public static double toDouble(final BigDecimal value) {
|
||||
return toDouble(value, 0.0d);
|
||||
}
|
||||
|
||||
|
@ -319,7 +322,7 @@ public class NumberUtils {
|
|||
* defaultValue if the <code>BigDecimal</code> is <code>null</code>.
|
||||
* @since 3.8
|
||||
*/
|
||||
public static double toDouble(BigDecimal value, double defaultValue) {
|
||||
public static double toDouble(final BigDecimal value, final double defaultValue) {
|
||||
return value == null ? defaultValue : value.doubleValue();
|
||||
}
|
||||
|
||||
|
@ -422,6 +425,161 @@ public class NumberUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a <code>BigDecimal</code> to a <code>BigDecimal</code> with a scale of
|
||||
* two that has been rounded using <code>RoundingMode.HALF_EVEN</code>. If the supplied
|
||||
* <code>value</code> is null, then <code>BigDecimal.ZERO</code> is returned.
|
||||
*
|
||||
* <p>Note, the scale of a <code>BigDecimal</code> is the number of digits to the right of the
|
||||
* decimal point.</p>
|
||||
*
|
||||
* @param value the <code>BigDecimal</code> to convert, may be null.
|
||||
* @return the scaled, with appropriate rounding, <code>BigDecimal</code>.
|
||||
* @since 3.8
|
||||
*/
|
||||
public static BigDecimal toScaledBigDecimal(BigDecimal value) {
|
||||
return toScaledBigDecimal(value, INTEGER_TWO, RoundingMode.HALF_EVEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a <code>BigDecimal</code> to a <code>BigDecimal</code> whose scale is the
|
||||
* specified value with a <code>RoundingMode</code> applied. If the input <code>value</code>
|
||||
* is <code>null</code>, we simply return <code>BigDecimal.ZERO</code>.
|
||||
*
|
||||
* @param value the <code>BigDecimal</code> to convert, may be null.
|
||||
* @param scale the number of digits to the right of the decimal point.
|
||||
* @param roundingMode a rounding behavior for numerical operations capable of
|
||||
* discarding precision.
|
||||
* @return the scaled, with appropriate rounding, <code>BigDecimal</code>.
|
||||
* @since 3.8
|
||||
*/
|
||||
public static BigDecimal toScaledBigDecimal(BigDecimal value, int scale, RoundingMode roundingMode) {
|
||||
if (value == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return value.setScale(
|
||||
scale,
|
||||
(roundingMode == null) ? RoundingMode.HALF_EVEN : roundingMode
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a <code>Float</code> to a <code>BigDecimal</code> with a scale of
|
||||
* two that has been rounded using <code>RoundingMode.HALF_EVEN</code>. If the supplied
|
||||
* <code>value</code> is null, then <code>BigDecimal.ZERO</code> is returned.
|
||||
*
|
||||
* <p>Note, the scale of a <code>BigDecimal</code> is the number of digits to the right of the
|
||||
* decimal point.</p>
|
||||
*
|
||||
* @param value the <code>Float</code> to convert, may be null.
|
||||
* @return the scaled, with appropriate rounding, <code>BigDecimal</code>.
|
||||
* @since 3.8
|
||||
*/
|
||||
public static BigDecimal toScaledBigDecimal(Float value) {
|
||||
return toScaledBigDecimal(value, INTEGER_TWO, RoundingMode.HALF_EVEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a <code>Float</code> to a <code>BigDecimal</code> whose scale is the
|
||||
* specified value with a <code>RoundingMode</code> applied. If the input <code>value</code>
|
||||
* is <code>null</code>, we simply return <code>BigDecimal.ZERO</code>.
|
||||
*
|
||||
* @param value the <code>Float</code> to convert, may be null.
|
||||
* @param scale the number of digits to the right of the decimal point.
|
||||
* @param roundingMode a rounding behavior for numerical operations capable of
|
||||
* discarding precision.
|
||||
* @return the scaled, with appropriate rounding, <code>BigDecimal</code>.
|
||||
* @since 3.8
|
||||
*/
|
||||
public static BigDecimal toScaledBigDecimal(Float value, int scale, RoundingMode roundingMode) {
|
||||
if (value == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return toScaledBigDecimal(
|
||||
BigDecimal.valueOf(value),
|
||||
scale,
|
||||
roundingMode
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a <code>Double</code> to a <code>BigDecimal</code> with a scale of
|
||||
* two that has been rounded using <code>RoundingMode.HALF_EVEN</code>. If the supplied
|
||||
* <code>value</code> is null, then <code>BigDecimal.ZERO</code> is returned.
|
||||
*
|
||||
* <p>Note, the scale of a <code>BigDecimal</code> is the number of digits to the right of the
|
||||
* decimal point.</p>
|
||||
*
|
||||
* @param value the <code>Double</code> to convert, may be null.
|
||||
* @return the scaled, with appropriate rounding, <code>BigDecimal</code>.
|
||||
* @since 3.8
|
||||
*/
|
||||
public static BigDecimal toScaledBigDecimal(Double value) {
|
||||
return toScaledBigDecimal(value, INTEGER_TWO, RoundingMode.HALF_EVEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a <code>Double</code> to a <code>BigDecimal</code> whose scale is the
|
||||
* specified value with a <code>RoundingMode</code> applied. If the input <code>value</code>
|
||||
* is <code>null</code>, we simply return <code>BigDecimal.ZERO</code>.
|
||||
*
|
||||
* @param value the <code>Double</code> to convert, may be null.
|
||||
* @param scale the number of digits to the right of the decimal point.
|
||||
* @param roundingMode a rounding behavior for numerical operations capable of
|
||||
* discarding precision.
|
||||
* @return the scaled, with appropriate rounding, <code>BigDecimal</code>.
|
||||
* @since 3.8
|
||||
*/
|
||||
public static BigDecimal toScaledBigDecimal(Double value, int scale, RoundingMode roundingMode) {
|
||||
if (value == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return toScaledBigDecimal(
|
||||
BigDecimal.valueOf(value),
|
||||
scale,
|
||||
roundingMode
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a <code>String</code> to a <code>BigDecimal</code> with a scale of
|
||||
* two that has been rounded using <code>RoundingMode.HALF_EVEN</code>. If the supplied
|
||||
* <code>value</code> is null, then <code>BigDecimal.ZERO</code> is returned.
|
||||
*
|
||||
* <p>Note, the scale of a <code>BigDecimal</code> is the number of digits to the right of the
|
||||
* decimal point.</p>
|
||||
*
|
||||
* @param value the <code>String</code> to convert, may be null.
|
||||
* @return the scaled, with appropriate rounding, <code>BigDecimal</code>.
|
||||
* @since 3.8
|
||||
*/
|
||||
public static BigDecimal toScaledBigDecimal(String value) {
|
||||
return toScaledBigDecimal(value, INTEGER_TWO, RoundingMode.HALF_EVEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a <code>String</code> to a <code>BigDecimal</code> whose scale is the
|
||||
* specified value with a <code>RoundingMode</code> applied. If the input <code>value</code>
|
||||
* is <code>null</code>, we simply return <code>BigDecimal.ZERO</code>.
|
||||
*
|
||||
* @param value the <code>String</code> to convert, may be null.
|
||||
* @param scale the number of digits to the right of the decimal point.
|
||||
* @param roundingMode a rounding behavior for numerical operations capable of
|
||||
* discarding precision.
|
||||
* @return the scaled, with appropriate rounding, <code>BigDecimal</code>.
|
||||
* @since 3.8
|
||||
*/
|
||||
public static BigDecimal toScaledBigDecimal(String value, int scale, RoundingMode roundingMode) {
|
||||
if (value == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return toScaledBigDecimal(
|
||||
createBigDecimal(value),
|
||||
scale,
|
||||
roundingMode
|
||||
);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// must handle Long, Float, Integer, Float, Short,
|
||||
// BigDecimal, BigInteger and Byte
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.lang.reflect.Modifier;
|
|||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
|
@ -238,6 +239,169 @@ public class NumberUtilsTest {
|
|||
assertTrue("toShort(String,short) 2 failed", NumberUtils.toShort("1234.5", (short) 5) == 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for {@link NumberUtils#toScaledBigDecimal(BigDecimal)}.
|
||||
*/
|
||||
@Test
|
||||
public void testToScaledBigDecimalBigDecimal() {
|
||||
assertTrue("toScaledBigDecimal(BigDecimal) 1 failed",
|
||||
NumberUtils.toScaledBigDecimal(BigDecimal.valueOf(123.456)).equals(BigDecimal.valueOf(123.46)));
|
||||
// Test RoudingMode.HALF_EVEN default rounding.
|
||||
assertTrue("toScaledBigDecimal(BigDecimal) 2 failed",
|
||||
NumberUtils.toScaledBigDecimal(BigDecimal.valueOf(23.515)).equals(BigDecimal.valueOf(23.52)));
|
||||
assertTrue("toScaledBigDecimal(BigDecimal) 3 failed",
|
||||
NumberUtils.toScaledBigDecimal(BigDecimal.valueOf(23.525)).equals(BigDecimal.valueOf(23.52)));
|
||||
assertTrue("toScaledBigDecimal(BigDecimal) 4 failed",
|
||||
NumberUtils.toScaledBigDecimal(BigDecimal.valueOf(23.525))
|
||||
.multiply(BigDecimal.valueOf(100)).toString()
|
||||
.equals("2352.00"));
|
||||
assertTrue("toScaledBigDecimal(BigDecimal) 5 failed",
|
||||
NumberUtils.toScaledBigDecimal((BigDecimal) null).equals(BigDecimal.ZERO));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for {@link NumberUtils#toScaledBigDecimal(BigDecimal, int, RoundingMode)}.
|
||||
*/
|
||||
@Test
|
||||
public void testToScaledBigDecimalBigDecimalIRM() {
|
||||
assertTrue("toScaledBigDecimal(BigDecimal, int, RoudingMode) 1 failed",
|
||||
NumberUtils.toScaledBigDecimal(BigDecimal.valueOf(123.456), 1, RoundingMode.CEILING).equals(BigDecimal.valueOf(123.5)));
|
||||
assertTrue("toScaledBigDecimal(BigDecimal, int, RoudingMode) 2 failed",
|
||||
NumberUtils.toScaledBigDecimal(BigDecimal.valueOf(23.5159), 3, RoundingMode.FLOOR).equals(BigDecimal.valueOf(23.515)));
|
||||
assertTrue("toScaledBigDecimal(BigDecimal, int, RoudingMode) 3 failed",
|
||||
NumberUtils.toScaledBigDecimal(BigDecimal.valueOf(23.525), 2, RoundingMode.HALF_UP).equals(BigDecimal.valueOf(23.53)));
|
||||
assertTrue("toScaledBigDecimal(BigDecimal, int, RoudingMode) 4 failed",
|
||||
NumberUtils.toScaledBigDecimal(BigDecimal.valueOf(23.521), 4, RoundingMode.HALF_EVEN)
|
||||
.multiply(BigDecimal.valueOf(1000))
|
||||
.toString()
|
||||
.equals("23521.0000"));
|
||||
assertTrue("toScaledBigDecimal(BigDecimal, int, RoudingMode) 5 failed",
|
||||
NumberUtils.toScaledBigDecimal((BigDecimal) null, 2, RoundingMode.HALF_UP).equals(BigDecimal.ZERO));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for {@link NumberUtils#toScaledBigDecimal(Float)}.
|
||||
*/
|
||||
@Test
|
||||
public void testToScaledBigDecimalFloat() {
|
||||
assertTrue("toScaledBigDecimal(Float) 1 failed",
|
||||
NumberUtils.toScaledBigDecimal(Float.valueOf(123.456f)).equals(BigDecimal.valueOf(123.46)));
|
||||
// Test RoudingMode.HALF_EVEN default rounding.
|
||||
assertTrue("toScaledBigDecimal(Float) 2 failed",
|
||||
NumberUtils.toScaledBigDecimal(Float.valueOf(23.515f)).equals(BigDecimal.valueOf(23.51)));
|
||||
// Note. NumberUtils.toScaledBigDecimal(Float.valueOf(23.515f)).equals(BigDecimal.valueOf(23.51))
|
||||
// because of roundoff error. It is ok.
|
||||
assertTrue("toScaledBigDecimal(Float) 3 failed",
|
||||
NumberUtils.toScaledBigDecimal(Float.valueOf(23.525f)).equals(BigDecimal.valueOf(23.52)));
|
||||
assertTrue("toScaledBigDecimal(Float) 4 failed",
|
||||
NumberUtils.toScaledBigDecimal(Float.valueOf(23.525f))
|
||||
.multiply(BigDecimal.valueOf(100)).toString()
|
||||
.equals("2352.00"));
|
||||
assertTrue("toScaledBigDecimal(Float) 5 failed",
|
||||
NumberUtils.toScaledBigDecimal((Float) null).equals(BigDecimal.ZERO));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for {@link NumberUtils#toScaledBigDecimal(Float, int, RoundingMode)}.
|
||||
*/
|
||||
@Test
|
||||
public void testToScaledBigDecimalFloatIRM() {
|
||||
assertTrue("toScaledBigDecimal(Float, int, RoudingMode) 1 failed",
|
||||
NumberUtils.toScaledBigDecimal(Float.valueOf(123.456f), 1, RoundingMode.CEILING).equals(BigDecimal.valueOf(123.5)));
|
||||
assertTrue("toScaledBigDecimal(Float, int, RoudingMode) 2 failed",
|
||||
NumberUtils.toScaledBigDecimal(Float.valueOf(23.5159f), 3, RoundingMode.FLOOR).equals(BigDecimal.valueOf(23.515)));
|
||||
// The following happens due to roundoff error. We're ok with this.
|
||||
assertTrue("toScaledBigDecimal(Float, int, RoudingMode) 3 failed",
|
||||
NumberUtils.toScaledBigDecimal(Float.valueOf(23.525f), 2, RoundingMode.HALF_UP).equals(BigDecimal.valueOf(23.52)));
|
||||
assertTrue("toScaledBigDecimal(Float, int, RoudingMode) 4 failed",
|
||||
NumberUtils.toScaledBigDecimal(Float.valueOf(23.521f), 4, RoundingMode.HALF_EVEN)
|
||||
.multiply(BigDecimal.valueOf(1000))
|
||||
.toString()
|
||||
.equals("23521.0000"));
|
||||
assertTrue("toScaledBigDecimal(Float, int, RoudingMode) 5 failed",
|
||||
NumberUtils.toScaledBigDecimal((Float) null, 2, RoundingMode.HALF_UP).equals(BigDecimal.ZERO));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for {@link NumberUtils#toScaledBigDecimal(Double)}.
|
||||
*/
|
||||
@Test
|
||||
public void testToScaledBigDecimalDouble() {
|
||||
assertTrue("toScaledBigDecimal(Double) 1 failed",
|
||||
NumberUtils.toScaledBigDecimal(Double.valueOf(123.456d)).equals(BigDecimal.valueOf(123.46)));
|
||||
// Test RoudingMode.HALF_EVEN default rounding.
|
||||
assertTrue("toScaledBigDecimal(Double) 2 failed",
|
||||
NumberUtils.toScaledBigDecimal(Double.valueOf(23.515d)).equals(BigDecimal.valueOf(23.52)));
|
||||
assertTrue("toScaledBigDecimal(Double) 3 failed",
|
||||
NumberUtils.toScaledBigDecimal(Double.valueOf(23.525d)).equals(BigDecimal.valueOf(23.52)));
|
||||
assertTrue("toScaledBigDecimal(Double) 4 failed",
|
||||
NumberUtils.toScaledBigDecimal(Double.valueOf(23.525d))
|
||||
.multiply(BigDecimal.valueOf(100)).toString()
|
||||
.equals("2352.00"));
|
||||
assertTrue("toScaledBigDecimal(Double) 5 failed",
|
||||
NumberUtils.toScaledBigDecimal((Double) null).equals(BigDecimal.ZERO));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for {@link NumberUtils#toScaledBigDecimal(Double, int, RoundingMode)}.
|
||||
*/
|
||||
@Test
|
||||
public void testToScaledBigDecimalDoubleIRM() {
|
||||
assertTrue("toScaledBigDecimal(Double, int, RoudingMode) 1 failed",
|
||||
NumberUtils.toScaledBigDecimal(Double.valueOf(123.456d), 1, RoundingMode.CEILING).equals(BigDecimal.valueOf(123.5)));
|
||||
assertTrue("toScaledBigDecimal(Double, int, RoudingMode) 2 failed",
|
||||
NumberUtils.toScaledBigDecimal(Double.valueOf(23.5159d), 3, RoundingMode.FLOOR).equals(BigDecimal.valueOf(23.515)));
|
||||
assertTrue("toScaledBigDecimal(Double, int, RoudingMode) 3 failed",
|
||||
NumberUtils.toScaledBigDecimal(Double.valueOf(23.525d), 2, RoundingMode.HALF_UP).equals(BigDecimal.valueOf(23.53)));
|
||||
assertTrue("toScaledBigDecimal(Double, int, RoudingMode) 4 failed",
|
||||
NumberUtils.toScaledBigDecimal(Double.valueOf(23.521d), 4, RoundingMode.HALF_EVEN)
|
||||
.multiply(BigDecimal.valueOf(1000))
|
||||
.toString()
|
||||
.equals("23521.0000"));
|
||||
assertTrue("toScaledBigDecimal(Double, int, RoudingMode) 5 failed",
|
||||
NumberUtils.toScaledBigDecimal((Double) null, 2, RoundingMode.HALF_UP).equals(BigDecimal.ZERO));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for {@link NumberUtils#toScaledBigDecimal(Double)}.
|
||||
*/
|
||||
@Test
|
||||
public void testToScaledBigDecimalString() {
|
||||
assertTrue("toScaledBigDecimal(String) 1 failed",
|
||||
NumberUtils.toScaledBigDecimal("123.456").equals(BigDecimal.valueOf(123.46)));
|
||||
// Test RoudingMode.HALF_EVEN default rounding.
|
||||
assertTrue("toScaledBigDecimal(String) 2 failed",
|
||||
NumberUtils.toScaledBigDecimal("23.515").equals(BigDecimal.valueOf(23.52)));
|
||||
assertTrue("toScaledBigDecimal(String) 3 failed",
|
||||
NumberUtils.toScaledBigDecimal("23.525").equals(BigDecimal.valueOf(23.52)));
|
||||
assertTrue("toScaledBigDecimal(String) 4 failed",
|
||||
NumberUtils.toScaledBigDecimal("23.525")
|
||||
.multiply(BigDecimal.valueOf(100)).toString()
|
||||
.equals("2352.00"));
|
||||
assertTrue("toScaledBigDecimal(String) 5 failed",
|
||||
NumberUtils.toScaledBigDecimal((String) null).equals(BigDecimal.ZERO));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for {@link NumberUtils#toScaledBigDecimal(Double, int, RoundingMode)}.
|
||||
*/
|
||||
@Test
|
||||
public void testToScaledBigDecimalStringIRM() {
|
||||
assertTrue("toScaledBigDecimal(String, int, RoudingMode) 1 failed",
|
||||
NumberUtils.toScaledBigDecimal("123.456", 1, RoundingMode.CEILING).equals(BigDecimal.valueOf(123.5)));
|
||||
assertTrue("toScaledBigDecimal(String, int, RoudingMode) 2 failed",
|
||||
NumberUtils.toScaledBigDecimal("23.5159", 3, RoundingMode.FLOOR).equals(BigDecimal.valueOf(23.515)));
|
||||
assertTrue("toScaledBigDecimal(String, int, RoudingMode) 3 failed",
|
||||
NumberUtils.toScaledBigDecimal("23.525", 2, RoundingMode.HALF_UP).equals(BigDecimal.valueOf(23.53)));
|
||||
assertTrue("toScaledBigDecimal(String, int, RoudingMode) 4 failed",
|
||||
NumberUtils.toScaledBigDecimal("23.521", 4, RoundingMode.HALF_EVEN)
|
||||
.multiply(BigDecimal.valueOf(1000))
|
||||
.toString()
|
||||
.equals("23521.0000"));
|
||||
assertTrue("toScaledBigDecimal(String, int, RoudingMode) 5 failed",
|
||||
NumberUtils.toScaledBigDecimal((String) null, 2, RoundingMode.HALF_UP).equals(BigDecimal.ZERO));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateNumber() {
|
||||
// a lot of things can go wrong
|
||||
|
|
Loading…
Reference in New Issue