不要在精确计算中使用float和double类型
http://blog.csdn.net/androiddevelop/article/details/8478879
一 问题描述
float和double类型不能用于精确计算,其主要目的是为了科学计算和工程计算,它们执行二进制浮点原酸,目的是为了广泛的数值范围上提供较为精确的快速近似计算而精心设计的。但是如果设计钱币之类的计算需要很精确,所以这种情况不能使用float和double,因为要让其精确表示0.1 或者 10的任何负数次方值是不可能的。
二 眼见为实,举例证明:
- // float与double 无法精确表示0.1 或者 10的负次方
- System.out.println( 0.15 - 0.05 ); // 0.09999999999999999
- System.out.println( 2.08f - 3.7f );// -1.6200001
三 举一个现实中会遇到的情况:
一个实际的例子,口袋里面有10元钱,买0.9元的商品十个 , 收银员需要找零1元。计算如下:
- 10 - 0.9 * 10 = 1
代码实现:
- float myMoney = 10.00f;
- float price = 0.9f;
- for (int i = 0; i < 10; i++) {
- myMoney -= price;
- }
- System.out.println( myMoney ); // 1.0000002
结果竟然输出的是1.0000002而非1,可能很多人会认为这也无所谓啊,毕竟仅偏差了0.0000002,但问题是如果前提是进行了1亿笔交易呢?难道你愿意仅仅因为使用了计算机计算这些数据,而损失一部分钱吗?
四 解决办法
1. 使用int 和 long类型,如果小数点以后的值可以忽略不计可以只用这两种类型
2. 对计算结果进行四舍五入
3. 使用BigDecimal类型进行浮点运算
先来看一段代码
- int intValue = 10;
- float floatValue = 0.99999f;
- int count1 = (int) (intValue + floatValue);
- System.out.println("10 + 0.99999 = " + count1); // output 10
- int count2 = (int) (intValue - floatValue);
- System.out.println("10 - 0.99999 = " + count2); // output 9
原本按我个人的理解 10 + 0.99999 = 10.99999 然后转为int类型会进行四舍五入 值为11,而实际结果为10
更深入的分析可以查看
如何解决float和double误差问题呢?可以使用Java中提供的java.math.BigDecimal,不过此类型是不可变的,每次计算都必须新创建一个对象,不适合大量计算
再来看一个舍入误差会出现的问题
- // 10.1 + 0.99*10 = 20
- float f1 = 10.1f;
- float f2 = 0.99f;
- for (int i = 0; i < 10; i++) {
- f1 += f2;
- }
- System.out.println(f1); // 19.999998
解决办法,使用BigDecimal
- BigDecimal count = new BigDecimal("10.1");
- for (int i = 0; i < 10; i++) {
- count = count.add(new BigDecimal("1"));
- }
- System.out.println(count.intValue()); // 20
参考资料:
2. 《Effective Java》 第2版 第48条 如果需要精确的答案,请避免使用float和double
不要在精确计算中使用float和double类型的更多相关文章
- Java中的float、double计算精度问题
java中的float.double计算存在精度问题,这不仅仅在java会出现,在其他语言中也会存在,其原因是出在IEEE 754标准上. 而java对此提供了一个用于浮点型计算的类——BigDeci ...
- C#中对于float,double,decimal的误解
原文:C#中对于float,double,decimal的误解 一直很奇怪C#的预定义数据类型中为什么加了一个decimal,有float和double不就够了吗?今天来挖一挖. 浮点型 如果我们在代 ...
- Effective Java 第三版——60. 需要精确的结果时避免使用float和double类型
Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...
- C#中对于float,double,decimal的误解(转载)
浮点型 Name CTS Type Description Significant Figures Range (approximate) float System.Single 32-bit sin ...
- java中int,float,long,double取值范围,内存泄露
java中int,float,long,double取值范围是多少? 写道 public class TestOutOfBound { public static void main(String[] ...
- MySQL中的float和decimal类型有什么区别
decimal 类型可以精确地表示非常大或非常精确的小数.大至 1028(正或负)以及有效位数多达 28 位的数字可以作为 decimal类型存储而不失其精确性.该类型对于必须避免舍入错误的应用程序( ...
- 关于SQL中数据类型(float和real)和 .NET Framework 中数据类型(float和double)的问题
今天同学写程序遇到一个问题,MSSQL里的数据是 float 类型,在 .NET Framework 中用的时候也转换成 float 类型,结果报错,类型转换异常,明明是相同的类型,为什么会异常 在w ...
- hive 中的float和double
表employees中字段 taxes(税率)用类型float存储 hive> select name, salary, taxes from employees where taxes &g ...
- C语言中关于float和double的输入输出格式
1.对于double类型,输入格式为scanf("%lf %lf", &foo, &bar); 对于float类型,输入格式为scanf("%f %f, ...
随机推荐
- php递归数组中的应用
<?php $arr = array(array(1,2), array(3, 4), array(array(5, 6), array(7, 8)));function t($a){ i ...
- 2、Python djang 框架下的word Excel TXT Image 等文件的下载
2.python实现文件下载 (1)方法一.直接用a标签的href+数据库中文件地址,即可下载.缺点:word excel是直接弹框下载,对于image txt 等文件的下载方式是直接在新页面打开. ...
- Linux(Fedora)下NodeJs升级最新版本(制定版本)
Linux(Fedora)下NodeJs升级最新版本(制定版本) 首先安装n模块: npm install -g n 升级node.js到最新稳定版 n stable 升级node.js到制定版本 n ...
- 使用PHP脚本来写Daemon程序
什么是Daemon进程 这又是一个有趣的概念,daemon在英语中是"精灵"的意思,就像我们经常在迪斯尼动画里见到的那些,有些会飞,有些不会,经常围着动画片的主人公转来转去,啰 ...
- apache日志文件 accesslog
因为想要看到apache的日志记录用户请求某个页面所花的时间,需要添加额外参数才会记录,所以临时查了下哦..记下来了 在httpd.conf里可以看到一行这样的配置 LogFormat "% ...
- Android Binder机制简单了解
Binder -- 一种进程间通信(IPC)机制, 基于OpenBinder来实现 毫无疑问, 老罗的文章是不得不看的 Android进程间通信(IPC)机制Binder简要介绍和学习计划 浅谈Ser ...
- Spring 初学 1
Spring是一个轻量级的框架,他有自己的MVC框架SpringMVC,在以往的Web项目中大多采用Structs2+hibernate+Spring的框架,Structs做web层,Hibernat ...
- SQL语句の循环添加数据
declare @i intset @i=1while @i<=1000begininsert into News_ITM(title,msg,subDateTime,author,imageP ...
- Laravel之路——缓存使用
1.使用Redis类 use Illuminate\Support\Facades\Redis; //设置指定 key 的值(覆盖老的value) Redis::setex('key','value' ...
- C++11的新特性lambda的小试牛刀RAII
C/C++的资源是手动管理的 这导致程序员在申请资源时,最后用完了偶尔会忘记回收 C++语言的发明者倡导RAII,资源获取即初始化 使用对象来管理资源的生命周期,在超出作用域时,析构函数自动释放资源 ...