BigDecimal
在《Effective Java》这本书中也提到q个原则Qfloat和double只能用来做科学计或者是工程计算Q在商业计算中我们要用java.math.BigDecimal。BigDecimal一共有4个够造方法,我们不关心用BigInteger来够造的那两个,那么q有两个Q它们是Q?br />
BigDecimal(double val)
Translates a double into a BigDecimal.
BigDecimal(String val)
Translates the String repre sentation of a BigDecimal into a BigDecimal.
上面的API要描q相当的明确Q而且通常情况下,上面的那一个用v来要方便一些。我们可能想都不惛_用上了,会有什么问题呢Q等到出了问题的时候,才发C面哪个够造方法的详细说明中有q么一D:
Note: the results of this constructor can be somewhat unpredictable. One might assume that new BigDecimal(.1) is exactly equal to .1, but it is actually equal to .1000000000000000055511151231257827021181583404541015625. This is so because .1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the long value that is being passed in to the constructor is not exactly equal to .1, appearances nonwithstanding.
The (String) constructor, on the other hand, is perfectly predictable: new BigDecimal(".1") is exactly equal to .1, as one would expect. Therefore, it is generally recommended that the (String) constructor be used in preference to this one.
原来我们如果需要精计,非要用String来够造BigDecimal不可Q在《Effective Java》一书中的例子是用String来够造BigDecimal的,但是书上却没有强调这一点,q也许是一个小的p吧?br />
解决Ҏ
现在我们已经可以解决q个问题了,原则是用BigDecimalq且一定要用String来够造?br />
但是惛_一下吧Q如果我们要做一个加法运,需要先两个QҎ转ؓStringQ然后够造成BigDecimalQ在其中一个上调用addҎQ传入另一个作为参敎ͼ然后把运的l果QBigDecimalQ再转换为QҎ。你能够忍受q么烦琐的过E吗Q下面我们提供一个工LArith来简化操作。它提供以下静态方法,包括加减乘除和四舍五入:
public static double add(double v1,double v2)
public static double sub(double v1,double v2)
public static double mul(double v1,double v2)
public static double div(double v1,double v2)
public static double div(double v1,double v2,int scale)
public static double round(double v,int scale)
附录
源文件Arith.javaQ?br />
import java.math.BigDecimal;
/**
* ׃Java的简单类型不能够_的对点数进行运,q个工具cL供精
* 的点数运,包括加减乘除和四舍五入?br />
*/
public class Arith{
//默认除法q算_ֺ
private static final int DEF_DIV_SCALE = 10;
//q个cM能实例化
private Arith(){
}
/**
* 提供Q相对)_的除法运。当发生除不的情况Ӟ由scale参数?br />
* 定精度,以后的数字四舍五入?br />
* @param v1 被除?br />
* @param v2 除数
* @param scale 表示表示需要精到数点以后几位?br />
* @return 两个参数的商
*/
public static double div(double v1,double v2,int scale){
if(scale<0){
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 提供_的小C四舍五入处理?br />
* @param v 需要四舍五入的数字
* @param scale 数点后保留几位
* @return 四舍五入后的l果
*/
public static double round(double v,int scale){
if(scale<0){
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(Double.toString(v));
BigDecimal one = new BigDecimal("1");
return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
}
};