gyy 发表于 2008-1-9 16:43:08

如何把十进制实数转换成32位二进制数

记得在学校上过一门课叫《计算机组成原理》,其中有一小节内容是关于浮点数的,什么又是尾数又是阶码还有对阶等等,当时听的我是云里雾里的,反正就是没怎么听懂,觉得这个东西在以后的工作中不会碰到,所以也就没有最后也没有好好学习,不懂就不懂了吧。
    毕业了,工作了,进入一家自动化控制公司工作,期间会用到各种PLC,并用LD和FBD语言编写控制程序。幸好,在实际的编程中还不需要用到浮点运算,而且大部分的PLC也没有浮点处理器,万幸啊。不过有一次我在看一种PLC的技术资料时,发现里面提到了浮点运算,因为当时工作中没有这个需要,自己也就草草地一眼带过了。
    不幸的事还是发生了,自己在工作之余学习用汇编编写OpenGL的时候,发现需要用到大量的浮点运算,这下完了,这条沟我过不去了。没办法,只能再翻书,再找资料学习关于浮点数的知识。
    下面我就把我学到的东西写出来,给大家伙看看,如果谁在工作中会遇到这样的问题也能有所帮助。
    注:这里我只写32位的浮点数,64位其实是一样的。

gyy 发表于 2008-1-9 16:51:17

32位浮点数的格式

32位浮点数由三部分组成
一.符号位
二.阶码
三.尾数

〖符号位〗位于最高位的第31位,其占用32位里的1位,该位值为〖0〗表示整个浮点数为正数,该位值为〖1〗表示整个浮点数为负数

〖阶码〗位于第23位~第30位,其占用32位里的8位

〖尾数〗位于第0位~第22位,其占用32位里的23位

gyy 发表于 2008-1-9 17:40:44

开始转换,并用例子加以说明

现在把十进制实数13.437转换32位二进制
一.把13转换成二进制,结果为1101
二.把0.437转换成二进制,结果为0.0110;1111;1101;1111;0011;101
      这个结果只是近似值,还可以继续计算下去,但在这里已经不需要了
   这里用〖;〗把数字分开只是为了方便数位数,下面也是如此
三.把两个结果相加,结果为1101.0110;1111;1101;1111;0011;101
四.计算尾数,把小数点移到最高一位〖1〗的右面
(为什么要移?没有为什么,要移就是要移)
   结果为1.1010;1101;1111;1011;1110;0111;01
      小数点向左移动了3位,记住这个值,在后面阶码运算的时候要用到
      这个过程叫什么?我忘了:L 好象是〖对阶〗也好象是〖规格化〗
五.计算阶码。用刚才移动的位数(向左移动为正数,向右移动为负数)+3,加上127
   结果为130
   为什么要加127,我也不知道,希望看到这的并且知道原因的兄弟姐妹能够告诉小弟一声
六.把计算出的阶码〖130〗转换成二进制,结果为1000;0010
   好了,做到现在一切准备工作都完成了,接下来就是根据浮点数的格式把这些值写
   成32位二进制数了
七.填写〖符号位〗,其值为〖0〗,共1位
   填写〖阶码〗,其值为〖1000;0010〗,共8位
   填写〖尾数〗,其值为〖1010;1101;1111;1011;1110;011〗,共23位
   填写〖尾数〗时,小数点左边的〖1〗不需要
八.组合上面的结果,最后的结果就是
〖0100;0001;0101;0110;1111;1101;1111;0011〗,共32位
   十进制结果为〖65;86;253;243〗
   十六进制结果为〖41;56;FD;F3〗

终于转换好了,累啊,结果对不对呢?用VC来检查一下。
结果怎么样?好象不对,为什么VC里面的值是〖41;56;FD;F4〗,比我们手工计算的
大1?我们计算错了?其实不是,只不过我们最后还没有进行〖舍入〗处理。〖舍入〗的原则就是〖0舍1入〗
九.舍入处理
   在第四步中为数的结果是1.1010;1101;1111;1011;1110;0111;01
   在第八步中,组合整个数值的时候,把最后3位〖101〗给去除了
   这时的舍入就要根据这个被去除的数值的最高一位来处理,如果最高一位是〖1〗,最后
   的结果要加上1,如果最高一位是〖0〗,最后的结果不变。这就是〖0舍1入〗
   所以在VC中看到的结果会比我们手动计算的大1。好了,最后舍入处理结束后,最后正
   确的结果就是〖0100;0001;0101;0110;1111;1101;1111;0100〗

