JAVA 精度使用

1. Double使用

记住java一定要用double,更鼓不变,就算数值不大也要用double。了解java虚拟机的底层会知道,float放在内存中其实是当作double来处理的,它不会比double更节约内存资源,对应的double虚拟机会直接以double形式来进行处理,快速而且精度高,但是如果用float,不但不会节约内存资源,虚拟机为了校验float的精度,会花费更多的系统资源,例如cpu时钟,程序执行步骤等等。

相对于这点,整数类型,能用int就用int,不要用什么short类型,道理是一样,其实虚拟机中short,char,boolean,byte在内存中都是以int形式来处理的,为了校验精度,虚拟机还会付出格外的开销,这样其实得不偿失,不要自作聪明以为节约了内存,其实错了。当然long类型例外,虽然long类型也会增加资源的开销,但是毕竟能完成int完成不了的功能。

还有,其实这些资源的开销对于整个应用程序和现有硬件资源而言就是九牛一毛,微乎其微,没有必要过于在意。就用习惯的形式即可。不要自作聪明的用特别的数据类型,浮点就double,整形就int,长整型就long,其它的必要性都不大(byte的话,用来做数组还是很方便的,除此不推荐使用)

2. BigDecimal使用

在商业计算中,比如尤其是电商这块,你要算两个商品的价格,可能是优惠前和优惠后的差价。
很多程序员,尤其是没怎么接触过这个行业的程序员都会使用double来描述一个金额。于是便出现了下面这个计算

  1. public static void main(String[] args) {
  2. double priceA = 0.03;
  3. double priceB = 0.02;
  4. System.out.println(priceA - priceB);
  5. }

这个算出来是多少。我保证肯定有很多人会说:”0.01呀,这还用问么?”。然而真实运行出来的结果却是:

Mysql Java金钱的数据类型一般使用 - 图1

为什么是0.009999999999999998 而不是0.01,因为float和double都是浮点数, 都有取值范围, 都有精度范围. 浮点数与通常使用的小数不同, 使用中, 往往难以确定。

常见的问题是定义了一个浮点数, 经过一系列的计算, 它本来应该等于某个确定值, 但实际上并不是!金额必须是完全精确的计算, 故不能使用double或者float, 而应该采用java.math.BigDecimal。在《Effective Java》这本书中也提到这个原则,float和double只能用来做科学计算或者是工程计算,在商业计算中我们要java.math.BigDecimal。而且使用BigDecimal类也可以进行大数的操作。BigDecimal具体的操作见:https://www.hellojava.com/article/128
所以改成如下代码:

  1. public static void main(String[] args) {
  2. BigDecimal priceA = BigDecimal.valueOf(0.03);
  3. BigDecimal priceB = BigDecimal.valueOf(0.02);
  4. System.out.println(priceA.subtract(priceB));
  5. }

运行出来的结果就对了。
以上代码运行出来的结果就是:

  1. 0.01


Mysql精度对比

一般用decimal,长度18,保存2位小数,具体看业务

在java的开发中,货币在数据库中MySQL常用Decimal和Numric类型表示,这两种类型被MySQL实现为同样的类型。他们被用于保存值,该值的准确精度是极其重要的值,例如与金钱有关的数据。当声明一个类是这些类型之一时,精度和规模的能被(并且通常是)指定;例如:
salary DECIMAL(9,2)

在这个例子中,9(precision)代表将被用于存储值的总的小数位数,而2(scale)代表将被用于存储小数点后的位数。因此,在这种情况下,能被存储在salary列中的值的范围是从-9999999.99到9999999.99

  1. DECIMALNUMERIC值作为字符串存储,而不是作为二进制浮点数,以便保存那些值的小数精度。一个字符用于值的每一位、小数点(如果scale>0)和“-”符号(对于负值)。如果scale0DECIMALNUMERIC值不包含小数点或小数部分。
  2. 不使用float或者double的原因:因为floatdouble是以二进制存储的,所以有一定的误差。
  3. 1
  4. 2
  5. 3

比如:在数据库中c1,c2,c3分别存储类型是float(10.2),decimal(10.2),float类型。

插入数据:
Mysql Java金钱的数据类型一般使用 - 图2
INTO test (c1,c2,c3) VALUES (1234567.23,1234567.23,1234567.23)

Mysql Java金钱的数据类型一般使用 - 图3