float、double的精度、范围,在内存中的存储方式
float、double的精度,在内存中的存储方式
一、浮点型变量在内存中的存储方式
Java的浮点数遵循IEEE 754标准,采用二进制数据的科学计数法来表示浮点数,float遵从的是IEEE R32.24 ,而double 遵从的是R64.53。该标准中表示的浮点数表示分为规约形式和非规约形式以及特殊情况。
无论是单精度还是双精度在存储中都分为三个部分:
- 符号位(Sign) : 0代表正,1代表为负
- 指数位(Exponent):用于存储科学计数法中的指数数据,并且采用移位存储
- 尾数部分(Mantissa):尾数部分
根据IEEE 754 标准,对于float单精度,第 31 位(左边第1位)表示浮点数字的符号;第 30-23位(8位)表示指数(指数加完偏移量,即加偏移量127后的值);第 22-0 位是尾数(尾数是23位);存储方式如下图所示:

指数是有符号的,但并不是使用有符号整形(int)的存储方式,而是使用偏移(Offset)算法,存储的数据=元数据 + 127,所以【实际指数值 = 指数部分二进制值 - 127】。8位二进制能表示的范围为0~255,这样的话范围就是(-127~128),另外全0和全1作为特殊处理,所以指数部分能表示的范围为-126~127(规约形式)。可以参考https://www.zhihu.com/question/21711083
根据IEEE 754 标准,对于double双精度,第 63 位表示浮点数字的符号;第 62-52 位(11位)表示指数(指数加完偏移量);第 51-0 位是尾数(尾数是52位,尾数位比float多,尾数位越多,精度越高);双精度的存储方式为:

