上次,提到“元转分”这个浮点数问题,boss倾向于手动把1.23元这种格式,转换成123分。
  
  但实际上,浮点数很容易遇到精度问题。
  
  比如,System.out.println(4.015 * 1000);结果就不会是4015。
  
  以前,总结的元转分的问题,没能考虑到所有的场景,今天补充点上次遗漏的。
  
  -5.09,如果金额是负数,应该是-500-9=-509,而不是-500+9=-441,这是上次的一个超级bug。
  
  另外,需要还有一个超级bug,“1045189788”转换成double类型的元时,结果变成了1.04。
  
  debug了好久,才发现以前代码的漏洞。
  
  1045189788这种比较大的浮点数,在传递过程中,是“科学计数法”表示的,类似“1.04E”,
  所以,最后转换出了问题。
  
  其实,我一直不建议boss采用这种人工截取计算的方式,需要考虑的场景太复杂,建议使用JDK内置的BigDecimal。
  
  经过实践,发现很不错。
  
  可以用double、string等多种原始类型,构造BigDecimal,再进行四则运算。
  
  使用BigDecimal的关键是,控制“标度”即“精度”,scale。
  
  算术运算结果的首选标度  运算 结果的首选标度 
加 max(addend.scale(), augend.scale()) 
减 max(minuend.scale(), subtrahend.scale()) 
乘 multiplier.scale() + multiplicand.scale() 
除 dividend.scale() - divisor.scale()

下面这个工具类,是从网上copy的,还是非常有价值的。
  
  import java.math.BigDecimal;

/**
 * 消除加减乘除的精度,解决Float与Double类型进度不准确的问题.
 */
public class DoubleUtil {
/**
* 加法运算

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

/**
* 除法运算

* @param v1
*            被除数
* @param v2
*            除数
* @return 商
*/
public static double div(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.divide(b2).doubleValue();
}

/**
* 除法运算

* @param v1
*            被除数
* @param v2
*            除数
* @return 商和余数
*/
public static BigDecimal[] divideAndRemainder(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
BigDecimal[] arr = b1.divideAndRemainder(b2);
return arr;
}

/**
* 求商(向下舍入)

* @param v1
* @param v2
* @return
*/
public static BigDecimal divideToIntegralValue(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
System.out.println("------------");
return b1.divideToIntegralValue(b2);
}

public static void main(String[] args) {
testUnPrecision();
System.out.println("----------使用BigDecimal消除精度影响------------\n"
+ DoubleUtil.add(0.05, 0.01));
System.out.println(DoubleUtil.sub(1.0, 0.54));
System.out.println(DoubleUtil.mul(4.015, 1000));
System.out.println(DoubleUtil.div(12.3, 10));
// 得到商和余数
BigDecimal[] arr = DoubleUtil.divideAndRemainder(12.3, 10);
System.out.println("得到商和余数");
for (BigDecimal bigDecimal : arr) {
System.out.println(bigDecimal);
}
System.out.println(DoubleUtil.divideToIntegralValue(4.5, 2));
}

/**
* 不准确问题示例
*/
private static void testUnPrecision() {
System.out.println("--------Java自身的Double类型有精度损失----------");
System.out.println(0.05 + 0.01);
System.out.println(1.0 - 0.54);
System.out.println(4.015 * 1000);
System.out.println(12.3 / 100);
}
}

