金额计算不能用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

import java.math.BigDecimal;

/**

 * 进行BigDecimal对象的加减乘除,四舍五入等运算的工具类 

 * @author ameyume

 *

 */

public class Arith {

    /**

     * 由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精  

     * 确的浮点数运算,包括加减乘除和四舍五入。  

     */

    //默认除法运算精度   

    private static final int DEF_DIV_SCALE = 10;

    //这个类不能实例化   

    private Arith(){

    }

    /**

     * 提供精确的加法运算。  

     * @param v1 被加数  

     * @param v2 加数  

     * @return 两个参数的和

     */

    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();

    }

    /**

     * 提供精确的减法运算。  

     * @param v1 被减数  

     * @param v2 减数  

     * @return 两个参数的差

     */

    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();

    }

    /**

     * 提供精确的乘法运算。  

     * @param v1 被乘数  

     * @param v2 乘数  

     * @return 两个参数的积

     */

    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();

    }

    /**

     * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到  

     * 小数点以后10位,以后的数字四舍五入。  

     * @param v1 被除数  

     * @param v2 除数  

     * @return 两个参数的商

     */

    public static double div(double v1,double v2){

        return div(v1,v2,DEF_DIV_SCALE);

    }

    /**

     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指  

     * 定精度,以后的数字四舍五入。  

     * @param v1 被除数  

     * @param v2 除数  

     * @param scale 表示表示需要精确到小数点以后几位。  

     * @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();

    }

    /**

     * 提供精确的小数位四舍五入处理。  

     * @param v 需要四舍五入的数字  

     * @param scale 小数点后保留几位  

     * @return 四舍五入后的结果

     */

    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();

    }

    /**

     * 提供精确的类型转换(Float)  

     * @param v 需要被转换的数字  

     * @return 返回转换结果

     */

    public static float convertsToFloat(double v){

        BigDecimal b = new BigDecimal(v);

        return b.floatValue();

    }

    /**

     * 提供精确的类型转换(Int)不进行四舍五入  

     * @param v 需要被转换的数字  

     * @return 返回转换结果

     */

    public static int convertsToInt(double v){

        BigDecimal b = new BigDecimal(v);

        return b.intValue();

    }

    /**

     * 提供精确的类型转换(Long)  

     * @param v 需要被转换的数字  

     * @return 返回转换结果

     */

    public static long convertsToLong(double v){

        BigDecimal b = new BigDecimal(v);

        return b.longValue();

    }

    /**

     * 返回两个数中大的一个值  

     * @param v1 需要被对比的第一个数  

     * @param v2 需要被对比的第二个数  

     * @return 返回两个数中大的一个值

     */

    public static double returnMax(double v1,double v2){

        BigDecimal b1 = new BigDecimal(v1);

        BigDecimal b2 = new BigDecimal(v2);

        return b1.max(b2).doubleValue();

    }

    /**

     * 返回两个数中小的一个值  

     * @param v1 需要被对比的第一个数  

     * @param v2 需要被对比的第二个数  

     * @return 返回两个数中小的一个值

     */

    public static double returnMin(double v1,double v2){

        BigDecimal b1 = new BigDecimal(v1);

        BigDecimal b2 = new BigDecimal(v2);

        return b1.min(b2).doubleValue();

    }

    /**

     * 精确对比两个数字  

     * @param v1 需要被对比的第一个数  

     * @param v2 需要被对比的第二个数  

     * @return 如果两个数一样则返回0,如果第一个数比第二个数大则返回1,反之返回-1  

     */

    public static int compareTo(double v1,double v2){

        BigDecimal b1 = new BigDecimal(v1);

        BigDecimal b2 = new BigDecimal(v2);

        return b1.compareTo(b2);

    }

  

定点数和浮点数的区别

