本文以单精度的内存存储来说明的
0X01 浮点数的内存存储
IEEE 754浮点数标准规定的浮点数结构:
S | E | M | 公式{V=(-1)S*2E*M ;E=e-Bias} | 偏移量 | |
---|---|---|---|---|---|
单精度 | 1 | 8 | 23 | (-1)S*2(e-127)*M ;(Bias = 127) | 127 |
双精度 | 1 | 11 | 52 | (-1)S*2(e-1023)*M;(Bias = 1023) | 1023 |
S是符号位,E是阶码,Bias = 2k-1 -1 。
M是尾数编码,尾数m为内存中小数字段,其值依赖于阶码e是否为0,当e!=0时M=1.m;当e=0时M=0.m;
其中S符号位,只有0和1,分别表示正负;E阶码,通常使用移码表示(原码、反码、补码和移码详解)。
二进制存储结构(单精度浮点数):
单精度 | S(第31位) | e((30位到23位)) | m(22位到0位) |
---|---|---|---|
双精度 | S(第63位) | e((62位到52位)) | m(51位到0位) |
单精度浮点数和双精度浮点数都是用IEEE754标准定义的,其中有一些 约定:
- 规格化的
e!=0&e!=255 - 非规格化的
e=0; 这里阶码E约定为固定值,E=1-Bias,(单精度时E=-126,双精度E=-1022); - 无穷
e=255 & m=0 ;阶码全为1,小数域全为0,根据符号位S来确定无穷大(s=0)还是无穷小(s=1) - NaN(Not a Number,不是一个数)
e=255 & m!=0;阶码全为1,小数域不为0
E用移码表示, 为了提供一种从非规格化值到规格化值平滑转换的方法 (为了规格化最小数和非规格化最大数平滑转变
)
0X02 极限值说明
Console.WriteLine(float.MaxValue); // 3.402823E+38
Console.WriteLine(float.MinValue); //-3.402823E+38
Console.WriteLine(float.Epsilon); // 1.401298E-45
1.最大值
S位取0,E位最大值取255-1 = 254,因为255有特殊含义 254=(11111110)2,M尾数m为11111111111111111111111)2
二进制表示: 011111110
11111111111111111111111
2.最小值
S位取1,E位最大值取255-1 = 254,因为255有特殊含义 254=(11111110)2,M尾数m为(11111111111111111111111)2
二进制表示: 111111110
11111111111111111111111
3.最接近0的浮点数(+0)
这里就得用非规格数来表示了,符号位S取0,阶码E取0,M尾数m取最小值为(00000000000000000000001)2
二进制表示: 000000000
00000000000000000000001
这里补充上代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace floatTest1
{
class Program
{
/// <summary>
/// 打印浮点数的二进制
/// </summary>
/// <param name="a"></param>
unsafe static void FToB(float a)
{
float* p = &a;
int b = *(int*)p;
Console.WriteLine(Convert.ToString(b, 2));
}
/// <summary>
/// 最大值
/// </summary>
unsafe static void DebugMaxFloat()
{
float b = 0f;
int* p = (int*)&b;
//这里是以符号位下标为0,先压入最高位,最后压入最低位
for (int i = 0; i < 32; i++)
{
int bit = 1;
//符号位 0
if (i == 0)
{
bit = 0;
}
//阶码 1-8
else if (i >= 1 && i <= 8)
{
//254的二进制是11111110,最后一位为0;
if (i == 8)
{
bit = 0;
}
}
//尾数 9-31
else
{
bit = 1;
}
*p = *p << 1;
*p = *p ^ bit;
}
//*p =* p >> 1;
FToB(b);
Console.WriteLine("Max::::"+b);
}
/// <summary>
/// 最小值
/// </summary>
unsafe static void DebugMinFloat()
{
float b = 0f;
int* p = (int*)&b;
//这里是以符号位下标为0,先压入最高位,最后压入最低位
for (int i = 0; i < 32; i++)
{
int bit = 1;
//符号位 0
if (i == 0)
{
bit = 1;
}
//阶码 1-8
else if (i >= 1 && i <= 8)
{
//254的二进制是11111110,最后一位为0;
if (i == 8)
{
bit = 0;
}
}
//尾数 9-31
else
{
bit = 1;
}
*p = *p << 1;
*p = *p ^ bit;
}
//*p =* p >> 1;
FToB(b);
Console.WriteLine("Min::::" + b);
}
/// <summary>
/// 最接近于+0的数
/// </summary>
unsafe static void DebugEpsilonFloat()
{
float b = 0f;
int* p = (int*)&b;
//这里是以符号位下标为0,先压入最高位,最后压入最低位
for (int i = 0; i < 32; i++)
{
int bit = 1;
//符号位 0
if (i == 0)
{
bit = 0;
}
//阶码 1-8
else if (i >= 1 && i <= 8)
{
//阶码取0,非规格化值,
bit = 0;
}
//尾数 9-31
else
{
//尾数取1;
if(i==31)
{
bit = 1;
}
else
{
bit = 0;
}
}
*p = *p << 1;
*p = *p ^ bit;
}
//*p =* p >> 1;
FToB(b);
Console.WriteLine("Epsilon::::" + b);
}
unsafe static void Main(string[] args)
{
Console.WriteLine("Max="+float.MaxValue); // 3.402823E+38
Console.WriteLine("Min=" + float.MinValue); //-3.402823E+38
Console.WriteLine("Epsilon=" + float.Epsilon); // 1.401298E-45
Console.WriteLine("------------------------------------------------------------------------------------");
DebugMaxFloat();
DebugMinFloat();
DebugEpsilonFloat();
}
}
}
0X03 举例单精度浮点数的表示
1.整数位表示
以a = 8为例子,8的二进制1000=1*23,符号位S=0;E = 3+127=130=(10000010)2;M尾数1.m=1.0,m全是0;
所以表示出来为:
010000010
00000000000000000000000
2.小数位表示
以a= 0.75为例子 0.75 = (1.1*2-1)2,符号位S=0;E = -1+127 = 126=(01111110)2;M尾数1.m=1.1,m=(10000000000000000000000)2 ;所以表示出来的数为:
001111110
10000000000000000000000
3.带整数位和小数位的表示
以a=8.75为例子,8.75= (1000.11)2=(1.00011*23)2,符号位S=0;E= 3+127=130=(10000010)2;M尾数1.m=1.00011 , m=(00011000000000000000000)2;所以表示出来的数为:
010000010
00011000000000000000000
上代码:
/// <summary>
/// 打印浮点数的二进制
/// </summary>
/// <param name="a"></param>
unsafe static void FToB(float a)
{
float* p = &a;
int b = *(int*)p;
Console.WriteLine(Convert.ToString(b, 2));
}
unsafe static void Main(string[] args)
{
FToB(8f);
FToB(0.75f);
FToB(8.75f);
}
结果:
0X04 浮点数的运算
参考这篇文章:浮点数的表示和基本运算
文章参考:
浮点数的表示和基本运算
浮点型 float double
IEEE-754 Analysis
2.7.1 浮点加法和减法
2.7.2 浮点乘、除法运算
浮点加法、减法, 乘法、除法运算