Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >浅谈浮点数(一)

浅谈浮点数(一)

作者头像
SecondWorld
发布于 2021-08-06 01:59:23
发布于 2021-08-06 01:59:23
63600
代码可运行
举报
文章被收录于专栏:Java开发者杂谈Java开发者杂谈
运行总次数:0
代码可运行

小数与浮点数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
很多人都会认为,小数就是浮点数。但其实非也。
小数只是一种实数的一种特殊表现形式,所有分数都可以用小数来表示。
而浮点数,是计算机领域的一个术语,浮点数代表着目前计算机表示小数的一方式。

浮点数的由来

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
我们都知道计算机表示特定的数据类型长度是固定的。
比如在java语言里,小数的表示,float是4字节,double是8字节。
那么这些固定长度的二进制位是如何表示小数的呢?
最直观的表示办法就是:固定的整数部分位数和固定的小数部分位数。比如以float为例,我们假设取前8位表示整数部分,后24位表示小数部分。则1.2用该方法表示如下:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	00000001 00000000 00000000 00000000 00000010
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    以上这种表示小数的方法我们称之为:定点表示法,即小数点的位置是固定的(这里固定在第24位之前)。
但是这种定点表示法有一个很大的问题,就是表示数的范围很有限。假设我现在要表示:256.1
那么因为整数部分固定只有8位,将无法表示256,会出现溢出。

   于是乎聪明的计算机科学家想到了另一种办法:科学计数法。我们知道10进制下的科学计数法可以将一个数表示成: 1.xxx * 10^n 。
依葫芦画瓢,那么2进制的科学计数法应该长这样:1.xxx * 2^n 
那么我们在存储小数的时候,可以用一部分存储指数:n,一部分存储小数:xxx 即可。
而这种表示的方式下,其实小数点没有固定的位置,既小数点是浮动的。所以我们也就称这种存储方式下的数字为浮点数。

浮点数的存储规范:IEEE 754

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  IEEE二进制浮点数算术标准(IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用。
这个标准定义了表示浮点数的格式(包括负零-0)与反常值(denormal number)),一些特殊数值(无穷(Inf)与非数值(NaN)),以及这些数值的“浮点数运算符”;
它也指明了四种数值舍入规则和五种例外状况(包括例外发生的时机与处理方式)。
说人话就是:一个浮点数可以表示如下:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	value = sign x exponent x fraction 
	其中value表示浮点数的实际值
	sign(bit)表示符号位: 0表示整数 1表示负数
	exponent表示的是转换成科学计数法后的指数偏移值
	fraction表示小数部分
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   知道浮点数的具体表示方式之后,接下来就是要确定每一部分所占的长度。
在IEEE 754标准中,对于32位浮点数的各部分长度约定如下:
    ·1bit的sign + 8bit的exponent + 23bit的fraction·
而对于64位的浮点数的各部分长度约定如下:
    ·1bit的sign + 11bit的exponent + 52bit的fraction·

我们前面说过exponent并不是科学计数法之后的实际指数,而是代表科学计数法后的指数偏移量。那么怎么个偏移法呢?
其实在IEEE 754中也对这个做了规定。我们假设k表示exponent所占的总位数,n表示转换成科学计数法之后的实际指数值,那么最终exponent = 2^(k-1) + n 
    
为什么要这么设计呢?我们知道小数可能是不带整数的,这时候如果转换成科学计数法之后实际指数值就应该是负数。
对于指数为负数的情况,我们很自然地会想到用exponent部分的第一位表示正负,然后对于负数值采用补码的方式来表示(取反加一)。
而原来整个value值也有一个sign位表示正负,剩余位在小数为负数的时候也需要使用补码方式来表示。
我们假设这样一种情况:指数为负数且小数为负数,那么对exponent部分的两次取反加1会导致最终结果不可预知。

	因此,最后IEEE 754采用了:exponent = 2^(k-1) + n 这种方式来存储指数的偏移值。

java中如何查看浮点数的二进制表示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
我们可以使用如下两行代码来查看0.1分别在32位和64位下的二级制形式:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
     System.out.println(Integer.toString(Float.floatToIntBits(0.1f), 2)); // 111101110011001100110011001101
     System.out.println(Long.toString(Double.doubleToLongBits(0.1), 2)); // 11111110111001100110011001100110011001100110011001100110011010
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
我们将高位补0,并且按照前面所讲的sign + exponent + fraction的形式将两者拆解如下:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
0 01111011    10011001100110011001101
0 01111111011 1001100110011001100110011001100110011001100110011010
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
要将一个小数转换成浮点数的形式,首先要求得小数的二进制表示法。0.1的整数部分为0,整数部分的如果用8位表示则为:00000000。
小数部分的0.1如何转换成2进制呢?这里我们仍然要从10进制小数来进行推导。

我们假设计算机是以10进制的形式来存储数据的。那么对于0.631,小数部分第1位存储的应该直接就是6,也就是0.631 * 10 的整数部分。
第2位存储的应该就是3,也就是 0.31 * 10 (在第一步去掉整数部分之后再乘以10的整数部分)。同理第3位存储的就是10.1 * 10。

