建设境外网站,浙江省建设工程造价信息网,wordpress获取用户文章,网站被人抄袭怎么办文章目录 例题引入剖析原因浮点型的二进制转换#xff08;M#xff09;正负号之分#xff08;S#xff09;科学记数法#xff08;E#xff09;关于 S E M 在内存中的存储存取浮点型时的情况讨论 例题解析整形存储为浮点型并输出浮点型存储为整形并输出 在我的上一篇博客中… 文章目录 例题引入剖析原因浮点型的二进制转换M正负号之分S科学记数法E关于 S E M 在内存中的存储存取浮点型时的情况讨论 例题解析整形存储为浮点型并输出浮点型存储为整形并输出 在我的上一篇博客中详细写了整形在内存中的存储以及大小端的介绍有兴趣可以看一下本篇文章重点讲讲浮点型在内存中的存储。 例题引入
#include stdio.h
int main() {int n 9;float* pFloat (float*)n;printf(n的值为%d\n, n);printf(*pFloat的值为%f\n, *pFloat);*pFloat 9.0;printf(num的值为%d\n, n);printf(*pFloat的值为%f\n, *pFloat);return 0;
}大家可以先猜测一下上述例题的输出结果可能是什么如果不是很熟练或者对float类型在内存中存储的方式不同的话很有可能会认为浮点数和整型在内存中的存储是一样的然而不对正确的输出结果如下 n的值为9 *pFloat的值为0.000000 num的值为1091567616 *pFloat的值为9.000000 剖析原因
那接下来就讲讲这其中的原因
在上一篇博客中我提到所有整形都是以二进制补码的形式存储在内存中的而浮点型虽然也是以二进制存储在内存中但是它遵循着国际标准IEEE(电气和电子工程协会)754 V ( − 1 ) S ∗ M ∗ 2 E ∙ ( − 1 ) S 表示符号位,当S0, V为正数;当S1, V为负数 ∙ M 表示有效数字,M是大于等于1,小于2的 ∙ 2 E 表示指数位 \begin{aligned} V(-1)^S*M*2^E \\ \bullet(-1)^S\text{ 表示符号位,当S0, V为正数;当S1, V为负数} \\ \bullet\text{ M 表示有效数字,M是大于等于1,小于2的} \\ \bullet2^E\text{ 表示指数位} \end{aligned} V(−1)S∗M∗2E∙(−1)S 表示符号位,当S0, V为正数;当S1, V为负数∙ M 表示有效数字,M是大于等于1,小于2的∙2E 表示指数位
大家第一次见应该都没法一下理解现在我以 5.5 这个浮点数为例通过画图解释一下IEEE中的 MSE
浮点型的二进制转换M
首先我们要将浮点数在转换为二进制数 下图就是二进制的转换方法首先5.5的二进制数是101.1
可以理解二进制的转换规则为凑相当于在小数点两边一直是2的n次方但是左边的n是从0开始依次递增右边的n是从-1开始递减当1代表有0代表没有左右两边独立计算。
以左边为例 1 * 22 0 * 21 1 * 20 5这样左边的5的二进制就凑出来了相同的右边 1 * 2-1 0.5右边的二进制也就出来了放在一起就是浮点数的二进制了。 而5.5转换成二进制后的101.1对应的就是IEEE中的M 正负号之分S
M出来了先理解一下好理解的S
举例来说:
十进制的5.0写成二进制是 101.0相当于 1.01x2^2。 那么按照上面V的格式可以得出S0M1.01E2.
十进制的-5.0写成二进制是-101.0相当于-1.01x2^2。 那么S1M1.01E2.
意思就是在IEEE中V最前面都是以 (-1)^S 的形式出现如果这个浮点数是整数S为0反之为1 科学记数法E
小学我们就学过十进制的科学计数法比如10000的科学计数法就是1*104 这里的E也是一样IEEE把M的值设定为在1和2之间所以我们需要把M的小数点放在第一个1的后面而往前往后多少位就决定了E的正负多少数
比如 1000.1的科学计数法就是1.0001 * 23 0.000101的科学计数法就是1.01 * 2-4
还是比较好理解的而之所以的2的次方是因为当前是二进制 但先注意下这里的E并不是最后储存的E等S,E,M的内存存储的形式了解后在解释 关于 S E M 在内存中的存储
对于32位的浮点数最高的1位存储符号位S接着的8位存储指数E剩下的23位存储有效数字M 对于64位的浮点数最⾼的1位存储符号位S接着的11位存储指数E剩下的52位存储有效数字M
如下图 注意点1 M的保存形式 前面说过 1≤M2 也就是说M可以写成1.xxxxxx 的形式其中 xxxxxx 表示小数部分。IEEE 754 规定在计算机内部保存M时默认这个数的第一位总是1因此可以被舍去只保存后面的xxxxxx部分。比如保存1.01的时候只保存01等到读取的时候再把第一位的1加上去。这样做的目的是节省1位有效数字。以32位浮点数为例留给M只有23位将第一位的1舍去以后等于可以保存24位有效数字。
注意点2 E的保存形式 首先E为一个无符号整数(unsignedint)
这意味着如果E为8位它的取值范围为0 ~ 255;如果E为11位它的取值范围为0 ~ 2047。但是我们知道科学计数法中的E是可以出现负数的所以IEEE754规定存入内存时E的真实值必须再加上一个中间数对于8位的E这个中间数是127;对于11位的E这个中间数是1023。比如2^10的E是10所以保存成32位浮点数时必须保存成10127137即10001001。 存取浮点型时的情况讨论
指数E从内存中取出还可以再分成三种情况:
情况1E不全为0或不全为1
这时浮点数就采用下面的规则表示即指数E的计算值减去127(或1023)得到真实值再将有效数字M前加上第一位的1。 比如:0.5的二进制形式为0.1由于规定正数部分必须为1即将小数点右移1位则为1.0*2^(-1)其阶码为-1127(中间值)126表示为 0111 1110而尾数1.0去掉整数部分为0补齐0到23位00000000000000000000000则其二进制表示形式为: 0 01111110 00000000000000000000000 情况2E全为0
这时浮点数的指数E等于1-127(或者1-1023)即为真实值有效数字M不再加上第一位的1而是还京为0.xxxxxx的小数。这样做是为了表示士0以及接近于0的很小的数字。 0 00000000 00100000000000000000000 情况3E全为1
这时如果有效数字M全为0表示士无穷大(正负取决于符号位s)。 0 11111111 00010000000000000000000 例题解析
整形存储为浮点型并输出
我们回到最开始引入的例题 先看上面这一部分
#include stdio.h
int main() {int n 9;float* pFloat (float*)n;printf(n的值为%d\n, n);printf(*pFloat的值为%f\n, *pFloat);
}首先 n 作为整形在内存中是以二进制补码的形式存储正整数的补码是其本身 9的二进制为X86环境下 0000 0000 0000 0000 0000 0000 0000 1001 类型转换时它不会先把原来的9以IEEE规则分解然后存储而是直接以9的二进制形式进行存储也就是说会变成下图情况 因为前面说到当E全为0时E的真实值为1-127也就是-126 所以最后存储的V为 V(-1)0 × 0.00000000000000000001001×2(-126)1.001×2(-146) 显然V是一个很小的接近于0的正数所以用十进制小数表示就是0.000000。 所以上面部分的代码的结果就是 n的值为9 *pFloat的值为0.000000 浮点型存储为整形并输出
再来看下半部分的代码
#include stdio.h
int main() {*pFloat 9.0;printf(num的值为%d\n, n);printf(*pFloat的值为%f\n, *pFloat);return 0;
}我们先把9.0在内存中的存储形式表达出来
首先9.0是正数所以S - 0
然后9.0的二进制为1001.0
所以 V(-1)0 × 1.001×2(3)
最后得出 S - 0 E - 3127 130 - 10000010 M - 去掉首位1 - 得001 - 补齐23位 - 001 0000 0000 0000 0000 0000 最后在内存中得存储 0 10000010 001 0000 0000 0000 0000 0000 通过计算器我们可以知道上面这个二进制数直接转换为十进制数为 这样我们就得出了最后的结果 num的值为1091567616 *pFloat的值为9.000000 – 完