浮点数(double、float)的格式化问题及处理
---恢复内容开始---
平时常会面临浮点数的格式处理问题,下面就举例说一说常见的问题及处理:
1,科学计数法问题
一个浮点数123456789.10,在打印的时候变成了1.234567891E8,处理起来很简单,如:
double d = 123456789.10;
System.out.println(d);//1.234567891E8
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setGroupingUsed(false);
System.out.println(nf.format(d));//打印结果:123456789.10
使用NumberFormat的时候要setGroupingUsed(false),否则结果就会变成123,456,789.1。
再有直接转为BigDecimal更简便:
System.out.println(new BigDecimal(d));//打印结果:123456789.10
2,指定小数位的位数
指定浮点数1.010515的小数位的位数:
double d = 1.010515;
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setMaximumFractionDigits(10);
System.out.println(nf.format(d));//打印结果:1.010515
nf.setMinimumFractionDigits(10);
System.out.println(nf.format(d));//打印结果:1.0105150000
使用NumberFormat格式化的时候可以设置最大和最小的小数位数,如果要求必须有多少位,就要将最大和最小位数保持一致了。
再有,转为BigDecimal也很简单,会自动补0:
System.out.println(new BigDecimal(d).setScale(10,BigDecimal.ROUND_HALF_UP));//打印结果:1.0105150000
使用BigDecimal的时候要选择舍入模式,接下来就说说这个问题。
3,四舍五入
接着看上面的例子,对1.010515进行小数位截取,进行四舍五入:
nf.setMaximumFractionDigits(3);
System.out.println(nf.format(d));//打印结果:1.011 四舍五入
nf.setMaximumFractionDigits(5);
System.out.println(nf.format(d));//打印结果:1.01052 四舍五入
不像BigDecimal,使用NumberFormat指定小数位的时候,不需要指定舍入方式,我们看到结果已经舍入了,但是我们将d+1,然后再看一下:
d = 2.010515;
nf.setMaximumFractionDigits(3);
System.out.println(nf.format(d));//打印结果:2.011 四舍五入
nf.setMaximumFractionDigits(5);
System.out.println(nf.format(d));//打印结果:2.01051 没有四舍五入
改变d的值后再进行小数位截取,会发现有的时候会四舍五入,有的时候不四舍五入,这时候就会想到指定舍入方式,NumberFormat 有很多舍入模式:UP、DOWN、CEILING、FLOOR、HALF_UP、HALF_DOWN、HALF_EVEN、UNNECESSARY,这些模式其实和BigDecimal的模式是一样的,NumberFormat的舍入模式就是对BigDecimal的做了一下封装,并没有什么不同,比如,RoundingMode.HALF_UP就等于BigDecimal.ROUND_HALF_UP,至于这么多模式我就不再多解释了,平时使用的时候根据实际的需求选择一种模式即可,对于我们平时理解的四舍五入对应的模式就是RoundingMode.HALF_UP,我们看代码:
nf.setRoundingMode(RoundingMode.HALF_UP);
System.out.println(nf.format(d));//打印结果:2.01051 没有四舍五入
是不是觉得奇怪,为什么没有四舍五入,换BigDecimal试一下:
System.out.println(new BigDecimal(d).setScale(5,BigDecimal.ROUND_HALF_UP));//打印结果:2.01051 没有四舍五入
还是没有四舍五入,再来试试下面的代码:
System.out.println(nf.format(BigDecimal.valueOf(d)));//打印结果:2.01052 成功了
System.out.println(BigDecimal.valueOf(d).setScale(5,BigDecimal.ROUND_HALF_UP));//打印结果:2.01052 成功了
哎?怎么又都成功了!呵呵,神不神奇,其实这就是下一个问题了(丢失精度)。
4,精度丢失
还是接着上面的例子说,对2.010515进行四舍五入的时候,只有最后一次的代码正确的对其进行了四舍五入的格式处理,关键在于BigDecimal.valueOf(d),将d转为了BigDecimal,但是不是随便转的:
System.out.println(nf.format(BigDecimal.valueOf(d))); //打印结果:2.01052 成功了
System.out.println(nf.format(new BigDecimal(d))); //打印结果:2.01051 失败
System.out.println(nf.format(new BigDecimal(String.valueOf(d)))); //打印结果:2.01052 又成功了
通过上边的代码可知,为了避免精度丢失,尽量将浮点数转为BigDecimal,并且,要使用BigDecimal.valueOf()函数,如果要用new函数,就要现将浮点数转为字符串,否则同样会丢失精度。
接下来我们还是继续上边的例子,我们对d*100进行四舍五入的操作:
nf.setMaximumFractionDigits(3);//保留三位小数
nf.setRoundingMode(RoundingMode.HALF_UP);//四舍五入
System.out.println(nf.format(BigDecimal.valueOf(d*100)));//打印结果:201.051 怎么又失败了
System.out.println(nf.format(new BigDecimal(String.valueOf(d*100)));//打印结果:201.051 失败
System.out.println(BigDecimal.valueOf(d*100).setScale(3,BigDecimal.ROUND_HALF_UP));//打印结果:201.051 使用BigDecimal同样失败
按照之前说的转为BigDecimal,但是还是出现错误,原因出在2.010515*100上,直接打印一下看看:
System.out.println(d*100);//打印结果:201.05149999999998,不是2.010515
结果精度丢失了,变成了201.05149999999998,所以上面的问题不是四舍五入的模式有bug,而是精度又丢失了,就相当于对201.05149999999998保留三位,四舍五入后就变成了201.051,而不是201.052,怎么解决?还是使用BigDecimal:
System.out.println(nf.format(BigDecimal.valueOf(d).multiply(BigDecimal.valueOf(100))));//打印结果:201.052 成功
通过BigDecimal运算函数来替换运算符,可以保证精度的不丢失,所以成功了,但是并不是所有的情况我们都能转化,比如d*100是作为double参数传递到我们的函数中的,我们无法干预函数之外的行为,怎么办?
对于上面的丢失精度问题,可以先判断一下小数位数,当超多12位的时候认为丢失精度了,先进行一次保留12位小数的四舍五入,然后再进行实际位数的四舍五入(不确定该方法是否通用):
nf.setMaximumFractionDigits(12);
BigDecimal bd = new BigDecimal(nf.format(BigDecimal.valueOf(d*100)));
nf.setMaximumFractionDigits(3);
System.out.println(nf.format(bd));//打印结果:201.052 达到目的
或者使用BigDecimal:
System.out.println(BigDecimal.valueOf(d*100).setScale(12,BigDecimal.ROUND_HALF_UP).setScale(3,BigDecimal.ROUND_HALF_UP));//打印结果:201.052
5,正负号问题
两个浮点数相减,比如:0.0003-0.0005,取3位小数位:
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setMaximumFractionDigits(3);
nf.setMinimumFractionDigits(nf.getMaximumFractionDigits());
System.out.println(nf.format(0.0003-0.0005));//打印结果:-0.000
System.out.println(BigDecimal.valueOf(0.0003-0.0005).setScale(3,BigDecimal.ROUND_HALF_UP));//0.000
NumberFormat的结果是-0.000,BigDecimal方式的结果是0.000
---恢复内容结束---
浮点数(double、float)的格式化问题及处理的更多相关文章
- java中浮点数的比较(double, float)(转)
问题的提出:如果我们编译运行下面这个程序会看到什么? public static void main(String args[]){ System.out.println(0.05+0.01); Sy ...
- float:浮点型double:双精度实型decimal:数字型单精度浮点数(Single)双精度浮点数(double)
单精度浮点数(Single) 双精度浮点数(double) Decimal为SQL Server.MySql等数据库的一种数据类型,不属于浮点数类型,可以在定义时划定整数部分以及小 ...
- 什么是浮点型?什么是单精度浮点数(float)以及双精度浮点数(double)?
前言 作为一名java学习者,怎能不懂这些java基础中的基础呢?本文就带各位温顾温顾java浮点型.单精度浮点数.双精度浮点数. 浮点型 首先明确java中浮点型数据类型主要有:单精度float.双 ...
- Java 浮点数精确性探讨(IEEE754 / double / float)与 BigDecimal 解决方案
一.抛砖引玉 一个简单的示例: double a = 0.0; IntStream.range(0,3).foreach(i->a+=0.1); System.out.println(a); / ...
- Java中的浮点型(Double&Float)计算问题
在刚刚做完的一个项目中,遇到了double型计算不精确的问题.到网上查找后,问题得到解决.经验共享,在这里总结一下. Java中的浮点数类型float和double不能够进行精确运算.这个问题有时候非 ...
- iOS - Json解析精度丢失处理(NSString, Double, Float)
开发中处理处理价格金额问题, 后台经常返回float类型, 打印或转成NSString都会有精度丢失问题, 因此使用系统自带的NSDecimalNumber做处理, 能解决这问题:经过测试其实系统NS ...
- double float的精度问题
三部曲 1: #include <iostream> #include <stdio.h> #include <string.h> using namespace ...
- JavaSE基础之double数据类型的格式化
JavaSE基础之double数据类型的格式化 1.double 数据类型的格式化工具类:DoubleFormatUtil.java package cn.com.zfc.util; import j ...
- mysql基础之double,float长度标度定义
MySQL类型float double decimal的区别 float数值类型用于表示单精度浮点数值,而double数值类型用于表示双精度浮点数值,float和double都是浮点型,而decima ...
- impala支持的数据库里的double(float)类型,通过迁移inceptor后,类型的值都变成了null
impala支持的数据库里的double(float)类型,通过迁移inceptor后,double类型的值都变成了null. 通过查阅日志发现默认将double转换成Decimal(38,10)然而 ...
随机推荐
- Qt OpenGL 鼠标拾取实现
在之前的文章中讲到了OpenGL鼠标拾取操作的例子,工作中需要在Qt中实现,下面的程序演示了QT中opengl的拾取例子. 本例子在Qt5.12和Qt Creator4.8.0上测试,使用的是QOpe ...
- 在windows上搭建SSH服务踩过的坑
前两天安装了windows操作系统,想在windows上做内网穿透,所以就想在windows下启用ssh服务,今天就来讲一下我在搭建ssh服务中遇到的坑. 我显示在Mac下搭建了ssh服务,并且测试通 ...
- 零拷贝sendfile解析
传统方式read/write send/recv 在传统的文件传输里面(read/write方式),在实现上事实上是比較复杂的,须要经过多次上下文的切换.我们看一下例如以下两行代码: 1. read( ...
- exception ‘PHPExcel_Calculation_Exception‘ with message ‘粉丝数据!C2679 -> Formula Error: Operator ‘=‘ has no operands
导致问题原因可能是导出字段中包含有 ‘=’ ,解决办法:在字段前拼上一个半单引号. if(strpos($lists[$i-2][‘nickname‘],‘=‘) === 0){ $lists[$ ...
- JBPM工作流(五)——执行流程实例
概念: ProcessInstance,流程实例:代表流程定义的一次执行.如:张三昨天按请假流程请了一次假.一个流程实例包括了所有运行阶段,其中最典型的属性就是跟踪当前节点的指针,如下图. Execu ...
- 使用call、apply和bind解决js中烦人的this,事件绑定时的this和传参问题
1.什么是this 在JavaScript中this可以是全局对象.当前对象或者任意对象,这完全取决于函数的调用方式,this 绑定的对象即函数执行的上下文环境(context). 为了帮助理解,让我 ...
- MUI学习01-顶部导航栏
建议:先看一下MUI注意事项 连接:http://ask.dcloud.net.cn/article/122 固定栏靠前 所谓的固定栏,也就是带有.mui-bar属性的节点,都是基于fixed定位的元 ...
- 2018今日头条杯 E-Jump a Jump
Problem E. Jump A JumpInput file: standard inputOutput file: standard outputTime limit: 1 secondsMemor ...
- 浅谈Vue 项目性能优化 经验
我优化公司的项目总结的几点: 1.先查看引入的图片大小,如果太大了,可以压缩,压缩路径:https://zhitu.isux.us/ 2.代码包优化, 待下项目开发完成.进行打包源码上线环节,需要对项 ...
- torch.nn.Embedding
自然语言中的常用的构建词向量方法,将id化后的语料库,映射到低维稠密的向量空间中,pytorch 中的使用如下: import torch import torch.utils.data as Dat ...