前言:

Java中float的精度为6-7位有效数字。double的精度为15-16位。

我们都知道浮点型变量在进行计算的时候会出现丢失精度的问题。如下一段代码:

System.out.println(0.05 + 0.01);
System.out.println(1.0 - 0.42);
System.out.println(4.015 * 100);
System.out.println(123.3 / 100);  输出:
0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999

可以看到在Java中进行浮点数运算的时候,会出现丢失精度的问题。那么我们如果在进行商品价格计算的时候,就会出现问题。

很有可能造成我们手中有0.06元,却无法购买一个0.05元和一个0.01元的商品。

因为如上所示,他们两个的总和为0.060000000000000005。

这无疑是一个很严重的问题,尤其是当电商网站的并发量上去的时候,出现的问题将是巨大的。可能会导致无法下单,或者对账出现问题。所以接下来我们就可以使用Java中的BigDecimal类来解决这类问题。

float和double只能用来做科学计算和工程计算。商业运算中我们要使用BigDecimal。

阿里巴巴java开发手册(泰山版):

总结:BigDecimal不丢失精度的方式:new BigDecimal(String)  或者 BigDecimal(double/float/long)

一:BigDecimal基础介绍

【常用API】

add(BigDecimal)        BigDecimal对象中的值相加,然后返回这个对象
subtract(BigDecimal)   BigDecimal对象中的值相减,然后返回这个对象
multiply(BigDecimal)   BigDecimal对象中的值相乘,然后返回这个对象
divide(BigDecimal)     BigDecimal对象中的值相除,然后返回这个对象toString()             将BigDecimal对象的数值转换成字符串
doubleValue()          将BigDecimal对象中的值以双精度数返回
floatValue()           将BigDecimal对象中的值以单精度数返回
longValue()            将BigDecimal对象中的值以长整数返回
intValue()             将BigDecimal对象中的值以整数返回
/** * 四舍五入 */
@Test
public void test2() {  double num = 111231.5585;  BigDecimal b = new BigDecimal(num);  //保留2位小数  double result = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();  System.out.println(result);  //111231.56
}

BigDecimal.setScale()方法用于格式化小数点

setScale(1) 表示保留一位小数,默认用四舍五入方式
setScale(1,BigDecimal.ROUND_DOWN) 直接删除多余的小数位,如2.35会变成2.3
setScale(1,BigDecimal.ROUND_UP) 进位处理,2.35变成2.4
setScale(1,BigDecimal.ROUND_HALF_UP) 四舍五入,2.35变成2.4setScaler(1,BigDecimal.ROUND_HALF_DOWN) 四舍五入,2.35变成2.3,如果是5则向下舍setScaler(1,BigDecimal.ROUND_CEILING) 接近正无穷大的舍入setScaler(1,BigDecimal.ROUND_FLOOR) 接近负无穷大的舍入,数字>0和ROUND_UP作用一样,数字<0和ROUND_DOWN作用一样setScaler(1,BigDecimal.ROUND_HALF_EVEN) 向最接近的数字舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。

注:
1:scale指的是你小数点后的位数。比如123.456则scale就是3.
scale()就是BigDecimal类中的方法啊。
比如:BigDecimal b = new BigDecimal(“123.456”);
b.scale(),返回的就是3.

2:roundingMode是小数的保留模式。它们都是BigDecimal中的常量字段,有很多种。
比如:BigDecimal.ROUND_HALF_UP表示的就是4舍5入。

3:pubilc BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
的意思是说:我用一个BigDecimal对象除以divisor后的结果,并且要求这个结果保留有scale个小数位,roundingMode表示的就是保留模式是什么,是四舍五入啊还是其它的,你可以自己选!

4:对于一般add、subtract、multiply方法的小数位格式化如下:

BigDecimal mData = new BigDecimal("9.655").setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("mData=" + mData);
// 结果: mData=9.66

二:BigDecimal常用的方式及拓展(日常避坑及高效代码)

  • 【API详情】

  • 保留两位小数
  • /** * 保留两位小数 */
    @org.junit.Test
    public void formatTest() {  double num=13.154215;  //方式一  DecimalFormat df1 = new DecimalFormat("0.00");  String str = df1.format(num);  System.out.println(str);  //13.15  //方式二  // #.00 表示两位小数 #.0000四位小数  DecimalFormat df2 =new DecimalFormat("#.00");  String str2 =df2.format(num);  System.out.println(str2);  //13.15  //方式三  //%.2f %. 表示 小数点前任意位数   2 表示两位小数 格式后的结果为f 表示浮点型  String result = String.format("%.2f", num);  System.out.println(result);  //13.15
    }
    
  • 四舍五入
  • 1.格式化