于是乎我们可以得到0.1作为二进制在计算机中的存储:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	第一位: 0.1 * 2 = 0.2 的整数部分  0
	
	第二位: 0.2 * 2 = 0.4 的整数部分  0
	第三位: 0.4 * 2 = 0.8 的整数部分  0
	第四位: 0.8 * 2 = 1.6 的整数部分  1  ---》再去掉整数部分后为0.6
	第五位: 0.6 * 2 = 1.2 的整数部分  1  ---》再去掉整数部分后为0.2
	
	第六为: 0.2 * 2 = 0.4 的整数部分  0
	第七位: 0.4 * 2 = 0.8 的整数部分  0
	第八位: 0.8 * 2 = 1.6 的整数部分  1  ---》再去掉整数部分后为0.6
	第九位: 0.6 * 2 = 1.2 的整数部分  1  ---》再去掉整数部分后为0.2
	
	.....
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
综上,我们得到0.1的二进制存储应该为:0001100110011...(0011循环)。
于是,0.1的整个二进制表示为: 00000000.0001100110011...(0011循环)
转换成科学计数法为:1.100110011...(0011循环) * 2^(-4)。
按照IEEE 754标准,如果是32位的表示法,那么exponent = 2 ^ 7 + (-4) = 01111011
如果是64位表示法,则exponent = 2 ^ 10 + (-4) = 01111111011
再按照 sign + exponent + fraction的表示方法拼接起来即得到32位和64位的表示分别如下:
	0 01111011    100110011001100110011...0011循环)
	0 01111111011 100110011001100110011001100110011001100110011...0011循环)

最后剩下的问题就是:小数的存储位数是固定的,那么如果将循环的部分截断呢?这就涉及到舍入规则。
舍入的规则如下:即如果左规或右规时丢弃的是0,则舍去不计,反之要将尾数的末尾加1。
我们同样以0.1为例,32位情况下,小数部分的最终表示如下:10011001100110011001101
我们知道小数部分最后是0011循环,所以最后一位数字本来应该是0,但是因为紧接着的是1,所以最终截取之后还需要进行加1操作,于是就得到164位的表示法同样也可以根据这个规则得到。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-08-03 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
JavaScript 浮点数之迷:0.1 + 0.2 为什么不等于 0.3?
“0.1 + 0.2 = ?” 这个问题,你要是问小学生,他也许会立马告诉你 0.3。但是在计算机的世界里就没有这么简单了,做为一名程序开发者在你面试时如果有人这样问你,小心陷阱喽! 你可能在哪里见过
五月君
2020/02/19
4.3K0
IEEE 754二进制浮点数算术标准
纳尼,不应该是0.1么,怎么变成0.09999999999999998呢?这就要从ECMAScript标准讲起了。
meteoric
2018/11/19
1.9K0
理解浮点数
相信大家在平常的 JavaScript 开发中,都有遇到过浮点数运算精度误差的问题。
QQ音乐前端团队
2018/12/09
2.6K0
理解浮点数
小朋友学C语言(43):浮点数的深入分析
IEEE二进制浮点数算术标准(IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用。这个标准定义了表示浮点数的格式(包括负零-0)与反常值(denormal number)),一些特殊数值(无穷∞与非数值NaN),以及这些数值的“浮点数运算符”。 IEEE 754规定了四种表示浮点数值的方式:单精确度(32位)、双精确度(64位)、延伸单精确度(43比特以上,很少使用)与延伸双精确度(79比特以上,通常以80位实现)。只有32位模式有强制要求,其他都是选择性的。大部分编程语言都有提供IEEE浮点数格式与算术,但有些将其列为非必需的。例如,IEEE 754问世之前就有的C语言,现在有包括IEEE算术,但不算作强制要求 C语言的float通常是指IEEE单精确度,而double是指双精确度。
海天一树
2019/03/06
2K0
小朋友学C语言(43):浮点数的深入分析
浮点数与IEEE 754标准浅谈
浮点数是一种用于表示实数的数值表示形式,它使计算机能够处理非常大的或非常小的数值。例如,在科学计算中,我们经常需要处理像 6.022 × 10^23 这样的数字,使用浮点数表示可以极大地提高计算的灵活性和效率。
一条晒干的咸鱼
2024/11/19
6620
浮点数与IEEE 754标准浅谈
0.1 + 0.2 不等于 0.3?原来是因为这个
浮点数精度丢失,一直是前端面试八股文里很常见的一个问题,今天我们就来深入的了解一下问题背后的原理,以及给一些日常处理的小技巧。
沐洒
2023/07/05
6820
0.1 + 0.2 不等于 0.3?原来是因为这个
探秘 JavaScript 世界的神秘数字 1.7976931348623157e+308
JavaScript 的 Number 对象中存储了很多常量,神秘数字 1.7976931348623157e+308 就在其中,打开浏览器 Console,输入 Number.MAX_VALUE,就会得到这个数字:
清秋
2022/09/20
1.9K0
探秘 JavaScript 世界的神秘数字 1.7976931348623157e+308
浮点数原理与精度损失问题
计算机中小数的表示按照小数点的位置是否固定可以分为浮点数和定点数。为了方便和float32浮点数做对比,我们构造一个32位精度的定点数,其中小数点固定在23bit处:
TOMOCAT
2020/10/29
3.4K0
浮点数原理与精度损失问题
js浮点数精度问题详解
浮点数精度问题是指在计算机中使用二进制表示浮点数时,由于二进制无法精确表示某些十进制小数,导致计算结果可能存在舍入误差或不精确的情况。
can4hou6joeng4
2023/11/17
9450
整数和浮点数在内存中的存储
三种表示方法均有符号位和数值位两部分,数值位的最高位被当作符号位,其中0表示“正”,1表示“负”,剩余的位则为数值位。
P_M_P
2024/01/18
2820
整数和浮点数在内存中的存储
C语言中的浮点数存储:深入探讨
由此可知,C语言中浮点数的存储方式和整数的存储方式是不同的,下面就让我们详细了解一下。
平凡之路.
2024/10/09
2850
C语言中的浮点数存储:深入探讨
基础野:细说浮点数
Brief                                 本来只打算理解JS中0.1 + 0.2 == 0.30000000000000004的原因,但发现自己对计算机的数字表示和运算十分陌生,于是只好恶补一下。  本篇我们一起来探讨一下基础——浮点数的表示方式和加减乘除运算。   在深入前有两点我们要明确的:   1. 在同等位数的情况下,浮点数可表示的数值范围比整数的大;   2. 浮点数无法精确表示其数值范围内的所有数值,只能精确表示可用科学计数法m*2e表示的数值而已;     
^_^肥仔John
2018/01/18
2.5K1
基础野:细说浮点数
Java浮点数机制及所存在的问题
Java中浮点数的机制,IEEE 754规则,以及为什么在java中0.1+0.2!=0.3
俺也想起舞
2020/08/14
7980
整数、浮点数在计算机中的存储
  计算机要处理的信息是多种多样的,如数字、文字、符号、图形、音频、视频等,这些信息在人们的眼里是不同的。但对于计算机来说,它们在内存中都是一样的,都是以二进制的形式来表示。要想学习编程,就必须了解二进制,它是计算机处理数据的基础。
