文档章节

Java中的浮点数-科学计数法-加减乘除

FansUnion
 FansUnion
发布于 2015/05/03 01:29
字数 706
阅读 39
收藏 0
  上次,提到“元转分”这个浮点数问题,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);
}
}

© 著作权归作者所有

FansUnion
粉丝 60
博文 858
码字总数 825464
作品 0
丰台
高级程序员
私信 提问
java 如何实现普通计数法转化为科学计数法?

在Java中如何实现指定有效位数之后将 普通计数法表示的浮点数转化为科学计数法表示的浮点数,比如将 0.0002345保留三位有效数字并采用科学计数法表示为 2.34-E4 ?

JackLeeMing
2016/05/05
2.6K
4
Java Double相加出现的怪事

问题的提出: 编译运行下面这个程序会看到什么 [java] view plaincopy public class test { public static void main(String args[]) { System.out.println(0.05 + 0.01); System.out.print......

onedotdot
2017/11/05
0
0
BigDecimal的精确计算及工具类

输出: BigDecimal是处理高精度的浮点数运算的常用的一个类 当需要将BigDecimal中保存的浮点数值打印出来,特别是在页面上显示的时候,就有可能遇到预想之外的科学技术法表示的问题。 一般直...

独钓渔
2018/02/05
2
0
Java中浮点型数据Float和Double进行精确计算的问题

一、浮点计算中发生精度丢失 大概很多有编程经验的朋友都对这个问题不陌生了:无论你使用的是什么编程语言,在使用浮点型数据进行精确计算时,你都有可能遇到计算结果出错的情况。来看下面的...

Junn
2013/06/10
0
1
java poi导入excel日期处理

java导入execl常见问题 一,导入的日期为一串数字 如“320422192610161818” 1, 在java导出excel时获取到的日期或其他列是一串数字,并且不管怎么更改都为数字则可以判断为模板有问题 解决办...

菜鸟来了
2015/04/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

以太坊私有链搭建

https://blog.csdn.net/Blockchain_lemon/article/details/80589123

Moks角木
30分钟前
1
0
自律给我自信-为什么要自律

为什么要自律 混一天和努力一天 看不到任何差别 3天看不到任何变化 7天也看不到任何效果 但是 1个月后, 会看到话题不同 3个月后, 会看到气场不同 6个月后, 会看到距离不同 3年后, 会看到...

周大壮
30分钟前
1
0
读书replay计划说明

突然脑袋一闪,我有了这样一个主意:通过写博客的方式,将我阅读的书中的内容replay出来。 我一般会找着我感兴趣的书去读,一般也会读书中我感兴趣的章节,或者当下对我有用的章节,所以这个...

wanxiangming
32分钟前
0
0
CentOS7安装xrdp环境可实现远程桌面访问

CentOS7安装xrdp环境可实现远程桌面访问 2018-07-14 06:39:28 分类:运维 阅读(2051) 评论(0) 在"Ubuntu系统安装xrdp桌面客户端及实现远程连接桌面"文章中有分享过在Ubuntu系统中安装XRDP环境...

linjin200
57分钟前
4
0
ConfigurationProperties

package cn.enjoy.config; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @ConfigurationProperties(pr......

少年已不再年少
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部