浮点数在计算机中的表示,程序中浮点数的取值和比较。

2023-05-16

小数的十进制、二进制转换

十进制 --> 二进制

整数部分除2取余,小数部分乘2取整。
考虑 8.25

整数部分8进行除2取余,
除2商4余0
除2商2余0
除2商1余0
除2商0余1
所以结果是1000【最后一个余数在最前】

小数部分0.25进行乘2取整,
0.25乘2得0.5 整数为0
0.5 乘2得1   整数为1
所以结果是01

十进制表示的8.25其二进制表示即为1000.01
 
 

二进制 --> 十进制

这个就简单多了,二进制的各个位乘以其权重即可。

整数部分 1*2^3 + 0*2^2 + 0*2^1 + 0*2^0  = 8
小数部分  0*2^(-1)  +  1*2^(-2)  =  0.25

 
 

小数不能被精确表示的原因

十进制中能够精确表示的小数,都是10的质因子2或5为分母的,比如

1/2=0.5     1/4=0.25      1/8=0.125   
1/5=0.2
1/10=0.1

十进制中不能精确表示的小数,有1/3,1/6,1/7,1/9

在二进制中,只有2是质因子,对于1/2,1/4,1/8可以精确表示;
但对于1/10=0.1和1/5=0.2都不能精确表示。【1/3,1/6,1/7,1/9也不能】
比如对于十进制表示的0.1取它的二进制表示,则是

小数部分0.1进行乘2取整,
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乘2得1.2 整数为1
0.2乘2得0.4 整数为0
0.4乘2得0.8 整数为0
0.8乘2得1.6 整数为1
发现已经开始循环了!根本无法取到精确值。

出处:https://0.30000000000000004.com/
 
 

计算机中小数的存储

需要先将小数的表示方法进行规格化,即整数部分为1,其余全部是小数部分的科学计数法。
比如

1000.01需要先表示为 1.00001*2^3

之后祭出IEEE 754标准
IEEE 754

符号位:0 表示正,1 表示负
指数位:指数是负数时,小数点需要左移;指数是正数时,小数点需要右移。
1.00001 * 2^3,里面的幂数+3代表小数点需要右移3位。
指数位的长度越长,数值的表达范围越大;
尾数位:小数部分,
1.00001 * 2^3,尾数部分就是 00001,
尾数的长度决定了这个数的精度,因此如果要表示精度更高的小数,则就要提高尾数位的长度;

double 的尾数部分是 52 位,float 的尾数部分是 23 位,但他们同时都隐含一个整数部分的1,
所以 double 共有 53 个二进制有效位,float 共有 24 个二进制有效位,
所以它们的精度在十进制中分别是 log10(2^53)约等于 15.95 和 log10(2^24)约等于 7.22 位,
因此 double 的有效数字是 15~16 位,float 的有效数字是 7~8 位,有效位包含整数部分和小数部分;

指数位里面的偏移量

在float类型当中
小数点移动范围是 -126~127
偏移量是127(0111 1111)
这样可以保证8位的指数位都是正数。

1000.01 规范化为 1.00001 * 2^3 
这里的指数位是 +3+127
0.00101 规范化为 1.01 * 2^(-3)
这里的指数位是 -3+127


在double类型当中
小数点移动范围是 -1022~1023
偏移量是1023(0011 1111 1111)
这样可以保证11位的指数位都是正数。

我们来填个空
1.00001 * 2^3
float类型在计算机中表示为
符号01位 0
指数08位 3+127 = 130 = 1000 0010
尾数23位 0000 1000 0000 0000 000
连起来
0 100 0001 0 000 0100 0000 0000 0000 0000
小端存储,低位在低地址,即为 0x41040000

这里有个网站,可以在线查看。
http://www.binaryconvert.com/result_float.html?decimal=056046050053
在这里插入图片描述
 
 

浮点数在计算机中的精度

double 的有效数字是 15~16 位,float 的有效数字是 7~8 位,有效位包含整数部分和小数部分;
如果整数部分越长,就会直接导致小数部分减少。精度变低!
如果小数部分最前边又添了几个0,就会直接导致尾数变长,变得更精确。

说明浮点表示仅仅是一种近似的表示方法,不能精确的表示数值,所以有时候大家在编程的过程中明明向float类型变量赋值了一个准确的数据,仿真一看数据成了一个近似值。

因此浮点数作比较不能使用==直接进行比较!
而是使用下面的宏