以上就是十进制实数转换成32位二进制数的全过程了,可能有些地方写得不够清楚,望大家谅解。:D

puchonghui 发表于 2008-1-9 20:53:15

。。。。。。。。
过程我是看懂了
但是其实大部分都没懂-_-

唔。。。那么我说下懂的东西

先说明下啥叫浮点数
所谓的浮点数就是指小数点在逻辑上是不固定的
与此相对的是定点数
浮点数里的整数是特殊情况,小数点在最后
(IEEE有个浮点标准,有兴趣可以去查下,这种东西我是背不出的:$ )

然后贴一段小数转二进制的问题,估计好多人不是很明白,至少我读书那会儿,学校里是从来不讲解小数如何表示的问题的。
具体的公式不一定要去记,但是要知道大概的过程是咋回事,事实上在我的开发经验中,类似的bug在设计中还是比较常见的,甚至有些人做到了高级技术人员对这个问题还是一无所知。

下面我仅以float(带符号,单精度,32位)类型的浮点数说明C++中的浮点数是如何在内存中表示的。先讲一下基础知识,纯小数的二进制表示。(纯小数就是没有整数部分的小数,讲给小学没好好学的人)
纯小数要想用二进制表示,必须先进行规格化,即化为 1.xxxxx * ( 2 ^ n ) 的形式(“^”代表乘方,2 ^ n表示2的n次方)。对于一个纯小数D,求n的公式如下:
n = 1 + log2(D);// 纯小数求得的n必为负数
再用 D / ( 2 ^ n ) 就可以得到规格化后的小数了。接下来就是十进制到二进制的转化问题,为了更好的理解,先来看一下10进制的纯小数是怎么表示的,假设有纯小数D,它小数点后的每一位数字按顺序形成一个集合:
{k1, k2, k3, ... , kn}
那么D又可以这样表示:
D = k1 / (10 ^ 1 ) + k2 / (10 ^ 2 ) + k3 / (10 ^ 3 ) + ... + kn / (10 ^ n )
推广到二进制中,纯小数的表示法即为:
D = b1 / (2 ^ 1 ) + b2 / (2 ^ 2 ) + b3 / (2 ^ 3 ) + ... + bn / (2 ^ n )
现在问题就是怎样求得b1, b2, b3,……,bn。算法描述起来比较复杂,还是用数字来说话吧。声明一下,1 / ( 2 ^ n )这个数比较特殊,我称之为位阶值。
例如0.456,第1位,0.456小于位阶值0.5故为0;第2位,0.456大于位阶值0.25,该位为1,并将0.45减去0.25得0.206进下一位;第3位,0.206大于位阶值0.125,该位为1,并将0.206减去0.125得0.081进下一位;第4位,0.081大于0.0625,为1,并将0.081减去0.0625得0.0185进下一位;第5位0.0185小于0.03125……
最后把计算得到的足够多的1和0按位顺序组合起来,就得到了一个比较精确的用二进制表示的纯小数了,同时精度问题也就由此产生,许多数都是无法在有限的n内完全精确的表示出来的,我们只能利用更大的n值来更精确的表示这个数,这就是为什么在许多领域,程序员都更喜欢用double而不是float。

sundyhui0322 发表于 2008-6-1 19:27:44

我只会 整形的转换,c代码如下

#include "stdio.h"
#include "math.h"
main()
{
        void binary(int num);
    int num;
    printf("please enter a number:\n");
    scanf("%d",&num);
    printf("the binary of num is:\n");
    binary(num);
    printf("\n");

}
void binary(int num)
{
        int surplus,i=0,j,n,a;
        n=fabs(num);
        /*二进制算法:整数(正数)除以2其余数从末尾往前补*/
        while(n>=2)
        {
                surplus=n%2;
                n/=2;
                a=surplus;
                i++;
        }
        a=n;
        /*余下的位置补0*/
        for(j=i+1;j<32;j++)
           a=0;
        /*输出二进制表示,正数则倒序输出,负数则取反*/
        if(num>0)
          for(i=31;i>=0;i--)
          printf("%d",a);
        if(num<0)
          for(i=31;i>=0;i--)
          {
                  a=fabs(a-1);
                printf("%d",a);
          }
          
}
页: [1]
查看完整版本: 如何把十进制实数转换成32位二进制数