指数部分与float单精度存储方式一样使用偏移(Offset)算法,存储的数据=元数据 + 1023,所以【实际指数值 = 指数部分二进制值 - 1023】。11位二进制能表示的范围为0~2047,所以指数部分能表示的范围为-1022~1023。
|
非规约形式表示: 当指数部分全0而且小数部分不全0时表示的是非规格化的浮点数,因为这里默认没有前导1,而是0。 对于float类型,取值位0.f * 2-126,表示范围位 2-149~(1-2-23) × 2-126 这里没有考虑符号。(IEEE 754标准规定:非规约形式的浮点数的指数偏移值比规约形式的浮点数的指数偏移值小1。) |
|
其他特殊表示: 1.当指数部分和小数部分全为0时,表示0值,有+0和-0之分(符号位决定),0x00000000表示正0,0x80000000表示负0. 2.指数部分全1,小数部分全0时,表示无穷大,有正无穷和负无穷,0x7f800000表示正无穷,0xff800000表示负无穷. 3.指数部分全1,小数部分不全0时,表示NaN,分为QNaN和SNaN,Java中都是NaN. |
二、二进制的科学计数法
十进制的科学计数法:任何数字都可以表示成a×10n,其中1≤a<10,n表示整数,一般用于表示很大的数字,例如:623500000000可以表示为6.235×1011。同理,任何二进制都可以表示成a×2n,其中a为带小数点的二进制序列,且小数点在第二位,n表示整数,例如:100111101100000000000000可以表示为1.001111011×223。
三、十进制转换为二进制
1.整数部分
余数法:用这个十进制的整数除以 2,会得到一个商值和一个余数值,再用商除以 2,一直除到商为 0 为止,把每次的余数,逆序连起来,就是要转的二进制数。整数总能用二进制准确表示。
2.小数部分
小数部分就是用十进制小数乘以2,得出的积,然后把积的整数位取出,再用积的小数部分乘以2,再把积的整数位取出,再用小数部分乘以2,循环操作,直到小数部分为0,或者遇到无限循环(小数转换为二进制可能会损失精度),取到你认为足够精度的小数为止,然后把取出的整数位顺序连接起来,就是要转换成的二进制小数。
|
十进制 |
二进制 |
|
0.5 |
0.1 |
|
0.25 |
0.01 |
|
0.125 |
0.001 |
|
0.0625 |
0.0001 |
|
0.03125 |
0.00001 |
|
0.015625 |
0.000001 |
|
0.0078125 |
0.0000001 |
|
0.00390625 |
0.00000001 |
十进制 0.875 转换成二进制 0.111,十进制0.3转换成二进制0.01001100110011…。
四、二进制转换为十进制
float与double的二进制表示转换为十进制时,先表示为科学计数法,再分别转换小数部分和整数部分。
0 01111111 00000000000000000000000的指数部分为01111111=(27-1)-127 = 0,尾数部分为00000000000000000000000,(因整数部分总为1,所以存储时省略整数部分)该数的科学计数法表示为1. 00000000000000000000000×20,所以该二进制对应的十进制为1。
1 10000000 00000000000000000000000的指数部分为10000000 = 27-127 = 1,尾数部分为00000000000000000000000,该数的科学计数法表示为1.00000000000000000000000×21,左移1位变为10.0000000000000000000000,所以该二进制对应的十进制为2。
0 01111101 00110011001100110011001的指数部分为01111101 = 125 – 127 = -2,尾数部分为00110011001100110011100,该数的科学计数法表示为1.00110011001100110011100×2-2,右移2位变为0.0100110011001100110011001,整数部分为0,小数部分约为0.3,该数为0.3。
0 10000000 10010010000111111011011的指数部分为10000000 = 27 – 127 = 1,尾数部分为10010010000111111011011,该数的科学计数法表示为1.10010010000111111011011×21,左移1位变为11.0010010000111111011011,整数部分为3,小数部分约为0. 1415926,该数为3.1415926。
五、float、double的精度
数学领域中的精度一般指有效数字,是十进制位数, 而计算机中的精度通常是指二进制位数。
从上述几个float的二进制表示转换为十进制的示例可以看出:
- 指数位决定了范围大小,因为指数位表示的越大则表示的数值越大。
- 尾数位决定了计算精度,因为尾数位能表示的越大,则计算精度越大。
浮点数的精度决定于尾数部分,而float尾数占了23个二进制位,加上省略的整数部分的1,共24位决定浮点数的精度。24位二进制表示的最大数字为224转化为十进制数为 16,777,216(8个十进制位),因此有一种说法是float的十进制精度为8位,但是由于其并不能表示所有8位十进制数,因此也有种说法是其精度为7位。【这些说法都不准确,因为尾数部分包含整数部分和小数部分】准确的说,float可以保证7位十进制有效数字。
float能表示的最大数为0 11111110 11111111111111111111111,也是Float.MAX_VALUE的值,(224-1)× 2(127-23)约为3.4028235E38。
float能表示最小正数为1 00000000 00000000000000000000001(非规约表示),也是Float.MIN_VALUE的值,2-149约为1.4E-45
double位数占52位,加上省略的整数部分的1,共53位决定浮点数的精度。53位二进制表示的最大数字为253转化为十进制数为 9,007,199,254,740,992(16个十进制位),但是它不能表示所有16位十进制数,其精度介于15~16位。准确的说,double可以保证15位十进制有效数字。
Double表示的最大数为1.7976931348623157E308,最小正数为4.9E-324
六、浮点转二进制科学表示的代码实现
1 import java.util.Scanner;
2 import java.util.regex.*;
3 public class FloatToHex {
4 /**
5 *将用户输入的浮点数,转换为二进制科学计数形式(浮点数在内存中的存储方式)
6 *@author: 李世颖
7 *@Create Date: 2020-01-10
8 */
9 public static void main(String[] args) {
10 // 键盘输入
11 Scanner sc = new Scanner(System.in);
12 String cmd=null;
13 float f = 0;
14 //double d = 0;
15 String binaryStr = "";
16 int prefixLen = 0;//需要补0位的数量
17 //float类型正则表达式规则
18 Pattern p = Pattern.compile("-?\\d+\\.?\\d*");
19 Matcher m = null;
20 //提示输入
21 System.out.println("输入浮点数,转换输出该浮点数的内存二进制表示形式。");
22 while (sc.hasNext()) {
23 //获取输入并删除分隔符
24 cmd = sc.nextLine();
25 //退出命令
26 if (cmd.equalsIgnoreCase("exit")) {
27 sc.close();
28 return;
29 }
30 //判断输入是否合法
31 m = p.matcher(cmd);
32 if (m.matches()) {
33 try {
34 f = Float.parseFloat(cmd);
35 //d = Double.parseDouble(cmd);
36 System.out.println(cmd + "在内存中的二进制表示如下:");
37 binaryStr = Integer.toBinaryString(Float.floatToIntBits(f));//将float转换为二进制字符串
38 //binaryStr = Long.toBinaryString(Double.doubleToLongBits(d));
39 prefixLen = 32 - binaryStr.length();
40 //prefixLen = 64 - binaryStr.length();
41 if(prefixLen > 0){
42 System.out.println(String.format("%0"+prefixLen+"d",0) + binaryStr);//补0后输出
43 }else{
44 System.out.println(binaryStr);
45 }
46 } catch (Exception e) {
47 System.out.println("输入的浮点数不合法或超出浮点数的范围");
48 continue;
49 }
50 } else {
51 System.out.println("请输入合法的浮点数");
52 }
53 }
54 }
55 }
float、double的精度、范围,在内存中的存储方式的更多相关文章
- Float在内存中的存储方式及IEC61131处理
Float在内存中的存储方式及IEC61131处理 1,fp32(32bits float)类型数据在存储器中占用4Bytes存储,且遵循IEEE-754标准: 一个浮点数分三部分组成: 符号位s(1 ...
- <转载>浅谈C/C++的浮点数在内存中的存储方式
C/C++浮点数在内存中的存储方式 任何数据在内存中都是以二进制的形式存储的,例如一个short型数据1156,其二进制表示形式为00000100 10000100.则在Intel CPU架构的系统中 ...
- C语言中浮点数在内存中的存储方式
关于多字节数据类型在内存中的存储问题 //////////////////////////////////////////////////////////////// int ,short 各自是4. ...
- QList介绍(QList比QVector更快,这是由它们在内存中的存储方式决定的。QStringList是在QList的基础上针对字符串提供额外的函数。at()操作比操作符[]更快,因为它不需要深度复制)非常实用
FROM:http://apps.hi.baidu.com/share/detail/33517814 今天做项目时,需要用到QList来存储一组点.为此,我对QList类的说明进行了如下翻译. QL ...
- 数据在内存中的存储方式( Big Endian和Little Endian的区别 )(x86系列则采用little endian方式存储数据)
https://www.cnblogs.com/renyuan/archive/2013/05/26/3099766.html 1.故事的起源 “endian”这个词出自<格列佛游记>.小 ...
- float和double在内存中的存储方式
本文转载于:http://wenku.baidu.com/link?url=ARfMiXVHCwCZJcqfA1gfeVkMOj9RkLlR9fIexbgs9gDdV8rIS48A1_xe1y6YgX ...
- C语言 float、double数据在内存中的存储方式
float在内存中占4个字节(32bit),32bit=符号位(1bit)+指数位(8bit)+底数位(23bit) 指数部分 指数位占8bit,可以表示数值的范围是0-(表示0~255一共256个数 ...
- C/C++浮点数在内存中的存储方式
一.内存表示 任何数据在内存中都是以二进制的形式存储的,浮点数的表示是把一个数的有效数字和数的范围在计算机的一个存储单元中分别予以表示,数的小数点位置随比例因子的不同而在一定范围内自由浮动.如下图是3 ...
- C/C++数据在内存中的存储方式
目录 1 内存地址 2 内存空间 在学习C/C++编程语言时,免不了和内存打交道,在计算机中,我们存储有电影,文档,音乐等数据,这些数据在内存中是以什么形式存储的呢?下面做一下简单介绍. 本文是学 ...
- C++成员函数在内存中的存储方式
用类去定义对象时,系统会为每一个对象分配存储空间.如果一个类包括了数据和函数,要分别为数据和函数的代码分配存储空间.按理说,如果用同一个类定义了10个对象,那么就需要分别为10个对象的数据和函数代码分 ...
随机推荐
- 编译Assimp时出现“warning C4819”的解决方案
最近又重新捣鼓起了OpenGL, 使用Assimp库加载3D模型,最新(2023/12/9)的版本是5.3.1. 使用cmake编译本是一件简单的事情: cmake . cmake --build ...
- RabbitMQ初学
RabbitMQ 消息队列在软件中的应用场景 异步处理上(优于原先的方式) 为什么优于呢? 首先,通常情况下,如上图我们其实不用消息队列的情况下,其实也可以不用100ms,不用allof即可 那么优势 ...
- 《ASP.ENT Core 与 RESTful API 开发实战》-- (第4章)-- 读书笔记(下)
第 4 章 资源操作 4.5 创建资源 由于创建资源的 Id 会在服务端生成,因此在创建资源时,不建议使用与获取数据时相同的 DTO,而要单独创建一个新的 DTO 类,并通过数据注解特性对相应 的属性 ...
- ABC 314
F 每次相当于创建一个包含 \(p_i,q_i\) 各自所在集合的点的大点 \(u\),然后 \(u\) 向 \(p_i,q_i\) 各自所在集合连边,边权就是胜率. 连完之后求每个点到根结点(\(\ ...
- IntersectionObserver对象
IntersectionObserver对象 IntersectionObserver对象,从属于Intersection Observer API,提供了一种异步观察目标元素与其祖先元素或顶级文档视 ...
- linux下使用find查找并操作文件
介绍 最近在centos7上部署了一套环境,需要根据文件名找到程序运行路径下的文件,并进行移动文件操作,为此查阅了一番,记录下这个操作的脚本.我想很多人都会有这个需求,查找简单,但是要对对查找到的文件 ...
- 我又踩坑了!如何为HttpClient请求设置Content-Type?
1. 坑位 最近在重构认证代码,认证过程相当常规: POST /open-api/v1/user-info?client_id&timstamp&rd=12345&sign=* ...
- 安装Standalone模式HBase
所谓Standalone模式HBase,就是只启动一个JVM进程,在这个进程中同时启动了多个后台角色,如:HMaster,单个HRegionServer,以及ZooKeeper服务. 下载安装 最新版 ...
- Array.forEach() 与 Array.map()这些方法的第三个可选参数 array 的作用
说明 let thisArray = [] thisArray.forEach((item, index, array)=>{ //为什么要有array,而不是直接用thisArray? }) ...
- OpenCV开发笔记(六十一):红胖子8分钟带你深入了解Shi-Tomasi角点检测(图文并茂+浅显易懂+程序源码)
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...