问题重现
使用示例:
1 2 3 4 5
| BigDecimal a =new BigDecimal(0.1); System.out.println("a values is:"+a); System.out.println("====================="); BigDecimal b =new BigDecimal("0.1"); System.out.println("b values is:"+b);
|
结果示例:
1 2 3
| a values is:0.1000000000000000055511151231257827021181583404541015625 ===================== b values is:0.1
|
原因分析:
- 参数类型为double的构造方法的结果有一定的不可预知性。有人可能认为在Java中写入newBigDecimal(0.1)所创建的BigDecimal正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。
- String 构造方法是完全可预知的:写入 newBigDecimal(“0.1”) 将创建一个 BigDecimal,它正好等于预期的 0.1。因此,比较而言, 通常建议优先使用String构造方法。
- 当double必须用作BigDecimal的源时,请注意,此构造方法提供了一个准确转换;它不提供与以下操作相同的结果:先使用Double.toString(double)方法,然后使用BigDecimal(String)构造方法,将double转换为String。要获取该结果,请使用static valueOf(double)方法。
BigDecimal常用方法详解
常用方法
add(BigDecimal) BigDecimal对象中的值相加,返回BigDecimal对象
subtract(BigDecimal) BigDecimal对象中的值相减,返回BigDecimal对象
multiply(BigDecimal) BigDecimal对象中的值相乘,返回BigDecimal对象
divide(BigDecimal) BigDecimal对象中的值相除,返回BigDecimal对象
toString() 将BigDecimal对象中的值转换成字符串
doubleValue() 将BigDecimal对象中的值转换成双精度数
floatValue() 将BigDecimal对象中的值转换成单精度数
longValue() 将BigDecimal对象中的值转换成长整数
intValue() 将BigDecimal对象中的值转换成整数
BigDecimal大小比较
java中对BigDecimal比较大小一般用的是bigdemical的compareTo方法
1
| int a = bigdemical.compareTo(bigdemical2)
|
返回结果分析:
a = -1,表示bigdemical小于bigdemical2;
a = 0,表示bigdemical等于bigdemical2;
a = 1,表示bigdemical大于bigdemical2;
举例:a大于等于b
new bigdemica(a).compareTo(new bigdemical(b)) >= 0
BigDecimal格式化
由于NumberFormat类的format()方法可以使用BigDecimal对象作为其参数,可以利用BigDecimal对超出16位有效数字的货币值,百分值,以及一般数值进行格式化控制。
以利用BigDecimal对货币和百分比格式化为例。首先,创建BigDecimal对象,进行BigDecimal的算术运算后,分别建立对货币和百分比格式化的引用,最后利用BigDecimal对象作为format()方法的参数,输出其格式化的货币值和百分比。
1 2 3 4 5 6 7 8 9 10 11
| NumberFormat currency = NumberFormat.getCurrencyInstance(); NumberFormat percent = NumberFormat.getPercentInstance(); percent.setMaximumFractionDigits(3); BigDecimal loanAmount = new BigDecimal("15000.48"); BigDecimal interestRate = new BigDecimal("0.008"); BigDecimal interest = loanAmount.multiply(interestRate); System.out.println("贷款金额:\t" + currency.format(loanAmount)); System.out.println("利率:\t" + percent.format(interestRate)); System.out.println("利息:\t" + currency.format(interest));
|
结果:
贷款金额: ¥15,000.48 利率: 0.8% 利息: ¥120.00
BigDecimal格式化保留2为小数,不足则补0:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class NumberFormat { public static void main(String[] s){ System.out.println(formatToNumber(new BigDecimal("3.435"))); System.out.println(formatToNumber(new BigDecimal(0))); System.out.println(formatToNumber(new BigDecimal("0.00"))); System.out.println(formatToNumber(new BigDecimal("0.001"))); System.out.println(formatToNumber(new BigDecimal("0.006"))); System.out.println(formatToNumber(new BigDecimal("0.206"))); }
public static String formatToNumber(BigDecimal obj) { DecimalFormat df = new DecimalFormat("#.00"); if(obj.compareTo(BigDecimal.ZERO)==0) { return "0.00"; }else if(obj.compareTo(BigDecimal.ZERO)>0&&obj.compareTo(new BigDecimal(1))<0){ return "0"+df.format(obj).toString(); }else { return df.format(obj).toString(); } } }
|
结果为:
3.44
0.00
0.00
0.00
0.01
0.21
BigDecimal常见异常
除法的时候出现异常
java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result
原因分析:
通过BigDecimal的divide方法进行除法时当不整除,出现无限循环小数时,就会抛异常:java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
解决方法:
divide方法设置精确的小数点,如:divide(xxxxx,2)
BigDecimal总结
在需要精确的小数计算时再使用BigDecimal,BigDecimal的性能比double和float差,在处理庞大,复杂的运算时尤为明显。故一般精度的计算没必要使用BigDecimal。
尽量使用参数类型为String的构造函数。
BigDecimal都是不可变的(immutable)的, 在进行每一次四则运算时,都会产生一个新的对象 ,所以在做加减乘除运算时要记得要保存操作后的值。
工具类推荐
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
| package com.vivo.ars.util; import java.math.BigDecimal;
public class ArithmeticUtils { private static final int DEF_DIV_SCALE = 10;
public static double add(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.add(b2).doubleValue(); }
public static BigDecimal add(String v1, String v2) { BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.add(b2); }
public static String add(String v1, String v2, int scale) { if (scale < 0) { throw new IllegalArgumentException( "The scale must be a positive integer or zero"); } BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.add(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString(); }
public static double sub(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.subtract(b2).doubleValue(); }
public static BigDecimal sub(String v1, String v2) { BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.subtract(b2); }
public static String sub(String v1, String v2, int scale) { if (scale < 0) { throw new IllegalArgumentException( "The scale must be a positive integer or zero"); } BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.subtract(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString(); }
public static double mul(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.multiply(b2).doubleValue(); }
public static BigDecimal mul(String v1, String v2) { BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.multiply(b2); }
public static double mul(double v1, double v2, int scale) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return round(b1.multiply(b2).doubleValue(), scale); }
public static String mul(String v1, String v2, int scale) { if (scale < 0) { throw new IllegalArgumentException( "The scale must be a positive integer or zero"); } BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.multiply(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString(); }
public static double div(double v1, double v2) { return div(v1, v2, DEF_DIV_SCALE); }
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(); }
public static String div(String v1, String v2, int scale) { if (scale < 0) { throw new IllegalArgumentException("The scale must be a positive integer or zero"); } BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v1); return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).toString(); }
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)); return b.setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue(); }
public static String round(String v, int scale) { if (scale < 0) { throw new IllegalArgumentException( "The scale must be a positive integer or zero"); } BigDecimal b = new BigDecimal(v); return b.setScale(scale, BigDecimal.ROUND_HALF_UP).toString(); }
public static String remainder(String v1, String v2, int scale) { if (scale < 0) { throw new IllegalArgumentException( "The scale must be a positive integer or zero"); } BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.remainder(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString(); }
public static BigDecimal remainder(BigDecimal v1, BigDecimal v2, int scale) { if (scale < 0) { throw new IllegalArgumentException( "The scale must be a positive integer or zero"); } return v1.remainder(v2).setScale(scale, BigDecimal.ROUND_HALF_UP); }
public static boolean compare(String v1, String v2) { BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); int bj = b1.compareTo(b2); boolean res; if (bj > 0) res = true; else res = false; return res; } }
|