首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从BigDecimal中删除十进制结束零

从BigDecimal中删除十进制结束零
EN

Stack Overflow用户
提问于 2017-03-16 09:26:15
回答 3查看 8.8K关注 0票数 4

我编写测试,并希望将BigDecimal结果与期望值进行比较。我希望使用Assert.assertEquals(BigDecimal, BigDecimal)方法,因为如果删除它,它会显示精确的比较值,而在eclipse中,我可以显示比较窗口。

因此,在代码中,我有返回BigDecimal四舍五入到小数点2位的方法。在测试用例中,我现在返回没有非零十进制数字的数字。因此,我希望创建标度为0的BigDecimal,并将BigDecimal返回到相同的比例。

考虑到更多的复杂性,我现在有了方法getDecimal(Object [,Optionaly int scale]),它可以从任何具有正确toString()值的对象中创建BigDecimal,该值具有默认的toString()值99。我在主要的“重”代码中使用它,所以这个方法必须非常快(不需要创建另一个对象,也不需要使用regexp等等)。

因此,简单的问题是:如何修改BigDecimal实例,以以最小的负载来修剪结尾的十进制零。

想要这样的撕扯

代码语言:javascript
复制
0.010 -> 0.01
5.000 -> 5
100 -> 100   not 1E+2

Resp:

代码语言:javascript
复制
someTrim(new BigDecimal("100.00")).equals(new BigDecimal(100))

做数学,就像

代码语言:javascript
复制
100.00 / (2, 99, DOWN) * 50.00 -> 2500

我的代码看起来就像

代码语言:javascript
复制
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比较方法,但我不知道。

谢谢你帮忙。铺设

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-03-16 11:53:58

我可能找到了解决办法。创建另外两个BigDecimal实例是不好的,但不知道另一个入侵较少的方法。如果没有必要,我很少做优化来不创建实例。

代码语言:javascript
复制
/** 
 * 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。您可以编写类似于OrderingComparsion的Macther类进行测试。简单的等价物

代码语言:javascript
复制
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];
    }
}
票数 1
EN

Stack Overflow用户

发布于 2017-03-18 10:56:26

这个需求的正式junit解决方案是使用hamcrest。

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

代码语言:javascript
复制
    BigDecimal a = new BigDecimal("100")
    BigDecimal b = new BigDecimal("100.00")
    assertThat(a,  Matchers.comparesEqualTo(b));

Hamcrest 1.3快速参考

票数 1
EN

Stack Overflow用户

发布于 2017-03-16 10:34:41

可能的解决办法:

将BigDecimalToCompare实现为BigDecimal的包装类:

代码语言:javascript
复制
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);
}

}

测试如下:

代码语言:javascript
复制
@Test
public void test(){
    BigDecimal a = new BigDecimal("100");
    BigDecimal b = new BigDecimal("100.00");
    assertEquals(BigDecimalToCompare.of(a),BigDecimalToCompare.of(b));
}

另一种可能的解决办法是:

代码语言:javascript
复制
assertEquals(new BigDecimal("150").stripTrailingZeros(),
                otherBigDecimal.stripTrailingZeros());
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42829933

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档