Java中的浮点数-科学计数法-加减乘除的更多相关文章

  1. Java中怎么把科学计数法显示出全部数字

    如果想去除科学计数法显示可以用如下方法处理: /** * 把科学计数法显示出全部数字 * @param d */ public static String object2Str(Object d) { ...

  2. 把Excel作为数据库,读到DataTable中,Excel科学计数法数字转字符串

    需要引用:using System.Data.OleDb; /// <summary> /// 获取Excel数据,包含所有sheet /// </summary> /// & ...

  3. 将Excel中读取的科学计数法表示的Double数据转换为对应的字符串

    已在SegmentFault提问,目前没有答案,自行实现如下: private static String getRealNumOfScientificNotation(String doubleSt ...

  4. Java 科学计数法

    目录 Java 科学计数法 1 科学计数法的概念 1.1 有效数字 1.2 E记号 2 Java中的科学计数法 2.1 NumberFormat 2.2 DecimalFormat 2.3 BigDe ...

  5. 数据库字段出现科学计数法e+的情况分析

    问题: 有时候,我们在将excel表格中数据导入数据库中时,对于表格中的数字会默认为float的数据类型,这个时候导入到数据库中的这个表的值是正常显示的: 然而如果你要把导入到数据库中的表,再插入到另 ...

  6. 解决从Excel导入数据库,导入到DataTable时数据类型发生变化的问题(如数字类型变成科学计数法,百分数变成小数)

    做项目的时候,C#读取Excel数据到DataTable或者DataSet,设断点查看DataTable,发现Excel的显示为较长位数数字的字段如0.000012在DataTable中显示为科学计数 ...

  7. 如何使java中double类型不以科学计数法表示

    在java中,把一个double或者BigDecimal的小数转换为字符串时,经常会用科学计数法表示,而我们一般不想使用科学计数法,可以通过:DecimalFormat a = new Decimal ...

  8. Java将Excel中科学计数法解析成数字

    需要注意的是一般的科学表达式是1.8E12 1.8E-12 而在Excel中的科学表达式是1.8E+12 1.8E-12 我写的科学计数法的正则表达式是(-?\d+\.?\d*)[Ee]{1}[\+- ...

  9. java使用poi解析或处理excel的时候,如何防止数字变成科学计数法的形式和其他常见Excel中数据转换问题

    当使用POI处理excel的时候,遇到了比较长的数字,虽然excel里面设置该单元格是文本类型的,但是POI的cell的类型就会变成数字类型. 而且无论数字是否小数,使用cell.getNumberi ...

随机推荐

  1. Eclipse如何从导入SVN上导入项目

    1.右键单击,选择 Import,进入导入项目窗口 2.点击选择从SVN检出项目,点击Next下一步 3.选择创建新的资源库位置,点击Next,如果项目之前已经导入过删除掉了,重新导入的时候,只需勾选 ...

  2. 本文介绍C# BitmapData

    本文介绍C# BitmapData,对于C# BitmapData,虽然BitmapData.Width还是等于Bitmap.Width,但大概是出于显示性能的考虑.   最近要转开发平台,正研究C# ...

  3. 标准模板库 STL 使用之 —— vector 使用 tricks

    1. 从已有 vector(或数组)中复制 vector<int> a{....}; int an = a.size(); int half = an/2; vector<int&g ...

  4. ajax+客户端与服务器端的交互

    一. AJAX 原生JS var xhr=new XMLHttpRequest(); xhr.open("GET","[请求地址]",false); xhr.o ...

  5. 微信小程序常见的UI框架/组件库总结

    想要开发出一套高质量的小程序,运用框架,组件库是省时省力省心必不可少一部分,随着小程序日渐火爆,各种不同类型的小程序也渐渐更新,其中不乏一些优秀好用的框架/组件库. 1:WeUI 小程序–使用教程 h ...

  6. chmod用数字来表示权限的方法

    前提:  mode权限设定字串.格式:[ugoa...][[+-=][rwxX]...][,...] 当中u表示拥有者(user).g表示与拥有者属于同一个群体(group),o表示其它以外的人(ot ...

  7. 【LCS】POJ1458Common Subsequence

    题目链接:http://poj.org/problem?id=1458 这是一道最长公共子序列的模板题: #include<iostream> #include<string> ...

  8. Apache的.htaccess项目根文件夹伪静态设置规则

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/ ...

  9. php对xml进行简单的增删改查(CRUD)操作

    假如有以下xml文件: <?xml version="1.0" encoding="UTF-8"? > <setting>     &l ...

  10. Textillate.js有什么用及使用实例

    Textillate.js有什么用及使用实例 一.总结 一句话总结:Textillate.js – 实现动感的 CSS3 文本动画的简单插件 二.textillate.js 文字动画 textilla ...