由于NumberFormat类的format()方法可以使用BigDecimal对象作为其参数,可以利用BigDecimal对超出16位有效数字的货币值,百分值,以及一般数值进行格式化控制。

/** * 格式化 */
@Test
public void test3() {  NumberFormat currency = NumberFormat.getCurrencyInstance(); //建立货币格式化引用  NumberFormat percent = NumberFormat.getPercentInstance();  //建立百分比格式化引用  percent.setMaximumFractionDigits(3); //百分比小数点最多3位  BigDecimal loanAmount = new BigDecimal("150.48"); //贷款金额  BigDecimal interestRate = new BigDecimal("0.008"); //利率  BigDecimal interest = loanAmount.multiply(interestRate); //相乘  System.out.println("贷款金额:\t" + currency.format(loanAmount)); //贷款金额: ¥150.48  System.out.println("利率:\t" + percent.format(interestRate));  //利率: 0.8%  System.out.println("利息:\t" + currency.format(interest)); //利息: ¥1.20
}
@Test
public void test3() {  DecimalFormat df = new DecimalFormat();  double data = 1234.56789; //格式化之前的数字  //1、定义要显示的数字的格式(这种方式会四舍五入)  String style = "0.0";  df.applyPattern(style);  System.out.println("1-->" + df.format(data));  //1234.6  //2、在格式后添加诸如单位等字符  style = "00000.000 kg";  df.applyPattern(style);  System.out.println("2-->" + df.format(data));  //01234.568 kg  //3、 模式中的"#"表示如果该位存在字符,则显示字符,如果不存在,则不显示。  style = "##000.000 kg";  df.applyPattern(style);  System.out.println("3-->" + df.format(data));  //1234.568 kg  //4、 模式中的"-"表示输出为负数,要放在最前面  style = "-000.000";  df.applyPattern(style);  System.out.println("4-->" + df.format(data)); //-1234.568  //5、 模式中的","在数字中添加逗号,方便读数字  style = "-0,000.0#";  df.applyPattern(style);  System.out.println("5-->" + df.format(data));  //5-->-1,234.57  //6、模式中的"E"表示输出为指数,"E"之前的字符串是底数的格式,  // "E"之后的是字符串是指数的格式  style = "0.00E000";  df.applyPattern(style);  System.out.println("6-->" + df.format(data));  //6-->1.23E003  //7、 模式中的"%"表示乘以100并显示为百分数,要放在最后。  style = "0.00%";  df.applyPattern(style);  System.out.println("7-->" + df.format(data));  //7-->123456.79%  //8、 模式中的"\u2030"表示乘以1000并显示为千分数,要放在最后。  style = "0.00\u2030";  //在构造函数中设置数字格式  DecimalFormat df1 = new DecimalFormat(style);  //df.applyPattern(style);  System.out.println("8-->" + df1.format(data));  //8-->1234567.89‰
}  
  • 2.BigDecimal比较
  • BigDecimal是通过使用compareTo(BigDecimal)来比较的,具体比较情况如下:

    /** * 注意不能使用equals方法来比较大小。 * * 使用BigDecimal的坏处是性能比double和float差,在处理庞大,复杂的运算时尤为明显,因根据实际需求决定使用哪种类型。 */
    @Test
    public void test4() {  BigDecimal a = new BigDecimal("1");  BigDecimal b = new BigDecimal("2");  BigDecimal c = new BigDecimal("1");  int result1 = a.compareTo(b);  int result2 = a.compareTo(c);  int result3 = b.compareTo(a);  System.out.println(result1);  //-1  System.out.println(result2);  //0  System.out.println(result3);  //1
    }
    
  • 科学计数法
  • 有些项目可能会涉及到从Excel导入数据,但如果Excel里单元格类型为数值,但内容数据太长时(如银行账号),导入时,会默认读取为科学计数法,用以下代码便轻松解决。

    @Test
    public void test5() {  BigDecimal bd = new BigDecimal("3.40256010353E11");  String result = bd.toPlainString();  System.out.println(result);  //340256010353
    }
    
  • 科学计数法
  • 有些项目可能会涉及到从Excel导入数据,但如果Excel里单元格类型为数值,但内容数据太长时(如银行账号),导入时,会默认读取为科学计数法,用以下代码便轻松解决。

    @Test
    public void test5() {  BigDecimal bd = new BigDecimal("3.40256010353E11");  String result = bd.toPlainString();  System.out.println(result);  //340256010353
    }
    
