将int转换为float时在后台会发生什么

时间:2011-11-02 08:00:54

标签: c floating-point int

我对如何逐步将int转换为float进行了一些了解?假设我有一个二进制格式的带符号整数。而且,我想把它用手漂浮。但是,我不能。因此,CAn会告诉我如何逐步进行转换?

我在c中进行多次转换?等;

  int a = foo ( );
  float f = ( float ) a ;

但是,我还没弄清楚背景会发生什么。此外,为了更好地理解,我想手工完成转换。

编辑:如果你对转换了解很多,你也可以提供有关浮动到双转换的信息。而且,对于浮动到int

2 个答案:

答案 0 :(得分:13)

浮点值(IEEE754,无论如何)基本上有三个组成部分:

  • 一个标志s;
  • 一系列指数位e;和
  • 一系列尾数位m

精度指示指数和尾数有多少位可用。让我们检查单精度浮点的值0.1:

s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm    1/n
0 01111011 10011001100110011001101
           ||||||||||||||||||||||+- 8388608
           |||||||||||||||||||||+-- 4194304
           ||||||||||||||||||||+--- 2097152
           |||||||||||||||||||+---- 1048576
           ||||||||||||||||||+-----  524288
           |||||||||||||||||+------  262144
           ||||||||||||||||+-------  131072
           |||||||||||||||+--------   65536
           ||||||||||||||+---------   32768
           |||||||||||||+----------   16384
           ||||||||||||+-----------    8192
           |||||||||||+------------    4096
           ||||||||||+-------------    2048
           |||||||||+--------------    1024
           ||||||||+---------------     512
           |||||||+----------------     256
           ||||||+-----------------     128
           |||||+------------------      64
           ||||+-------------------      32
           |||+--------------------      16
           ||+---------------------       8
           |+----------------------       4
           +-----------------------       2

标志是积极的,这很容易。

指数为64+32+16+8+2+1 = 123 - 127 bias = -4,因此乘数为2 -4 1/16。偏差是存在的,这样你就可以获得非常小的数字(例如10 -30 )以及大数字。

尾数很粗糙。它由1(隐式基数)加上(对于所有这些位,每个位值为1 /(2 n ),因为n1开始,增加到右边),{1/2, 1/16, 1/32, 1/256, 1/512, 1/4096, 1/8192, 1/65536, 1/131072, 1/1048576, 1/2097152, 1/8388608}

当您添加所有这些内容时,您会获得1.60000002384185791015625

当你乘以2 -4 乘数时,得到0.100000001490116119384765625,这就是为什么他们说你不能完全将0.1表示为IEEE754浮点数。

整数转换为浮点数而言,如果尾数中包含多个位(包括隐式1),则只需传输整数位模式并选择正确的指数。不会有精度损失。例如,双精度IEEE754(64位,其中52/53为尾数)对32位整数没有任何问题。

如果整数中有更多位(例如32位整数和32位单精度浮点数,只有23/24位尾数),则需要缩放整数。

这涉及剥离最低有效位(实际舍入),以使其适合尾数位。这当然会导致精度损失,但这是不可避免的。


让我们看一下特定的值123456789。以下程序转储每种数据类型的位。

#include <stdio.h>

static void dumpBits (char *desc, unsigned char *addr, size_t sz) {
    unsigned char mask;
    printf ("%s:\n  ", desc);
    while (sz-- != 0) {
        putchar (' ');
        for (mask = 0x80; mask > 0; mask >>= 1, addr++)
            if (((addr[sz]) & mask) == 0)
                putchar ('0');
            else
                putchar ('1');
    }
    putchar ('\n');
}

int main (void) {
    int intNum = 123456789;
    float fltNum = intNum;
    double dblNum = intNum;

    printf ("%d %f %f\n",intNum, fltNum, dblNum);
    dumpBits ("Integer", (unsigned char *)(&intNum), sizeof (int));
    dumpBits ("Float", (unsigned char *)(&fltNum), sizeof (float));
    dumpBits ("Double", (unsigned char *)(&dblNum), sizeof (double));

    return 0;
}

