其实不论是float还是double在存储方式上都是遵从IEEE的规范 的,float遵从的是IEEE R32.24 ,而double 遵从的是R64.53。
无论是单精度还是双精度在存储中都分为三个部分:
- 符号位(Sign) : 0代表正,1代表为负
- 指数位(Exponent):用于存储科学计数法中的指数数据,并且采用移位存储
- 尾数部分(Mantissa):尾数部分
我们知道,浮点数在内存中是以科学记数法存储的,只不过我们用的是10进制,而计算机用的是2进制,例如 123456789.4321
关于指数,他们的表示方式是一个偏移量,float的为127,double的为1023,所以实际在指数位存储的值为 指数 + 1023
下面是我写的一个测试程序:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace ConsoleViewer 7 { 8 class Program 9 { 10 static void Main(string[] args) 11 { 12 double val = 123456789.4321; 13 int offset = 1023; 14 long value = GetMemoryValue(val); 15 int sign = (int)(((ulong)value & 0x8000000000000000)>>63); 16 int e = (int)((value & 0x7FF0000000000000)>>52)-offset; 17 long d = (value & 0xFFFFFFFFFFFFF); 18 Console.WriteLine("123456789.4321 在内存内的布局方式:\r\n\r\n{0}\r\n", GetBinary(val)); 19 double b = GetBaseNumber(d); 20 Console.WriteLine("符号位:{0}",sign); 21 Console.WriteLine("指数:{0}",e); 22 Console.WriteLine("底数小数部分(十进制):{0}",d); 23 Console.WriteLine("底数小数部分(二进制):\r\n{0}", GetBinary(d)); 24 Console.WriteLine("十进制底数:{0}",b); 25 Console.WriteLine("验算:{0} * 2^{1} = {2}",b,e,b*Math.Pow(2,e)); 26 Console.ReadLine(); 27 } 28 29 static double GetBaseNumber(long value) 30 { 31 double result = 0.0, u = 0x10000000000000; 32 long d = 0x1; 33 for (int i = 0; i < 52; i++) 34 { 35 result += ((value & d) >> i) / u; 36 d <<= 1; 37 u /= 2; 38 } 39 return 1 + result; 40 } 41 42 static unsafe long GetMemoryValue(double value) 43 { 44 return (*((long*)(&value))); 45 } 46 47 static unsafe string GetBinary(double val) 48 { 49 char[] chars = new char[64]; 50 ulong d = 1; 51 ulong value = *(ulong*)(&val); 52 for (int i = 0; i < 64; i++) 53 { 54 chars[63-i] = ((char)((char)((d & value)>>i) + '0')); 55 d <<= 1; 56 } 57 return new string(chars,0,64); 58 } 59 60 static unsafe string GetBinary(long val) 61 { 62 char[] chars = new char[64]; 63 ulong d = 1; 64 ulong value = *(ulong*)(&val); 65 for (int i = 0; i < 64; i++) 66 { 67 chars[63 - i] = ((char)((char)((d & value) >> i) + '0')); 68 d <<= 1; 69 } 70 return new string(chars, 0, 64); 71 } 72 } 73 }
上面的代码的运行结果见上图!