@Test
public void test1() {  java.util.StringTokenizer st = new StringTokenizer( "123,456,789", ",");  StringBuffer sb = new StringBuffer();  while(st.hasMoreTokens())   {  sb.append(st.nextToken());  }  System.out.println(sb);  //123456789
}  @Test
public void test2() {  String str = "123,456,789";  str = str.replace(",", "");  System.out.println(str);  //123456789
}
  • java中价格的数字中间有逗号的处理
double value1=1.00;
String value2 = "1.00";
BigDecimal b1 = new BigDecimal(Double.valueOf(value1));
BigDecimal b1 = new BigDecimal(String.valueOf(value2));  public BigDecimal add(BigDecimal value);        //加法  public BigDecimal subtract(BigDecimal value);   //减法   public BigDecimal multiply(BigDecimal value);   //乘法  public BigDecimal divide(BigDecimal value);     //除法
  • 精确计算

【工具类】
提供加,减,乘,除运算

public class Arith {  /** * 提供精确加法计算的add方法 * @param value1 被加数 * @param value2 加数 * @return 两个参数的和 */  public static double add(double value1,double value2){  BigDecimal b1 = new BigDecimal(Double.valueOf(value1));  BigDecimal b2 = new BigDecimal(Double.valueOf(value2));  return b1.add(b2).doubleValue();  }  /** * 提供精确减法运算的sub方法 * @param value1 被减数 * @param value2 减数 * @return 两个参数的差 */  public static double sub(double value1,double value2){  BigDecimal b1 = new BigDecimal(Double.valueOf(value1));  BigDecimal b2 = new BigDecimal(Double.valueOf(value2));  return b1.subtract(b2).doubleValue();  }  /** * 提供精确乘法运算的mul方法 * @param value1 被乘数 * @param value2 乘数 * @return 两个参数的积 */  public static double mul(double value1,double value2){  BigDecimal b1 = new BigDecimal(Double.valueOf(value1));  BigDecimal b2 = new BigDecimal(Double.valueOf(value2));  return b1.multiply(b2).doubleValue();  }  /** * 提供精确的除法运算方法div * @param value1 被除数 * @param value2 除数 * @param scale 精确范围 * @return 两个参数的商 * @throws IllegalAccessException */  public static double div(double value1,double value2,int scale) throws IllegalAccessException{  //如果精确范围小于0,抛出异常信息  if(scale<0){           throw new IllegalAccessException("精确度不能小于0");  }  BigDecimal b1 = new BigDecimal(Double.valueOf(value1));  BigDecimal b2 = new BigDecimal(Double.valueOf(value2));  return b1.divide(b2, scale).doubleValue();      }
}  

BigDecimal类有3个toString方:toEngineeringString、toPlainString和toString,

toEngineeringString:有必要时使用工程计数法。工程记数法是一种工程计算中经常使用的记录数字的方法,与科学技术法类似,但要求10的幂必须是3的倍数

toPlainString:不使用任何指数

toString:有必要时使用科学计数法

 不使用指数 科学记数法 工程记数法
2700 2.7 × 10³ 2.7 × 10³
27000 2.7 × 10⁴ 27 × 10³
270000 2.7 × 10⁵ 270 × 10³
2700000 2.7 × 10⁶ 2.7 × 10⁶

BIgDecimal的用法,及与各类数据类型的转换相关推荐

  1. bigdecimal 等于0_好程序员Java培训分享BigDecimal的用法

    好程序员Java培训分享BigDecimal的用法,如果对数值结果精度要求很高,那么就可以使用BigDecimal,BigDecimal可以精准的控制小数点后面的数字 Java培训 1. 实例 Big ...

  2. Java输出、变量、数据类型及其转换

    20190701(输出.变量.数据类型及其转换) 标签: java #输出命令 System.out.println("徐凤年"+"两袖青蛇"+"剑开 ...

  3. Gox语言中的基本数据类型及其转换-GX5.1

    Gox语言默认选用Qlang语法引擎,Qlang脚本语言又是基于Go语言(Golang)做了一定的改进,数据类型基本继承自Go语言,数据的赋值等操作也基本类似但略加改进和变化.一个主要的不同是,Gox ...

