浮点数的一些认识

浮点数的一些认识

浮点数包括 float double 两种类型, float 32 位, double 64 位。其二进制存储格式遵循 IEEE754 标准。以 float 为例:

     

      符号位:正数为 0 ,负数为 1

      float 型数据 123.456 为例,分析其二进制存储格式:

      首先将十进制数 123.456 转换为二进制数为: 1111011. 01110100101111001 

      (其中 0.456 如何转换为二进制?不断乘以 2…

      1111011. 01110100101111001  1. 11101101110100101111001 乘以 2 6 次方

      首先这是一个正数,则符号位为 0

      阶码为 6 ,不过要转换成移码。

      (如何求 6 的移码?这里我也不太深究,我见大家都是直接 6+127=133 ,换为 2 进制为 10000101

      尾数则为 1. 11101101110100101111001 的小数部分,即

11101101110100101111001

综上: 123.456 的二进制存储格式为: 0 1000010 111101101110100101111001

用一段代码来验证一下:

#include <cstdlib>

#include <iostream>

using namespace std;

void printBinary(const unsigned char val)

{

      for(int i = 7; i >= 0; i--)

           if(val & (1 << i))

                 std::cout << "1";

           else

                 std::cout << "0";

}

int main()

{

      float d = 123.456;

      unsigned char* cp = reinterpret_cast<unsigned char*>(&d);

      for(int i = sizeof(float)-1; i >= 0 ; --i)

      {

           printBinary(cp[i]);

      }

      system("PAUSE");

}

      要注意的是, X86 架构为小端模式,是指数据的低位保存在内存的低 地址 中,而数 据的高位保存在内存的高地址中。所以上面的 for(int i = sizeof(float)-1; i >= 0 ; --i) 先打印高地址部分,即二进制的高字节数据。

      程序的执行结果:

     

0 1000010 111101101110100101111001

      对比一下刚才的分析结果是相同的。

      double 类型和 float 类型的二进制存储格式是同样的道理。


以上部分是我从别人的博客中转来的,大家可以看看,好了,下面我提出一个问题,


double a;
a=1.1;
int b = (int&) a;



然后输出b,会是什么结果,1吗,当然不是,结果是 -1717986918,为什么呢,我们来分析一下:

double是用52位来存储小数部分的,我们算出52位的存储应当是 0001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010 最后四位需要注意,因为在计算机里面也是需要“四舍五入的”。如果省略的后一位是1那么前一位就要加一来存储。所以1001 + 1就是1010。
四、取最后面的32位,换成有符号的十进制。第一位是符号,表示负数,取补码就是 0110 0110 0110 0110 0110 0110 0110 0110就是1717986918。即是-号的这个数而已。


另外还有一个很有意思的事情,看看下面的代码:

double a=3.0,b=10.0,ans;

ans=a/b;

单步调试看看ans的值会是多少,0.333333333...吗,当然不是,而是0.299999999...,为什么呢,分析一下,C语言里用的是IEEE794浮点数,比如double型是64位的。很多数,比如0.3用二进制表示是无限循环小数,自然会被截断。除非你用第三方的精确浮点库,否则只要是C语言,无论哪个编译器都是这个结果,你输出的时候最好用%5.2f这样的宽度控制来限制输出尾数,而且如果判断的话,一定不要直接用==。最好是abs(a-b)<0.000001之类的。

另外一个很好的方法是在3.0上面加一个无穷小的小数,比如你的编译器支持的浮点数的最小正小数是0.000000001,那么在运算的时候在3.0上加上这个值,再除10,就不会出现这样的情况了。这个只能解决部分问题,如果要心里安稳点的话,就看看标准库里的float.h头文件或者cfloat头文件吧

有个朋友说,最初的时候Excel和Windows计算器都用的IEEE794浮点数,double的有效数字最大就15位。
不过后来Windows计算器内部实现了一个比较复杂的模拟分数算法。你也可以用一对p和q保存值的分子和分母,认为遇到的值都是有理分数(无理数只能截断)。作为参考吧

posted on 2011-05-18 23:05  karying  阅读(431)  评论(0编辑  收藏  举报

导航