在计算机系统的发展过程中,曾经提出过多种方法表达实数。典型的比如相对于浮点数的定点数(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 '账户余额',

金额要用BigDecimal,原理分析相关推荐

  1. 支付宝app支付java后台流程、原理分析(含nei wang chuan tou)

    java版支付宝app支付流程及原理分析 本实例是基于springmvc框架编写      一.流程步骤          1.执行流程            当手机端app(就是你公司开发的app) ...

  2. java signature 性能_Java常见bean mapper的性能及原理分析

    背景 在分层的代码架构中,层与层之间的对象避免不了要做很多转换.赋值等操作,这些操作重复且繁琐,于是乎催生出很多工具来优雅,高效地完成这个操作,有BeanUtils.BeanCopier.Dozer. ...

  3. Select函数实现原理分析

    转载自 http://blog.chinaunix.net/uid-20643761-id-1594860.html select需要驱动程序的支持,驱动程序实现fops内的poll函数.select ...

  4. spring ioc原理分析

    spring ioc原理分析 spring ioc 的概念 简单工厂方法 spirng ioc实现原理 spring ioc的概念 ioc: 控制反转 将对象的创建由spring管理.比如,我们以前用 ...

  5. 一次 SQL 查询优化原理分析(900W+ 数据,从 17s 到 300ms)

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 来源:Muscleape jianshu.com/p/0768eb ...

  6. 原理分析_变色近视眼镜原理分析

    随着眼镜的发展,眼镜的外型变得越来越好看,并且眼镜的颜色也变得多姿多彩,让佩戴眼镜的你变得越来越时尚.变色近视眼镜就是由此产生的新型眼镜.变色镜可以随着阳光的强弱变换不同的色彩. 变色眼镜的原理分析 ...

  7. jieba分词_从语言模型原理分析如何jieba更细粒度的分词

    jieba分词是作中文分词常用的一种工具,之前也记录过源码及原理学习.但有的时候发现分词的结果并不是自己最想要的.比如分词"重庆邮电大学",使用精确模式+HMM分词结果是[&quo ...

  8. EJB调用原理分析 (飞茂EJB)

    EJB调用原理分析 EJB调用原理分析 作者:robbin (MSN:robbin_fan AT hotmail DOT com) 版权声明:本文严禁转载,如有转载请求,请和作者联系 一个远程对象至少 ...

  9. 深入掌握Java技术 EJB调用原理分析

      深入掌握Java技术 EJB调用原理分析     一个远程对象至少要包括4个class文件:远程对象:远程对象的接口:实现远程接口的对象的stub:对象的skeleton这4个class文件. 在 ...

  10. 神经网络(NN)+反向传播算法(Backpropagation/BP)+交叉熵+softmax原理分析

    神经网络如何利用反向传播算法进行参数更新,加入交叉熵和softmax又会如何变化? 其中的数学原理分析:请点击这里. 转载于:https://www.cnblogs.com/code-wangjun/ ...

最新文章

  1. 常见问题:内存,循环引用,runloop的简单理解
  2. hashCode() 和equals() 区别和作用
  3. 如何识别真正的程序员
  4. 前端学习(3249):react的文件src
  5. Csharp迭代循环
  6. 如何解决comctl32.dll文件丢失的问题?
  7. Python 调试:pdb
  8. 超详细讲解,带你零基础入门 kafka!
  9. hpml350服务器安装系统,安装HP ML350
  10. 由异常掉电问题---谈xfs文件系统
  11. python选择日期控件_Python3 自己写了个DateCtrl日期控件 | 学步园
  12. RH413-Linux系统下umask测试
  13. git pull keeping local changes
  14. 史上最强图标下载,3124个图标专辑,超过60万免费图标提供下载
  15. 基于bim二次开发的智能楼宇管理系统
  16. 酷软 正在连接服务器,酷软一直显示正在连接服务器...系统日志有大量错误信息...
  17. 2020年产品经理面试题
  18. 网传互联网公司大裁员
  19. squid代理服务器的应用
  20. Word自带编辑器设置类Times New Roman字体

热门文章

  1. 用Python在地图上模拟疫情扩散
  2. 标准正态分布怎么算_标准正态分布密度函数计算公式怎么算、
  3. 电机控制-H 桥电路 控制方式简单解析
  4. Java类加载机制--类加载过程(加载)
  5. 基于QT和DCMTK的Dicom 图像浏览器---目录
  6. easyar android 开发,【EasyAR学习】安装Android SDK
  7. 小白的网站seo经验
  8. 对龙果支付系统的简单了解
  9. 卡尔滤波算法 java_卡尔曼滤波算法及其代码
  10. 索爱S318小蜜蜂扩音器性能如何?