/***************************************
*Author:(公众号:最后一个bug)
****************************************/
#define FLOAT_EPS (0.000001) //根据需求
#define Float_Equ(a, b) ((fabs((a)-(b)))<(FLOAT_EPS))

再来一个例子证明精度问题,

#include <stdio.h>
#include <stdlib.h>
/***************************************
*Author:(公众号:最后一个bug)
****************************************/
#define	FACTOR	(1UL<<28)
int main(int argc, char *argv[]) {
	float a = 1.7 * FACTOR;
	float b = 0.2 * FACTOR;
	float c = a + b;

	float d = 1.9 * FACTOR;

	printf("%f\n", c);
	printf("%f\n", d);

	printf("%f\n",c - d);
	return 0;
}

打印结果为

510027392.000000
510027360.000000
32.000000

 
 

浮点数编程案例

#include <stdio.h>
#include <stdlib.h>

typedef union _tag_FloatConvert
{
    unsigned char byte[4];
    float Result;
}uFloatConvert;
/***************************************
*Author:(公众号:最后一个bug)
****************************************/
int main(int argc, char *argv[]) {
    uFloatConvert unFloatConvert; 
    float fVal   = 4.25;
    int   iVal   = 0x40880000;
    float *pfVal = NULL; 
    int   *pIVal = NULL; 

    //1)常见错误 
    fVal  = (float)iVal;
    printf("fVal = %.3f\n",fVal);
    printf("iVal = %d\n",iVal);

    //2) 正确做法
    pfVal = (float*)(&iVal);
    printf("*pfVal = %.3f\n",*pfVal);

    //3)采用共联体进行数据转化
    unFloatConvert.byte[0] = 0x00;
    unFloatConvert.byte[1] = 0x00;
    unFloatConvert.byte[2] = 0x88;
    unFloatConvert.byte[3] = 0x40;
    printf("unFloatConvert.Result = %.3f\n",unFloatConvert.Result);
    printf("公众号:最后一个bug\n");
    return 0;
}

运行结果

fVal = 1082654720.000
iVal = 1082654720
*pfVal = 4.250
unFloatConvert.Result = 4.250
公众号:最后一个bug

可见直接强制转换的做法是错误的!
 
 
本文内容大量参考下边的文章,如果有侵权问题,请联系我删除。
 
 

浮点数运算不满足交换律

(3.14 + 1e10) - 1e10 求值得到 0.0 因为尾数被丢掉了。
3.14 + (1e10 - 1e10) 会得到 3.14。
 
 

编译器、CPU不一定使用的是IEEE 754

x86 CPU 是在 x87 FPU的内部以80b计算得到结果后,再 truncate 为 IEEE 754 的 float(32b) 或者 double(64b),这中间会有微小的差异。

另一方面,ARM VFP 指令(IEEE 754 相容) 与 NEON指令(非完全 IEEE 754 相容)也可能会有不同的输出结果。

另外还有 gcc 的 -mfpmath=sse2 参数。
 
 

参考:
为什么 0.1 + 0.2 不等于 0.3 ?
【典藏】别怪"浮点数"太坑(C语言版本)
同事用"两个浮点数相等" 被说了一顿
浮点数的美丽与哀愁

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