  4. java赋值运算的类型转换出新的问题_学习Java基本数据类型与转换++,--等问题总结...

    java中的数据类型java有4种类型分别是整数类型.浮点类型.字符型.布尔型.java的八中分类分别是byte.short.int.long.float.double.char.boolean简称4 ...

  5. 浮点数,字符串入门,基本数据类型自动转换,JDK7新特性, 变量.

    8.1 浮点型 **√ **float**类型又被称作单精度类型,尾数可以精确到7位有效数字,在很多情况下,float类型的精度很难满足需求. √ ****double表示这种类型的数值精度是floa ...

  6. python基础-第1关数据类型与转换

    数据类型与转换(沟通语言) 数据类型 (1)字符串string 只要是被[单/双/三引号]这层皮括起来的内容,不论那个内容是中文.英文.数字甚至火星文.只要是被括起来的,就表示是字符串类型. ※字符串 ...

  7. python学习笔记1-print()函数与变量+数据类型与转换+条件判断与条件嵌套+input()函数

    print()函数与变量 1.基本句式 print('千寻') 2.引号的用法 3.转义字符 print('let\'s go') 4.变量和赋值 5.小结 数据类型与转换 字符串 整数 浮点数 数据 ...

  8. PyTorch 笔记(03)— Tensor 数据类型分类(默认数据类型、CPU tensor、GPU tensor、CPU 和 GPU 之间的转换、数据类型之间转换)

    1. Tensor 数据类型 Tensor 有不同的数据类型,如下表所示,每种类型都有 CPU 和 GPU 版本(HalfTensor)除外,默认的 tensor 是数据类型是 FloatTensor ...

  9. Php的if自动转换类型,php之数据类型自动转换,php之数据类型转换_PHP教程

    php之数据类型自动转换,php之数据类型转换 1:概述 ---php是一种弱类型的语言,它可以根据运行环境的变化而自动进行数据类型的转换 1.1转换成布尔类型的原则 以下值都将转换成布尔类型中的fa ...

最新文章

  1. java 本地 交互图_Java与UML交互图
  2. [转]Cookie/Session机制详解
  3. 如何使用网络库实现应用级消息收发
  4. sublime无法输入中文(转)
  5. gerber文件怎么导贴片坐标_利用Gerber文件生成贴片坐标及元件位置图的方法技巧...
  6. Qt实现多屏幕多分辨率自适应
  7. 记录 Duplicate spring bean id dubbo
  8. java界面ATM机取款后的余额_java_ATM机银行存取款系统的设计与实现本科毕业论文...
  9. 港中文用 Zoom 考试,中途遭黑客入侵传播不可描述内容
  10. 【渝粤教育】国家开放大学2018年春季 0047-21T计算机办公软件应用 参考试题
  11. java batik 字体文件_java使用batik转换svg文件-Go语言中文社区
  12. python交通流预测算法_对各种交通流预测模型的简要分析
  13. D3D11 加载静态3D模型(.obj格式)
  14. 数商云:补齐数字化短板,农林牧渔供应链升级执行“三步走”
  15. android系统视频剪辑app推荐,知乎10w人收藏:玩短视频必装的9款剪辑App(最全)...
  16. MFC-CListCtrl重绘,添加按钮到单元格
  17. 从系统托盘中删除Synaptics触摸板图标
  18. Table ... doesn‘t exist
  19. 解决导航栏按钮背景色切换,刷新页面,按钮背景色切换,页面和路径没有切换问题
  20. nz-modal 使用

热门文章

  1. 【苹果推??iMessage群发设置内容参数】什么是苹果推信?什么是苹果推?什么是日历推
  2. 几种经典的卷积神经网络
  3. 人工智能与智能的异同
  4. 用友t6服务器端操作系统,用友t6远程服务器
  5. 用友u8服务器无法自动启动,u8服务有的没有启动,启动服务,没有反应-用友U8...
  6. 结合断线修复方法的乡村道路提取
  7. 个人主页博客网页设计制作HTML5+CSS大作业——个人相册展示留言博客模板(6页) 简单个人网页制作
  8. 使用Python3将word文档和pdf电子书进行格式互转(兼容Windows/Linux)
  9. 【医学成像】超声成像中的分辨率
  10. 【海外APP】Twitch 全球首屈一指的游戏直播平台