mukekeheart
2019/09/29
1.9K0
整数、浮点数在计算机中的存储
原理解析 | JavaScript 计算0.1 + 0.2真的很难,看完才知道!
已经很久没有写技术文章了,脑袋瓜有点生锈,写的不好别见怪,今天就是想带点干货给大家分享一下。文章的内容有一点点难度,不过基本都是计算机组成原理的知识,算是温故而知新吧!
HTML5学堂
2020/07/14
8300
原理解析 | JavaScript 计算0.1 + 0.2真的很难,看完才知道!
JavaScript 浮点数陷阱及解法
众所周知,JavaScript 浮点数运算时经常遇到会 0.000000001 和 0.999999999 这样奇怪的结果,如 0.1+0.2=0.30000000000000004、1-0.9=0.09999999999999998,很多人知道这是浮点数误差问题,但具体就说不清楚了。本文帮你理清这背后的原理以及解决方案,还会向你解释JS中的大数危机和四则运算中会遇到的坑。
laixiangran
2018/10/22
1.9K0
JavaScript 浮点数陷阱及解法
浅谈float浮点型的底层存储与运算
没错,上述现象简单来说就是计算机计算的0.1+0.2并不等于0.3了,其实这个现象很常见,对别的语言来说也一样,下面通过一步步简要分析来解释这个现象
仙人技术
2021/08/31
2K1
浅谈float浮点型的底层存储与运算
浮点数在内存中的存储
常见的浮点数:3.14159、1E10等,浮点数家族包括: float、double、long double 类型。浮点数表示的范围: float.h 中定义
用户11328191
2024/10/23
2220
浮点数在内存中的存储
[c语言日寄]浮点数在内存中的储存
在计算机科学中,浮点数是一种用于表示实数的数据类型。与整数不同,浮点数可以表示非常大或非常小的数值,并且能够处理小数部分。然而,浮点数在内存中的存储方式与整数有很大的不同,本文将深入探讨浮点数在内存中的存储方式,帮助读者更好地理解这一概念。
siy2333
2025/02/07
1750
[c语言日寄]浮点数在内存中的储存
IEEE二进制浮点数算术标准(IEEE 754)
IEEE二进制浮点数算术标准(IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用。这个标准定义了表示浮点数的格式(包括负零-0)与反常值(denormal number)),一些特殊数值(无穷(Inf)与非数值(NaN)),以及这些数值的“浮点数运算符”;它也指明了四种数值舍入规则和五种例外状况(包括例外发生的时机与处理方式)。
用户7886150
2021/02/12
1.6K0
相关推荐
JavaScript 浮点数之迷:0.1 + 0.2 为什么不等于 0.3?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验