Java中浮点类型的精度问题 double float
IEEE 754 标准
官方文档中的介绍
The floating-point types are float and double, which are conceptually概念 associated with the single-precision 32-bit and double-precision 64-bit format IEEE 754 values and operations as specified指定 in IEEE Standard for Binary Floating-Point Arithmetic, ANSI/IEEE Standard 754-1985 (IEEE, New York).
浮点类型是float 和double,它们是概念性概念,与单精度32位和双精度64位格式的IEEE 754的值和运算相关,这些是在这个标准中制订的:IEEE标准二进制浮点运算 ANSI / IEEE标准 754-1985(IEEE,纽约)。
The IEEE 754 standard includes not only positive and negative numbers that consist of a sign and magnitude量级, but also positive and negative zeros, positive and negative infinities, and special Not-a-Number values (hereafter今后 abbreviated缩写 NaN). A NaN value is used to represent the result of certain某些 invalid operations such as dividing zero by zero. NaN constants of both float and double type are predefined as Float.NaN and Double.NaN.
IEEE 754标准不仅包括正数和负数,它们包括符号和量级,还包括正零和负零,正负无穷大和特殊非数字值(以下简称为NaN)。NaN值用于表示某些无效操作的结果,例如将零除零。float和double类型的NaN常数预定义为Float.NaN 和Double.NaN。
Every implementation of the Java programming language is required to support two standard sets of floating-point values, called the float value set and the double value set. In addition, an implementation of the Java programming language may support either or both of two extended-exponent扩展指数 floating-point value sets, called the float-extended-exponent value set and the double-extended-exponent value set. These extended-exponent value sets may, under certain circumstances, be used instead of the standard value sets to represent the values of expressions of type float or double (§5.1.13, §15.4).
Java编程语言的每个实现都需要支持两个标准的浮点值集合,称为float value set 和 double value set。此外,Java编程语言的实现可以支持称为float扩展指数值集合和double扩展指数值集合的两个扩展指数浮点值集合中的一个或两者。在某些情况下,这些扩展指数值集可以用来代替标准值集合来表示类型float或double(§5.1.13, §15.4)表达式的值。
The finite有限的 nonzero values of any floating-point value set can all be expressed in the form s · m · 2(e - N + 1), where s is +1 or -1, m is a positive integer less than 2N, and e is an integer between Emin = -(2K-1-2) and Emax = 2K-1-1, inclusive包含, and where N and K are parameters that depend on the value set. Some values can be represented in this form in more than one way; for example, supposing that a value v in a value set might be represented in this form using certain values for s, m, and e, then if it happened that m were even and e were less than 2K-1, one could halve m and increase e by 1 to produce a second representation for the same value v. A representation in this form is called normalized if m ≥ 2N-1; otherwise the representation is said to be denormalized. If a value in a value set cannot be represented in such a way that m ≥ 2N-1, then the value is said to be adenormalized value, because it has no normalized representation.
任何浮点值集合中的【有限非零值】都可以用 s · m ·2 (e - N + 1)来表示,其中 s 是 +1 或 -1,m 是小于 2N 的正整数,E 是 [ Emin = -(2K-1-2) , Emax = 2K-1-1 ] 之间的整数,并且其中参数 N 和 K 是依赖于集合的值。一些值可以以多种方式以这种形式表示; 例如,假设值集合中的值v可以使用s,m和e的某些值以此形式表示 ,则如果发生m为偶数且e小于2 K -1,则可以将一半米和增加e 1以产生相同的值的第二表示v。在这种形式的表示被称为归一化的,如果m ≥2 N -1 ; 否则表示被称为非规范化。如果在设定的值的值不能在这样的方式来表示中号 ≥2 Ñ -1,则该值被认为是一个非标准化的值,因为它没有归一化表示。
The constraints on the parameters N and K (and on the derived parameters Emin and Emax) for the two required and two optional floating-point value sets are summarized in Table 4.1.
表4.1中总结了两个必需和两个可选浮点值集合的参数 N 和 K(以及派生参数Emin和Emax)的约束。
Table 4.1. Floating-point value set parameters
| Parameter | float | float-extended-exponent | double | double-extended-exponent |
|---|---|---|---|---|
| N | 24 | 24 | 53 | 53 |
| K | 8 | ≥ 11 | 11 | ≥ 15 |
| Emax | +127 | ≥ +1023 | +1023 | ≥ +16383 |
| Emin | -126 | ≤ -1022 | -1022 | ≤ -16382 |
浮点数的组成结构
- 符号位(S):最高位(31位)为符号位,表示整个浮点数的正负,0为正,1为负
- 指数位(E):23-30位共8位为指数位,这里指数的底数规定为2。并且指数位是以补码的形式来划分的(最高位为指数位的符号位,0为正,1为负)。另外,标准中还规定了,当指数位8位全0或全1的时候,浮点数为非正规形式,所以指数位真正范围为:-126~127。
- 尾数位(M):0-22位共23位为尾数位,表示小数部分的尾数,即形式为1.M或0.M,至于什么时候是 1 什么时候是 0,则由指数和尾数共同决定。小数部分最高有效位是1的数被称为正规(规格化)形式。小数部分最高有效位是0的数被称为非正规(非规格化)形式,其他情况是特殊值。
取值范围
S:符号位,E:指数位,M:尾数位
float:S1_E8_M23,指数位有8位,指数的取值范围为-2^7~2^7-1(即-128~127)
float的取值范围为-2^128 ~ +2^127(10^38级别的数)
double:S1_E11_M52,指数位有11位,指取的取值数范围为-2^10~2^10-1(即-1024~1023)
double的取值范围为-2^1024 ~ +2^1023(10^308级别的数)
PS:官方文档中好像说float指数的取值范围为-126~127,double指取的取值数范围为-1022~1023
精度
float:S1_E8_M23,尾数位有23位,2^23 = 83886_08,一共7位,这意味着最多能有7位有效数字,但能保证的为6位,也即float的精度为6~7位有效数字;
double:S1_E11_M52,尾数位有52位,2^52 = 45035_99627_37049_6,一共16位,同理,double的精度为15~16位有效数字。
总结
浮点数和二进制的相互转化
十进制浮点数如何用二进制表示
计算过程:将该数字乘以2,取出整数部分作为二进制表示的第1位(大于等于1为1,小于1为0);然后再将小数部分乘以2,将得到的整数部分作为二进制表示的第2位......以此类推,直到小数部分为0。
特殊情况: 小数部分出现循环,无法停止,则用有限的二进制位无法准确表示一个小数,这也是在编程语言中表示小数会出现误差的原因
0.6 * 2 = 1.2 ——————- 1
0.2 * 2 = 0.4 ——————- 0
0.4 * 2 = 0.8 ——————- 0
0.8 * 2 = 1.6 ——————- 1
0.6 * 2 = 1.2 ——————- 1
0.2 * 2 = 0.4 ——————- 0
…………
二进制浮点数如何转换为十进制
计算过程:从左到右,v[i] * 2^( - i ), i 为从左到右的index,v[i]为该位的值,直接看例子,很直接的
1 * 2^-1 + 0 * 2^-2 + 0 * 2^-3 + 1 * 2^-4 + 1 * 2^-5 + ……
= 1 * 0.5 + 0 + 0 + 1 * 1/16 + 1 * 1/32 + ……
= 0.5 + 0.0625 + 0.03125 + ……
=无限接近0.6
为何float类型的值赋给double类型的变量后可能会出现精度问题
float f = 0.6f;
double d1 = 0.6d;
double d2 = f;
System.out.println((d1 == d2) + " " + f + " " + d2);//false 0.6 0.6000000238418579
double d = 0.6;
System.out.println((float) d + " " + d);//0.6 0.6
浮点数参与运算示例代码
//注意,以下案例是刻意挑选出来的,并【不是所有】情况都会出现类似问题的
System.out.println(0.05+0.01); //0.060000000000000005
System.out.println(1.0-0.42); //0.5800000000000001
System.out.println(4.015*100); //401.49999999999994
System.out.println(123.3/100); //1.2329999999999999
double addValue = BigDecimal.valueOf(0.05).add(BigDecimal.valueOf(0.01)).doubleValue();
System.out.println("0.05+0.01=" + (0.05 + 0.01) + " " + addValue);//0.05+0.01=0.060000000000000005 0.06
double subtractValue = BigDecimal.valueOf(1.0).subtract(BigDecimal.valueOf(0.42)).doubleValue();
System.out.println("1.0-0.42=" + (1.0 - 0.42) + " " + subtractValue);//1.0-0.42=0.5800000000000001 0.58
double multiplyValue = BigDecimal.valueOf(4.015).multiply(BigDecimal.valueOf(100)).doubleValue();
System.out.println("4.015*100=" + (4.015 * 100) + " " + multiplyValue);//4.015*100=401.49999999999994 401.5
double divideValue = BigDecimal.valueOf(123.3).divide(BigDecimal.valueOf(100), 10, BigDecimal.ROUND_HALF_UP).doubleValue();
System.out.println("123.3/100=" + (123.3 / 100) + " " + divideValue);//123.3/100=1.2329999999999999 1.233
String pattern = "#,##0.00";//强制保留两位小数,整数部分每三位以逗号分隔,整数部分至少一位
DecimalFormat format = new DecimalFormat(pattern);
format.setRoundingMode(RoundingMode.HALF_UP);//默认不是四舍五入,而是HALF_EVEN
System.out.println(format.format(0.05 + 0.01)); //0.06
System.out.println(format.format(1.0 - 0.42)); //0.58
System.out.println(format.format(4.015 * 100)); // 401.50
System.out.println(format.format(123.3 / 100)); //1.23
double d = 0.06;//Java当中默认声明的小数是double类型的,其默认后缀"d"或"D"可以省略
float f = 0.06f;//如果要声明为float类型,需显示添加后缀"f"或"F"
System.out.println((0.05 + 0.01) + " " + (0.05f + 0.01f));//0.060000000000000005 0.060000002
System.out.println((d == (0.05 + 0.01)) + " " + (f == (0.05f + 0.01f)));//false false
System.out.println(d + " " + f + " " + (float) d + " " + (double) f);//0.06 0.06 0.06 0.05999999865889549
System.out.println((d == f) + " " + (d == (double) f) + " " + ((float) d == f));//false false true
//虽然向下转型后可以保证相等,但是一般不会主动干丢失精度的事的!
Java中浮点类型的精度问题 double float的更多相关文章
- java 基础 浮点类型
1.浮点类型用于表示小数的数据类型. 2.浮点数原理:也就是二进制科学计数法. 3.Java的浮点类型有float和double两种. 4.Java默认浮点类型计算的结果是double类型,字面量也是 ...
- Java 中的浮点数取精度方法
Java 中的浮点数取精度方法 一.内容 一般在Java代码中取一个double类型的浮点数的精度,四舍五入或者直接舍去等的方式,使用了4种方法,推荐使用第一种,我已经封装成工具类了. 二.代码实现 ...
- JAVA中值类型和引用类型的不同(面试常考)
转载:https://www.cnblogs.com/1ming/p/5227944.html 1. JAVA中值类型和引用类型的不同? [定义] 引用类型表示你操作的数据是同一个,也就是说当你传一个 ...
- Java中boolean类型占用多少个字节?我说一个,面试官让我回家等通知
摘自:https://www.cnblogs.com/qiaogeli/p/12004962.html 程序员乔戈里 腾讯面试官问我Java中boolean类型占用多少个字节?我说一个,面试官让我回家 ...
- java中基本类型封装对象所占内存的大小(转)
这是一个程序,java中没有现成的sizeof的实现,原因主要是java中的基本数据类型的大小都是固定的,所以看上去没有必要用sizeof这个关键字. 实现的想法是这样的:java.lang.Runt ...
- Java进阶(二十三)java中long类型转换为int类型
java中long类型转换为int类型 由int类型转换为long类型是向上转换,可以直接进行隐式转换,但由long类型转换为int类型是向下转换,可能会出现数据溢出情况: 主要以下几种转换方法,供参 ...
- Java中String类型细节
Java中String类型细节 一 . String两种初始化方式 1 . String str1= “abc”;//String类特有的创建字符对象的方式,更高效 在字符串缓冲区中检测”abc”是否 ...
- Java中String类型详解
这篇博客是我一直想总结的,这两天一直比较忙,先上传下照片吧,过后有时间再弄成正常的. 本文主要是对Java中String类型的总结,包括其在JVM中是怎么存储的...
- java中String,int,Integer,char、double类型转换
java中String,int,Integer,char.double类型转换----https://www.cnblogs.com/kangyu222/p/5866025.html
随机推荐
- [leetcode greedy]45. Jump Game II
Given an array of non-negative integers, you are initially positioned at the first index of the arra ...
- iOS Sprite Kit教程之使用帮助文档以及调试程序
iOS Sprite Kit教程之使用帮助文档以及调试程序 IOS中使用帮助文档 在编写代码的时候,可能会遇到很多的方法.如果开发者对这些方法的功能,以及参数不是很了解,就可以使用帮助文档.那么帮助文 ...
- [Luogu4724][模板]三维凸包(增量构造法)
1.向量点积同二维,x1y1+x2y2+x3y3.向量叉积是行列式形式,(y1z2-z1y2,z1x2-x1z2,x1y2-y1x2). 2.增量构造法: 1)首先定义,一个平面由三个点唯一确定.一个 ...
- NOI.AC WC模拟赛
4C(容斥) http://noi.ac/contest/56/problem/25 同时交换一行或一列对答案显然没有影响,于是将行列均从大到小排序,每次处理限制相同的一段行列(呈一个L形). 问题变 ...
- java多线程技术之条件变量
上一篇讲述了并发包下的Lock,Lock可以更好的解决线程同步问题,使之更面向对象,并且ReadWriteLock在处理同步时更强大,那么同样,线程间仅仅互斥是不够的,还需要通信,本篇的内容是基于上篇 ...
- curl多文件上传
发送: header('Content-type:text/html; charset=utf-8'); //声明编码//模拟批量POST上传文件$url = 'http://test.cm/rece ...
- Vue基础知识简介
基础知识: vue的生命周期: beforeCreate/created.beforeMount/mounted.beforeUpdate/updated.beforeDestory/destorye ...
- jQuery动画高级用法(上)——详解animation中的.queue()函数
如果你拿着一个疑问去找专业人士寻找答案,那么你的一个疑问会变成三个,因为他会用另外两个令你更加一头雾水的名词来解释你的这个疑问. 我想这是大多数,包括我在内,IT人在学习过程中碰到的最大问题.当你有一 ...
- ios项目开发(天气预报项目):使用正则获取 weather.com.cn站点信息
NSString *pattern = @"(?<=<td class=\"bigblod\">).*?(?=</td>)"; 2 ...
- 电感式DC/DC变换器工作原理
http://www.amobbs.com/thread-3293203-1-1.html 首先必须要了解电感的一些特性:电磁转换与磁储能.其它所有参数都是由这两个特性引出来的. 电感回路通电瞬间 断 ...