如何对“无精度错误”进行单位测试数值计算?

问题描述:

我们有一个用Java编写的大型系统,大部分时间精度并不那么重要。因此,我们将所有数字存储在两倍。如何对“无精度错误”进行单位测试数值计算?

但是,几年之后,出现了新的要求,对于某些罕见的情况,精确度很重要。所以我有这种情况,我需要采取一个价格(代表double),基地(也代表double),并将价格四舍五入到最接近的基数的倍数,并将结果再次存储在double

十进制形式中,这是简单的:result = roundDownToBase(price + base*0.5, base)

据我所知,与双天真地进行上述式将导致精度问题。我也明白一个适当的解决办法是在计算过程中将所有内容转换为BigDecimal。

我的问题是,我怎样才能系统地(单元)测试BigDecimal版本没有双倍版本具有相同的精度问题?我可以随机选择一些数值并声明结果,但由于输入的宇宙是无限的,这似乎没有给我太多信心。或者,有没有一种方法可以在单元测试中系统地选择一些代表性值,并对代码质量产生相当高的置信度?

P.S.我的代码:

public static double roundToNear(double price, double base) { 
     BigDecimal value = BigDecimal.valueOf(price); 
     BigDecimal baseValue = BigDecimal.valueOf(base); 
     BigDecimal two = BigDecimal.valueOf(2); 
     BigDecimal halfUp = value.add(baseValue.divide(two)); 
     return roundDownToBase(halfUp.doubleValue(), base); 
    } 

    public static double roundDownToBase(double value, double base) { 
     BigDecimal val1 = BigDecimal.valueOf(value); 
     BigDecimal val2 = BigDecimal.valueOf(base); 
     BigDecimal remainder = val1.remainder(val2); 
     return MathUtil.isZeroOrNaN(remainder.doubleValue()) ? value:val1.subtract(remainder).doubleValue(); 
    } 
+0

当你将'halfUp'转换为double时,你可能会失去精度。 –

+0

@PatriciaShanahan是的,如果你只看那个单一的陈述,那是对的。然而,所得到的不精确的双精度仍然是最能代表真正的小数半数的双精度 - 例如该double上的toString将与小数点上的toString相同。这里的事情是,roundDown方法将再次将double表示的halfup放入BigDecimal中,这将带回精度。 BigDecimal.valueOf(halfup.doubleValue())应该与halfup相同 – Xinchao

+0

“该double上的toString将与小数点上的toString相同”简单反例:尝试'price = 1e20'和'base = 1'。 'halfUp'toString是100000000000000000000.5,double的toString是1.0E20。将double转换为BigDecimal将得到1e20,不需要额外的0.5。 –

我认为在这种情况下,他们是平台的方法,在我的经验,单元测试,你不能测试这些方法是你写代码,例如,如果你认为roundDownToBase(10.01 ,10.02)应该返回实例5,那么这将是一个有效的文本,否则你不能测试双因为这是平台功能

+0

但即使对我而言,随机挑选几个输入对和如果你有一个函数addtwointeger(int a和int b){return a + b;}唯一的一个测试,那么这个测试是否是一个更有系统的方法呢?对于数值计算算法,我们如何对它们进行单元测试? – Xinchao

+0

你可以做的是assertthat(addtwointeger(1,1))。isequalto(2);算术运算不在你的控制之中,因此你不能测试它,这是框架,我希望它是有道理的。 –

+0

意思是说,当你把你的addTwoInteger当作一个黑盒子,你不知道它在内部做了一个原始的add操作或者一些有趣的东西,比如for(int i = 1; i Xinchao