package test.com.xy6.interview.util;
import static org.junit.Assert.assertEquals;
import java.math.BigDecimal;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class TestProductUtil {
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void testRoundTax() {
BigDecimal bd2 = BigDecimal.valueOf(10.10);
BigDecimal bd3 = BigDecimal.valueOf(10.20);
assertEquals(bd2,bd3);
}
}
上述代码运行通过,junit版本junit4.4。
原因:初始化BigDecimal时,方法使用错误,应使用valueOf(String),而非valueOf(double)。
BigDecimal对象有两个构造函数public BigDecimal(double val),public BigDecimal(String val)。在使用double进行初始化时,转换后的数据是不精确的。如传入0.1,转换后的数据可能为.0.1000000000000000055511151231257827021181583404541015625。这是由浮点型自身的特性决定的,它并不能精确地描述一个数据。故Effective Java中建议:float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用java.math.BigDecimal。
官方API(http://docs.oracle.com/javase/6/docs/api/index.html)中对于public BigDecimal(double val)的解释是比较清楚的:
BigDecimal
public BigDecimal(double val)
Translates a double into a BigDecimal which is the exact decimal representation of the double's binary floating-point value. The scale of the returned BigDecimal is the smallest value such that (10scale × val) is an integer.
Notes:
1 The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.
2 The String constructor, on the other hand, is perfectly predictable: writing new BigDecimal("0.1") creates a BigDecimal which is exactly equal to 0.1, as one would expect. Therefore, it is generally recommended that the String constructor be used in preference to this one.
3 When a double must be used as a source for a BigDecimal, note that this constructor provides an exact conversion; it does not give the same result as converting the double to a String using the Double.toString(double) method and then using the BigDecimal(String) constructor. To get that result, use the static valueOf(double) method.
修改后的代码:
BigDecimal bd2 = new BigDecimal("10.10");
BigDecimal bd3 = new BigDecimal("10.20");
assertEquals(bd2,bd3);
此时,测试是不通过的。