【原创】为什么浮点数1e38f + 1 - 1e38f等于0
1. 问题
为什么1e38f + 1 - 1e38f为0?
2. 分析
int ii = ; //00 00 00 02
int *pii = ⅈ
float i = 1e38f; //7e 96 76 99 (0111 1110 1001 0110 0111 0110 1001 1001)
float j = -1e38f;//fe 9676 99 (1111 1110 1001 0110 0111 0110 1001 1001)
float *pi = &i;
float *pj = &j;
int fs = sizeof(float);
float k = i + j + ; //3f 80 00 00 (0011 1111 1000 0000 0000 0000 0000 0000)
float l = i + + j; //00 00 00 00
float *pk = &k;
float *pl = &l;
根据IEEE 754single-precision binary floating-point format
单精度浮点数:4个字节,最高位为符号位,23-30共8位指数,0-22共23为尾数(隐藏了最高位1);指数用移码表示,指数的偏移量为127;尾数用补码表示。
float i = 1e38f; //99 76 96 7e (0111 1110 1001 0110 0111 0110 1001 1001)
符号位:0
指数:1111 1101
尾数:001 0110 0111 0110 1001 1001
float j = -1e38f; //99 76 96 fe (1111 1110 1001 0110 0111 0110 1001 1001)
符号位:1
指数:1111 1101(和上面一样有没有)
尾数:001 0110 0111 0110 1001 1001
指数对齐,尾数相加,(对齐时,指数向大的对齐,相加前小的指数对应的尾数要右移指数差位)
这里指数一样大,不用对齐;
1 = +1 * 2^0
符号位:0
指数:127(0111 1111)
尾数:1(000 0000 0000 0000 0000 0000)
0 0111 1111 000 0000 0000 0000 0000 0000
3. i + 1计算步骤:
3.1 指数对齐
1111 1101和0111 1111,差为253-127=126
尾数相加时要把隐藏的1写出来;
尾数补上最高位1,再右移126位,由于右移126位超过了23位,尾数都被移除,全被置0。
3.2 尾数相加
1001 0110 0111 0110 1001 1001
+ 0000 0000 0000 0000 0000 0000
= 0 1001 0110 0111 0110 1001 1001
3.3 溢出判断
上面的数没有溢出;
如果溢出将该数右移1位且指数加1
3.4 结果合成
由于尾数实际为24位,最高位总为1,实际上只存储23位,最高位不存储。
去除尾数最高位及指数部分清0:result =result &(~0xFF800000)
和较大指数合并:result= result| (e1 << 23);
result即为浮点数的二进制表示了,把它转换成浮点数:c = *((float *)&result);
由上述可以得出,尾数相加后不变,指数不变,所以和结果不变,仍为较大的那个浮点数。
进而我们可以得出一个结论:当两个浮点数的指数相差超过浮点数的尾数位数,那么两个浮点数的相加结果将会等于较大的浮点数! 所以1e38f + 1 - 1e38f = 1e38f - 1e38f = 0
4. 代码
#include <stdio.h>
// simple ieee 754 single precision float number
// addition arithmetic.
// format:
// S E F
// 1 8 23
float test1(float a, float b)
{
float c = ;
unsigned int p1 = *((unsigned int *)&a);
unsigned int p2 = *((unsigned int *)&b);
unsigned int t;
// compute exponent difference
// essentially, we must let two number's exponent be same
int e1 = (p1 << ) >> ;
int e2 = (p2 << ) >> ;
int diff = e1 - e2;
if (diff < ) {
diff = - diff;
t = p1;
p1 = p2;
p2 = t;
e1 = e2;
}
//convert mantissa to signed integer
// there is a hidden bit
//:) i do not want to handle minus number here
//
int p3 = p1 | 0x00800000;
p3 = p3 & 0x00ffffff;
int p4 = p2 | 0x00800000;
p4 = p4 & 0x00ffffff;
//mantissa should be shift right according to difference of
//exponent.
unsigned int result = p3 + (p4 >> diff);
if (result >= 0x01000000) {
result = result >> ;
e1 = e1 + ;
}
// combination
result = result&(~0xFF800000) | (e1 << );
c = *((float *)&result);
return c;
}
int _tmain(int argc, _TCHAR* argv[])
{
float c = test1(4.1f, 1.0f);
return ;
}
5. 流程图

