上次,提到“元转分”这个浮点数问题,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. Hi35xx NVR GDB调试

    Hi35xx NVR GDB调试   1. 下载gdb源代码 嵌入式Linux 的GDB 调试环境由Host 和Target 两部分组成,Host 端使用arm-linuxgdb,Target Boa ...

  2. eclipse- log 打印跟输出到文件

    1.在eclipse中打印log,经常使用的就是log.e(string,string) 代码中如下 @Override public boolean onTouchEvent(MotionEvent ...

  3. dot 语法全介绍

    0. 保存 保存为 pdf:dot -Tpdf iris.dot -o iris.pdf 1. 基本 (1)无向图.有向图.子图 graph G {} // 无向图 digraph G {} // 有 ...

  4. UART和RS232/RS485的关系,RS232与RS485编程

    http://wpp9977777.blog.163.com/blog/static/4625100720138495943540/ 串口通讯是电子工程师和嵌入式开发工程师面对的最基本问题,RS232 ...

  5. .v 和 .sdf

    DC输出的.v(网表?)和.sdf(储存的是延时的信息) 用于后仿真

  6. Java Web学习总结(3)——Servlet详解

    一.ServletConfig讲解 1.1.配置Servlet初始化参数 在Servlet的配置文件web.xml中,可以使用一个或多个<init-param>标签为servlet配置一些 ...

  7. 开发过程使用Tomcat Maven插件持续快捷部署Web项目

    我在平时工作中部署Web项目到测试服务器上的Tomcat时用的是Hudson.Hudson本身已经跟SVN.Git.Maven集成并且支持添加各种插件.但如果使用Hudson,我需要配置两个任务:一个 ...

  8. [Spark源代码剖析] DAGScheduler划分stage

    转载请标明出处:http://blog.csdn.net/bigbigdata/article/details/47293263 本文基于Spark 1.3.1 先上一些stage相关的知识点: DA ...

  9. shell基础之符号与语法

            shell脚本如今已经成为了一种非常普遍的脚本语言,之所以如此广泛的被应用,毋庸置疑它是有它的独到之处的.shell脚本语言和其它的语言比方说c/c++有何不同呢?c/c++等语言属于 ...

  10. 深入理解线程本地变量ThreadLocal

    ThreadLocal理解: 假设在多线程并发环境中.一个可变对象涉及到共享与竞争,那么该可变对象就一定会涉及到线程间同步操作,这是多线程并发问题. 否则该可变对象将作为线程私有对象,可通过Threa ...