浮点数的存储方式与剖析 独属 浮点数的科学计数法 V(-1)^S * M * 2^E10进制 2进制 科学2进制5.0 101.0 -1^0 * 1.01 * 2^2以四字节float和八字节doble举例符号位S 指数E 有效数M1bit 8bit 23bit 32bit float1bit 11bit 52bit 64bit doubleM第一位默认1,因此省略第一位M也可多存储一个bitE为无符号数但可为负eg0.5 0.1 (-1) ^ 0 * 1.0 * 2^-1因此真实E 中间值 实际存储的Efloat 127double 1023#include stdio.h int main() { float f -9.5; //化为标准二进制为 (-1)^1 * 1.0011 * 2^3 //S 1 M 1.0011 真实存储 0011 E 3 真实存储 127 3 //1 10000010 00110000000000000000000 return 0; }有的10进制无法用2进制完美表示eg:1.2 1.001..........普遍场景E不全01情况E存储 − 127float / 1023double 真实EM前加 1.特殊场景E 全 0 E当成 -126 /-1022计算M前面不再加 1E 全 0 是非规格化数可以表示一系列确定的极小数字不是单纯 “无限趋近 0”只是数值非常靠近 0。最小 float 非规格化数\(2^{-149}\)E 全 1M 全 0\(\boldsymbol{\pm\infty}\)正负无穷 含义运算存在数学结果但数值超出浮点数可表示范围溢出。S0 为正无穷S1 为负无穷。无穷不是一个确定大数只是溢出标记。2. E 全 1M 不全 0\(\boldsymbol{NaN}\)Not a Number非数 含义运算本身无数学意义不存在合法结果例0/0、负数开平方。 重要特性NaN 不等于任何数包括 NaN 自身。便于理解版E 全 1M 全部为 0 → 正负无穷不是无穷小无穷小是靠近 0无穷是数值溢出极大 / 极小有正负M 任意位不为 0 → NaN运算无数学意义。 E 全 0非规格化数是一组确定的极小值不是单纯 “无限接近于 0”只是数值非常靠近 0。#define _CRT_SECURE_NO_WARNINGS 1 #include stdio.h int main() { double a 0.1; double b 0.2; double c 0.3; double esp 1e-9;// 1.0 * 10^-9 if (fabs((a b - c) esp))// fabs() 求浮点数绝对值函数 math.h { printf(\n); } else { printf(!\n); } }#define _CRT_SECURE_NO_WARNINGS 1 #include stdio.h int main() { // int类型9二进制0000 0000 0000 0000 0000 0000 0000 1001 int n 9; // 取出变量n的内存地址强制转换成float*指针 // 意思不改变内存里的二进制改用float浮点数规则解析这同一块4字节内存 float* pFloat (float*)n; // 按照int规则解读这块内存读出整数9 printf(n %d\n, n); /* 现在用浮点数规则解读这块二进制 S(符号位)0E(指数位)全0M(尾数位)不全为0 属于【非规格化浮点数】是一个非常靠近0的极小正数 因为数值太小%f默认保留6位小数所以打印显示0.000000但它本身不等于0 */ printf(pFloat %f\n, *pFloat); // 向pFloat指向的这块内存也就是n的内存写入float 9.0f的二进制编码 // 注意写入的是浮点数9.0对应的二进制和整数9的二进制完全不一样 *pFloat 9.0f; // 现在再用int规则读取这块内存拿到的就是浮点数9.0的二进制对应的整数 printf(n %d\n, n); // 用float规则读取就是正常的9.0 printf(pFloat %f\n, *pFloat); return 0; }