金额计算不能用doube!!!!
金额计算必须用BigDecimal,下面对比一下用double 跟BigDecimal的区别。先看一个小例子:
请看题:
示例1
问, 结果是多少? 0.01?
No! 结果是0.009999999999999998!
为什么会这样呢? 因为float和double都是浮点数, 都有取值范围, 都有精度范围. 浮点数与通常使用的小数不同, 使用中, 往往难以确定.
常见的问题是定义了一个浮点数, 经过一系列的计算, 它本来应该等于某个确定值, 但实际上并不是!
double相减会转换成二进制,因double有效位数为 16位这就会出现存储小数位数不够的情况,这种情况下就会出现误差,解决方法就是使用BigDecimal,它的有效长度足够长可存储小数位数。
因此可代替double来进行加减乘除, 金额必须是完全精确的计算, 故不能使用double或者float, 而应该采用java.math.BigDecimal.
加减乘除
两个BigDecimal值应该怎样进行加减乘除呢? +, -, *, / 这样写吗? 不!
请看示例:
加减乘除使用了英文的加减乘除, 即add, substract, multiply和divide
大小比较
两个BigDecimal值怎么比较大小呢? 能用>或者<吗? 也不可以!
两个BigDecimal值比较使用compareTo方法, 比较结果有-1, 0, 1, 分别表示小于, 等于, 大于; 对于0, 可以使用BigDecimal.ZERO表示!
四舍五入
简化BigDecimal计算的小工具类
如果我们要做一个加法运算,需要先将两个浮点数转为String,然后够造成BigDecimal,在其中一个上调用add方法,传入另一个作为参数,然后把运算的结果(BigDecimal)再转换为浮点数。
你能够忍受这么烦琐的过程吗?
网上提供的工具类Arith来简化操作。它提供以下静态方法,包括加减乘除和四舍五入:
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)
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 |
|
定点数和浮点数的区别
在计算机系统的发展过程中,曾经提出过多种方法表达实数。典型的比如相对于浮点数的定点数(Fixed Point Number)。在这种表达方式中,小数点固定的位于实数所有数字中间的某个位置。
货币的表达就可以使用这种方式,比如 99.00 或者 00.99 可以用于表达具有四位精度(Precision),小数点后有两位的货币值。由于小数点位置固定,所以可以直接用四位数值来表达相应的数值。
SQL 中的 NUMBER 数据类型就是利用定点数来定义的。还有一种提议的表达方式为有理数表达方式,即用两个整数的比值来表达实数。
定点数表达法的缺点在于其形式过于僵硬,固定的小数点位置决定了固定位数的整数部分和小数部分,不利于同时表达特别大的数或者特别小的数。
最终,绝大多数现代的计算机系统采纳了所谓的浮点数表达方式。这种表达方式利用科学计数法来表达实数,即用一个尾数(Mantissa ),一个基数(Base),一个指数(Exponent)以及一个表示正负的符号来表达实数。
比如 123.45 用十进制科学计数法可以表达为 1.2345 × 102 ,其中 1.2345 为尾数,10 为基数,2 为指数。浮点数利用指数达到了浮动小数点的效果,从而可以灵活地表达更大范围的实数。
在MySQL中使用浮点数类型和定点数类型来表示小数。浮点数类型包括单精度浮点数(FLOAT型)和双精度浮点数(DOUBLE型)。定点数类型就是DECIMAL型。MySQL的浮点数类型和定点数类型如下表所示:
类型名称 | 字节数 | 负数的取值范围 | 非负数的取值范围 |
---|---|---|---|
FLOAT | 4 | -3.402823466E+38~ -1.175494351E-38 | 0和1.175494351E-38~ 3.402823466E+38 |
DOUBLE | 8 | -1.7976931348623157E+308~ -2.2250738585072014E-308 | 0和2.2250738585072014E-308~ 1.7976931348623157E+308 |
DECIMAL(M,D)或DEC(M,D) | M+2 | 同DOUBLE型 | 同DOUBLE型 |
从上表中可以看出,DECIMAL型的取值范围与DOUBLE相同。但是,DECIMAL的有效取值范围由M和D决定,而且DECIMAL型的字节数是M+2,也就是说,定点数的存储空间是根据其精度决定的。
MySQL
BigDecimal在进行入库时, 数据库选择decimal类型, 长度可以自定义, 如18; 小数点我们项目中用的是2, 保留2位小数. 此外还要注意的就是默认值, 一定写成0.00, 不要用默认的NULL, 否则在进行加减排序等操作时, 会带来转换的麻烦!
`balance` decimal(18,2) DEFAULT '0.00' COMMENT '账户余额',