6. 参考文献
https://en.wikipedia.org/wiki/Single-precision_floating-point_format
http://www.cnblogs.com/cornsea/archive/2010/09/18/1830366.html
【原创】为什么浮点数1e38f + 1 - 1e38f等于0的更多相关文章
- 【js奇妙说】如何跟非计算机从业者解释,为什么浮点数计算0.1+0.2不等于0.3?
壹 ❀ 引 0.1+0.2不等于0.3,即便你不知道原理,但也应该听闻过这个问题,包括博主本人也曾在面试中被问到过此问题.很遗憾,当时只知道一句精度丢失,但是什么原因造成的精度丢失却不太清楚.而我在查 ...
- 深入理解JavaScript系列:为什么03-0.2不等于0.1
五一宅家看书,所以接着更新一篇文章. 今天讲一下为什么03-0.2不等于0.1这个问题. 有点标题党的味道,在JavaScript中,当你试着对小数进行加减运算时,有时候会发现某个结果并非我们所想的那 ...
- 如何解决JavaScript中0.1+0.2不等于0.3
console.log(0.1+0.2===0.3)// true or false?? 在正常的数学逻辑思维中,0.1+0.2=0.3这个逻辑是正确的,但是在JavaScript中0.1+0.2!= ...
- Android6.0机型上调用系统相机拍照返回的resultCode值始终等于0的问题
版权声明:本文为博主原创文章,未经博主允许不得转载. 正常情况下调用系统相机拍照: 如果拍照后点击的是“确定”图标,返回的resultCode = -1(Activity.RESULT_OK): 如果 ...
- 为什么js中0.1+0.2不等于0.3,怎样处理使之相等?(转载)
为什么js中0.1+0.2不等于0.3,怎样处理使之相等? console.log(0.1+0.2===0.3)// true or false?? 在正常的数学逻辑思维中,0.1+0.2=0.3这个 ...
- 为什么在JavaScript中0.1+0.2不等于0.3?
0.1+0.2不等于0.3?是不是有点颠覆你的认知,但是,在js中,是真实存在的! console.log(0.1+0.2); // 0.30000000000000004 其实这都是因为浮点数运算的 ...
- mytatis将Integer等于0识别成空字符串
在进行myBatis条件查询的时候,会有如下操作: <if test="delFlag !=null and delFlag != ''"> and t.del_fla ...
- false等于0???
看到一个函数strpos($string,$str),用于在字符串$string中查找$str,如果在$string中查找到$str,则返回第一次出现的位置,起始位置为0:如果$string中不包含$ ...
- 【iOS开发必收藏】详解iOS应用程序内使用IAP/StoreKit付费、沙盒(SandBox)测试、创建测试账号流程!【2012-12-11日更新获取”产品付费数量等于0的问题”】
转的别人的 看到很多童鞋问到,为什么每次都返回数量等于0?? 其实有童鞋已经找到原因了,原因是你在 ItunesConnect 里的 “Contracts, Tax, and Banking”没有完成 ...
随机推荐
- redis学习-散列表常用命令(hash)
redis学习-散列表常用命令(hash) hset,hmset:给指定散列表插入一个或者多个键值对 hget,hmget:获取指定散列表一个或者多个键值对的值 hgetall:获取所欲哦键值以及 ...
- 线程中的join方法
join方法的作用是同步线程. 1.不使用join方法:当设置多个线程时,在一般情况下(无守护线程,setDeamon=False),多个线程同时启动,主线程执行完,会等待其他子线程执行完,程序才会退 ...
- [Java基础复习] -- x. 正则表达式的使用
序号待定, 先用x占位表示 理论知识待完善, 先贴上代码 import java.util.regex.Matcher; import java.util.regex.Pattern; import ...
- Solaris:你好奇的十件事
想想你周围的人,看看他们正在使用的操作系统.绝大部分人的电脑都在用主流操作系统:Windows,MacOS,甚至是Ubuntu.当说到Solaris,Unix和BSD的时候,其他人还以为你说鸟语呢.除 ...
- [转]MYSQL性能查看(命中率,慢查询)
网上有很多的文章教怎么配置MySQL服务器,但考虑到服务器硬件配置的不同,具体应用的差别,那些文章的做法只能作为初步设置参考,我们需要根据自己的情况进行配置优化,好的做法是MySQL服务器稳定运行了一 ...
- 破解StarUML3.01最新版 for Linux(Ubuntu16LTS)
原文地址:https://blog.csdn.net/yoyofreeman/article/details/80844739 chmod +x StarUML-3.0.1-x86_64.AppIma ...
- FineCMS 5.0.10 多个 漏洞详细分析过程
0x01 前言 已经一个月没有写文章了,最近发生了很多事情,水文一篇.今天的这个CMS是FineCMS,版本是5.0.10版本的几个漏洞分析,从修补漏洞前和修补后的两方面去分析. 文中的evai是特意 ...
- 白话TCP为什么需要进行三次握手
阅读本文大概需要 2.3 分钟. 作者:雨林 https://www.cnblogs.com/yuilin 首先简单介绍一下TCP三次握手 在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次 ...
- JDK设计模式之——策略模式(Comparable和Comparator接口)
策略模式:其实就是java的多态...父类引用指向子类对象. 使用策略模式,改善排序算法上文中需要排序的是一个数组 让他可以对任何类型的数组进行排序 1.利用 接口 Comparable<T&g ...
- 使用Java面向对象单词必备
第一章 class 班级,用声明类 object 目标,整个程序集对大 static 静态的 final 不可更改的,用声明常量 private 私有的,用访问权限 public ...