当前位置:首页 > Java技术 > 项目中BigDecimal与Double使用场景

项目中BigDecimal与Double使用场景

2022年09月16日 22:46:43Java技术6

金额要用BigDecimal

金额计算不能用doube!!!!

金额计算必须用BigDecimal,下面对比一下用double 跟BigDecimal的区别。先看一个小例子:

请看题:

项目中BigDecimal与Double使用场景 _ JavaClub全栈架构师技术笔记

示例1

问, 结果是多少? 0.01?

No! 结果是0.009999999999999998!

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

常见的问题是定义了一个浮点数, 经过一系列的计算, 它本来应该等于某个确定值, 但实际上并不是!

double相减会转换成二进制,因double有效位数为 16位这就会出现存储小数位数不够的情况,这种情况下就会出现误差,解决方法就是使用BigDecimal,它的有效长度足够长可存储小数位数。

因此可代替double来进行加减乘除, 金额必须是完全精确的计算, 故不能使用double或者float, 而应该采用java.math.BigDecimal.

加减乘除

两个BigDecimal值应该怎样进行加减乘除呢? +, -, *, / 这样写吗? 不!

请看示例:

项目中BigDecimal与Double使用场景 _ JavaClub全栈架构师技术笔记

加减乘除使用了英文的加减乘除, 即add, substract, multiply和divide

大小比较

两个BigDecimal值怎么比较大小呢? 能用>或者<吗? 也不可以!

项目中BigDecimal与Double使用场景 _ JavaClub全栈架构师技术笔记

两个BigDecimal值比较使用compareTo方法, 比较结果有-1, 0, 1, 分别表示小于, 等于, 大于; 对于0, 可以使用BigDecimal.ZERO表示!

四舍五入

项目中BigDecimal与Double使用场景 _ JavaClub全栈架构师技术笔记

 

简化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)  

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 '账户余额',

 

作者:森林木马
来源链接:https://www.cnblogs.com/owenma/p/7991508.html

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。


本文链接:https://www.javaclub.cn/java/42281.html

标签: BigDecimal
分享给朋友:

“项目中BigDecimal与Double使用场景” 的相关文章

java BigDecimal(String val)确保小数点后有效位数 ✨ 每日积累

float输出,前7位有效数字是真实值,第8位是估算值,可能和原始一致,可能是四舍五入上来的。double值,前15位有效数字是真实值,第16位是估算值,可能和原始一致,可能是四舍五入上来的。当小数点后的有效位数超过float和doulbe的有效位置之后...

Java 使用BigDecimal进行高精度加减乘除

有时候我们计算金钱或者其他一些计算的时候需要高精度的计算加减乘除,可以使用BigDecimal 加: BigDecimal num1 = new BigDecimal("100.569"); BigDecimal num2 = new Big...

BigDecimal转为int类型

BigDecimal转为int类型

直接调用BigDecimal的intValue()方法 示例: BigDecimal a = new BigDecimal(“1.1”); int b = a.intValue(); BigDecimal运算方法:...

JDK中BigDecimal的代码实现

package java.math; import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.PrintStream;...

BigDecimal 使用compareTo比较大小

1.BigDecimal的比较模式  BigDecimal b1 = new BigDecimal(0.1); BigDecimal b2 = new BigDecimal(0.2); int c = b1.compareTo(b2); // -1 c=1表示...

BigDecimal常被忽略的问题

BigDecimal常被忽略的问题

  一:相除精度丢失的问题   BigDecimal的api除法相对加减乘要实现的复杂多了,只介绍常用的我遇到的问题:   问题:两数相除,如果9/3=3整除没问题,但是10/3=0.33333333......除不尽,这里不能让电脑一直除不尽,所以BigD...

BigDecimal

import java.math.BigDecimal; import java.math.RoundingMode; public class BigDecimalTest { public static void main(String[] args) {...

BigDecimal在使用中遇到的问题

BigDecimal在使用中遇到的问题

问题出处 今天在做活动统计的时候遇到的问题,数据库使用的字段为字符串来存储金额,解释就是不确定奖励是物品还是金钱,所以使用字符串来存储的,在查询做统计的时候需要对这个字段进行相加操作,本来想了下在mapper里直接使用sql来进行统计,后来测试是行...

BigInteger类,BigDecimal类,超大数字的运算与精度

 BigInteger类   可以让超过Integer范围内的数据进行运算   不可变的任意精度的整数。  java.lang.Object  ——java.lang.Number ——————java.math.Bi...

BigDecimal 判断大于小于

BigDecimal a = new BigDecimal (101); BigDecimal b = new BigDecimal (111);   //使用compareTo方法比较 //注意:a、b均不能为null,否则会报空指针 if(a.compareTo(b...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。