浮点数在计算机中的表示,程序中浮点数的取值和比较。 的相关文章

  • 科大讯飞星火认知大模型:诚意满满、全村希望

    近日 xff0c 科大讯飞召开了星火认知大模型成果发布会 xff0c 会上表示讯飞星火大模型将突破开放式问答 xff0c 对标ChatGPT xff0c 在中文能力上超过ChatGPT xff0c 在英文能力上与ChatGPT相当 对此 x
  • Android NDK tombstone分析工具

    Android NDK tombstone分析工具 在Andoird Native库发生异常的时候 xff0c Linux会发生不同级别的sig xff0c 来结构相关进程的运行 xff0c 同时会产生tombstone trace文件用于
  • 关于UEFI

    最近在Thinkpad上安装Ubuntu12 04的时候 xff0c 经历了几个问题 xff0c 发现BOIS里多了很多选项 xff0c 而且安装双系统也有UEFI有关 xff0c 在网站上找了一篇文章 xff0c 发现这还是一个新概念 x
  • 怎样在github上协同开发

    描述 xff1a How to co work wither parter via github Github协同开发情景模拟 Github不仅有很多开源的项目可以参考 xff0c 同样也是协同开发的最佳工具 xff0c 接下来的就模拟一下
  • Android libdvm.so 与 libart.so

    Android libdvm so 与 libart so 系统升级到5 1之后 xff0c 发现system lib 下面没有libdvm so了 xff0c 只剩下了libart so 对于libart模式 xff0c 从4 4就在De
  • 链表快速排序quick-sort(递归+迭代)

    递归版 直接上代码 span class token keyword static span span class token keyword void span span class token function list qsort s
  • 反向代理--解决跨域问题

    为什么要解决跨域问题 xff1a 因为浏览器有限制 xff0c 只有同域名同端口号下的数据才能拿来用 xff1b 那如果想拿到不同域名不同端口号下的数据就不行了 xff1b 在单文件组件中如何去解决跨域问题 xff1a 因为服务器没有跨域限
  • 写在2011

    很早就想写点东西了 xff0c 可晃荡晃荡地就到了2011年最后一刻 我想是要写点东西了 2011年 xff0c 我有太多的感触 这一年是我第一次在异地迎接农历新年了 xff0c 对 xff0c 当时的感觉很刺激 xff0c 刺激得让我和当
  • Translate Aticle

    最近在Thinkpad上安装Ubuntu12 04的时候 xff0c 经历了几个问题 xff0c 发现BOIS里多了很多选项 xff0c 而且安装双系统也有UEFI有关 xff0c 在网站上找了一篇文章 xff0c 发现这还是一个新概念 x
  • Window64位系统用HSDIS对java代码进行反编译

    1 下载hsdis amd64 dll文件并放入 JAVA HOME jre bin中 xff0c 例如 xff1a C Program Files Java jdk1 8 0 191 jre bin 书上说的是放在 JAVA HOME j
  • golang中的context

    一 Context含义 1 context定义 context是golang中的上下文 goroutine的相关环境快照 xff0c 其中包含函数调用以及涉及的相关的变量值 golang通过Context机制解决一个request中多个go
  • Win10部署Authelia(OAuth2授权框架)

    一 安装docker 二 下载authelia代码 span class token comment 下载代码并切换到本地运行例子 span span class token function git span clone https gi
  • golang并发学习及实战记录

    一 切片append方法不是原子操作 多个协程操作同一个切片 xff0c 使用append方法添加元素时 xff0c 存在并发安全问题 xff0c 需要对append方法加锁 span class token keyword func sp
  • Jetson TX1/TX2搭载RTSO-9003载板刷机及使用JetPack3.3安装软件教程(防踩坑)

    1 烧录Linux系统 1 1 系统要求 最好给主机电脑安装Ubuntu14和Ubuntu16 x86 64系统 Ubuntu18系统不能运行JetPack3 3软件 xff0c 且JetPack3 3安装软件必须在主机Host x86 6
  • Ubuntu系统下ROS安装说明

    1 准备工作 安装前看看有什么更改Ubuntu默认的更新源 xff0c 如果更改了 xff0c 要换回备份的默认的安装源 xff08 etc apt sources list bak xff09 权限设置 用户需要成为 拨出 组的一部分 x
  • 腾讯云服务器上搭建Hadoop伪分布式教程

    1 登陆腾讯云服务器控制台查看内网ip地址 2 更改主机名 修改master ip地址 xff0c 地址改为内网地址 vi etc hosts 172 21 0 修改主机名 vi etc hostname master 重启服务器 rebo
  • 时间序列(二)数据重采样

    数据重采样 时间数据由一个频率转换到另一个频率 降采样 升采样 生成一条带随机值的时间序列 rng 61 pd date range span class hljs string 39 1 1 2011 39 span periods 61
  • linux lib/list_sort.c排序算法

    linux lib list sort c排序算法 没看懂 xff0c 留念一下 patch地址是https www mail archive com linux kernel 64 vger kernel org msg1957556 h
  • RealSenseD345I —— imu + camera标定

    目录 1 标定目的 2 标定准备 3 标定步骤 nbsp nbsp nbsp nbsp 1 IMU标定 nbsp nbsp nbsp
  • 深度学习分类算法系列之 -KNN

    先看一个实例来体会一下什么叫做KNN 已知一堆数据a和一堆数据0 xff0c 然后有一个未知数据c xff0c 要判断c到底属于a还是0 如果是1NN 就找到离C最近的数据 xff0c 离哪一个最近 xff0c 就判断c属于哪一类 如果利用

随机推荐