从大十进制中删除小数结尾零



我写测试并希望将BigDecimal结果与预期值进行比较。 我想使用方法Assert.assertEquals(BigDecimal, BigDecimal)因为如果下降它会显示精确的比较值,并且在日食中我可以显示比较窗口。

所以在代码中,我有方法返回四舍五入到小数点后 2 位的BigDecimal。 在测试用例中,我现在返回没有非零十进制数字的数字。所以我想创建小数位数为 0 的 BigDecimal 并将返回的 BigDecimal修剪为相同的比例。

为了更复杂的情况,我现在有方法getDecimal(Object [,Optionaly int scale]),可以从具有正确toString()值且默认小数位数为 99 的任何对象创建BigDecimal。我在主要的"重"代码中使用它,所以这个方法必须非常快(没有必要创建另一个对象,不要使用正则表达式等)。

所以简单的问题是:如何修改BigDecimal实例以通过最小负载修剪结束十进制零。

想要像这样撕裂

0.010 -> 0.01
5.000 -> 5
100 -> 100   not 1E+2

参考资料:

someTrim(new BigDecimal("100.00")).equals(new BigDecimal(100))

做数学类似的事情

100.00 / (2, 99, DOWN) * 50.00 -> 2500

我的代码看起来像

public static BigDecimal getDecimal( Object value ) {
// null here probably work beter, but dont want number longer then 99 decimal digits
return getDecimal( value, 99 );
}
public static BigDecimal getDecimal( Object value, Integer scale ) {
if ( value == null )
return null;
BigDecimal result = ( value instanceof BigDecimal ) ? ( BigDecimal ) value : new BigDecimal( value.toString() );
if ( scale == null )
return result;
return result.setScale( scale, DOWN );
}
// Main heavy method could call this 100 000 times per tenant (cca 1500 tenants), of course not expect all in same time, but can severals
public static myModify(E entity){
return myModify( entity.getValue(), entity.getDivisor(), entity.getMultiplicator() );
}
public static myModify( BigDecimal value, Integer divisor, BigDecimal multiplicator){
return value.divide( getDecimal(divisor), 99, RoundingMode.DOWN ).multiply( multiplicator );
}
@Test
public void myModifyTest(){
// Constructor have param: value, divisor, multiplicator
E entity = new E(new BigDecimal("100.00"), 2, new BigDecimal("50.00"));
// Should pass
Assert.assertEquals(getDecimal(100), entity);
// Should drop: java.lang.AssertionError: expected:<50> but was:<100>
Assert.assertEquals(getDecimal(50), entity);
// Not want: java.lang.AssertionError: expected:<5E+1> but was:<1E+2>
}

也许存在另一种丢弃相同错误的 junit 比较方法,但我不知道

感谢您的帮助。帕维尔

针对此要求的官方 junit 解决方案是使用 hamcrest。

在java-hamcrest 2.0.0.0中,我们可以使用以下语法:

BigDecimal a = new BigDecimal("100")
BigDecimal b = new BigDecimal("100.00")
assertThat(a,  Matchers.comparesEqualTo(b));

哈姆克雷斯特 1.3 快速参考

我可能找到了解决方案。创建 2 个另一个 BigDecimal 实例是不好的,但不知道另一种侵入性较小的方法。如果没有必要,我几乎没有进行优化以不创建实例。

/** 
* For text comparsion or log propouse
* @return human readable text without decimal zeros 
*/
public static String getPlainText( BigDecimal value ) {
if ( value == null )
return null;
// Strip only values with decimal digits
BigDecimal striped = ( value.scale() > 0 ) ? value.stripTrailingZeros() : value;
return striped.toPlainString();
}
/** 
* For comparison by equals method like test assertEquals
* @return new instance without decimal zeros 
*/
public static BigDecimal stripDecimalZeros( BigDecimal value ) {
if ( value == null )
return null;
// Strip only values with decimal digits
BigDecimal striped = ( value.scale() > 0 ) ? value.stripTrailingZeros() : value;
// Unscale only values with ten exponent
return ( striped.scale() < 0 ) ? striped.setScale( 0 ) : striped;
}

多亏了@frhack。可以编写测试你拥有的Macther类类似于排序比较。简单为平等,如

public static class BigDecimalEqualComparator extends TypeSafeMatcher<BigDecimal> {
private final BigDecimal expected;
private static final String[] comparisonDescriptions = { "less than", "equal to", "greater than" };
public BigDecimalEqualComparator( BigDecimal expected ) {
this.expected = expected;
}
@Override
public boolean matchesSafely( BigDecimal actual ) {
return actual.compareTo( expected ) == 0;
}
// You must change this
@Override
public void describeMismatchSafely( BigDecimal actual, Description mismatchDescription ) {
mismatchDescription.appendValue( actual.stripTrailingZeros().toPlainString() ).appendText( " was " )
.appendText( asText( actual.compareTo( expected ) ) ).appendText( " " )
.appendValue( expected.stripTrailingZeros().toPlainString() );
}
@Override
public void describeTo( Description description ) {
description.appendText( "a value equal to " ).appendValue( expected.stripTrailingZeros().toPlainString() );
}
private static String asText( int comparison ) {
return comparisonDescriptions[signum( comparison ) + 1];
}
}

可能的解决方案:

实现一个 BigDecimalToCompare 作为 BigDecimal 的包装类:

public class BigDecimalToCompare {
private final BigDecimal bigDecimal;
public BigDecimal getBigDecimal(){
return bigDecimal;
}
BigDecimalToCompare(BigDecimal bigDecimal){
this.bigDecimal = bigDecimal;
}
@Override
public boolean equals(Object obj){
return bigDecimal.compareTo(((BigDecimalToCompare)obj).getBigDecimal()) ==0;
}
@Override
public String toString(){
return bigDecimal.toString();
}
public static BigDecimalToCompare of(BigDecimal bd){
return new BigDecimalToCompare(bd);
}

}

测试如下:

@Test
public void test(){
BigDecimal a = new BigDecimal("100");
BigDecimal b = new BigDecimal("100.00");
assertEquals(BigDecimalToCompare.of(a),BigDecimalToCompare.of(b));
}

另一种可能的解决方案:

assertEquals(new BigDecimal("150").stripTrailingZeros(),
otherBigDecimal.stripTrailingZeros());

最新更新