我系统的输出如下:

123456789 123456792.000000 123456789.000000
integer:
   00000111 01011011 11001101 00010101
float:
   01001100 11101011 01111001 10100011
double:
   01000001 10011101 01101111 00110100 01010100 00000000 00000000 00000000

我们会一次看这些。首先是两个整数,简单的幂:

   00000111 01011011 11001101 00010101
        |||  | || || ||  || |    | | +->          1
        |||  | || || ||  || |    | +--->          4
        |||  | || || ||  || |    +----->         16
        |||  | || || ||  || +---------->        256
        |||  | || || ||  |+------------>       1024
        |||  | || || ||  +------------->       2048
        |||  | || || |+---------------->      16384
        |||  | || || +----------------->      32768
        |||  | || |+------------------->      65536
        |||  | || +-------------------->     131072
        |||  | |+---------------------->     524288
        |||  | +----------------------->    1048576
        |||  +------------------------->    4194304
        ||+---------------------------->   16777216
        |+----------------------------->   33554432
        +------------------------------>   67108864
                                         ==========
                                          123456789

现在让我们看一下单精度浮点数。注意尾数的匹配模式匹配整数作为近乎完美的匹配:

mantissa:       11 01011011 11001101 00011    (spaced out).
integer:  00000111 01011011 11001101 00010101 (untouched).

在尾数的左边有一个隐式的 1位,它在另一端也被舍入,这是精度损失的来源(值从{改变) {1}}至123456789,与上述程序的输出相同。)

计算出值:

123456792

标志是积极的。指数为s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm 1/n 0 10011001 11010110111100110100011 || | || |||| || | |+- 8388608 || | || |||| || | +-- 4194304 || | || |||| || +------ 262144 || | || |||| |+-------- 65536 || | || |||| +--------- 32768 || | || |||+------------ 4096 || | || ||+------------- 2048 || | || |+-------------- 1024 || | || +--------------- 512 || | |+----------------- 128 || | +------------------ 64 || +-------------------- 16 |+---------------------- 4 +----------------------- 2 ,因此乘数为2 26 128+16+8+1 = 153 - 127 bias = 26

尾数是67108864(隐含基数)加上(如上所述)1。当您添加所有这些内容时,您会获得{1/2, 1/4, 1/16, 1/64, 1/128, 1/512, 1/1024, 1/2048, 1/4096, 1/32768, 1/65536, 1/262144, 1/4194304, 1/8388608}

当你乘以2 26 乘数时,得到1.83964955806732177734375,与程序输出相同。

双位掩码输出为:

123456792

将要经历确定该野兽的价值的过程:-)但是,我显示整数格式旁边的尾数显示公共位表示:

s eeeeeeeeeee mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
0 10000011001 1101011011110011010001010100000000000000000000000000

您可以再次看到左侧隐含位的共性和右侧的更大位可用性,这就是为什么在这种情况下不会丢失精度。


就浮动和双打之间的转换而言,这也很容易理解。

首先必须检查特殊值,例如NaN和无穷大。这些由特殊的指数/尾数组合表示,并且可能更容易检测这些前置角度,以新格式生成等效物。

然后,在你从double到float的情况下,你显然可用的范围较小,因为指数中的位数较少。如果你的双倍超出浮动范围,你需要处理它。

假设它适合,那么你需要:

  • 指数指数(两种类型的偏差不同)。
  • 从尾数中复制尽可能多的位(如果需要,可以进行舍入)。
  • 用零位填充剩余的目标尾数(如果有的话)。

答案 1 :(得分:1)

概念上这很简单。 float(在IEEE 754-1985中)具有以下表示:

  • 1位符号
  • 8位指数(0表示非规范化数字,1表示-126,127表示0,255表示无穷大)
  • 23位尾数(跟随“1”的部分)

所以基本上是粗略的:

  • 确定数字的符号和大小
  • 找到24个最有效位,正确舍入
  • 调整指数
  • 将这三个部分编码为32位格式

实现自己的转换时,很容易测试,因为您只需将结果与内置类型转换运算符进行比较。