C 显式int32的规则->;浮式铸造

C 显式int32的规则->;浮式铸造,c,casting,integer,floating-point,C,Casting,Integer,Floating Point,我的家庭作业是模拟浮点型转换,例如: int y = /* ... */; float x = (float)(y); 。但显然没有使用铸造。这很好,我也不会有问题,除非我找不到任何具体的定义来说明这种类型的转换应该如何操作 我已经编写了一个工作相当好的实现,但它有时并不完全匹配(例如,它可能会在指数中输入值3并用1填充尾数,但“基本真理”在指数中的值为4并用0填充尾数)。事实上,这两者是等价的(sorta,通过无限级数),这是令人沮丧的,因为位模式仍然是“错误的” 当然,我从分散的网站上得到

我的家庭作业是模拟浮点型转换,例如:

int y = /* ... */;
float x = (float)(y);
。但显然没有使用铸造。这很好,我也不会有问题,除非我找不到任何具体的定义来说明这种类型的转换应该如何操作

我已经编写了一个工作相当好的实现,但它有时并不完全匹配(例如,它可能会在指数中输入值3并用1填充尾数,但“基本真理”在指数中的值为4并用0填充尾数)。事实上,这两者是等价的(sorta,通过无限级数),这是令人沮丧的,因为位模式仍然是“错误的”

当然,我从分散的网站上得到了模糊的东西,比如“向零进发”,但老实说,我的搜索总是被C类新手的问题堵塞(例如,“演员阵容是什么?”,“我什么时候用它?”)。所以,我找不到一个通用的规则来明确定义指数和尾数

帮忙?谢谢,

Ian

我看到了你的问题,还记得我很久以前写的一些浮点仿真代码。首先是一条非常重要的关于浮点数的建议。阅读,这是一本很好的完整的主题指南

至于我的代码,我到处翻找并找到了它,但我必须警告你,它很难看,因为它是为一个个人项目(我的本科论文)写的,所以没有正确的注释。此外,代码可能具有某些特殊性,因为它针对的是嵌入式系统(机器人)。指向解释项目并具有代码下载链接的页面的链接为。不要介意网站,恐怕我不是网页设计师:)

这就是我在该项目中表示浮点的方式:

typedef struct
{
    union{
        struct {
           unsigned long mantissa: 23;
           unsigned long exponent: 8;
           unsigned long sign: 1;
       } float_parts;   //the struct shares same memory space as the float
                        //allowing us to access its parts with the bitfields

        float all;

    };

}_float __attribute__((__packed__));
它使用的解释我猜超出了主题范围,所以如果你想了解更多信息,请参考链接

我想你会对这个函数感兴趣。请注意,代码编写得不是很好,我已经多年没有看过它了。还请注意,因为我只针对特定机器人的架构,所以代码没有检查endianess。但无论如何,我希望它对你有用

_float intToFloat(int number)
{
    int i;
    //will hold the resulting float
    _float result;

    //depending on the number's sign determine the floating number's sign
    if(number > 0)
        result.float_parts.sign = 0;
    else if(number < 0)
    {
        number *= -1; //since it would have been in twos complements
                     //being negative and all
        result.float_parts.sign = 1;
    }
    else // 0 is kind of a special case
    {
        parseFloat(0.0,&result);
        return result;
    }

    //get the individual bytes (not considering endiannes here, since it is for the robot only for now)
    unsigned char* bytes= (unsigned char*)&number;

    //we have to get the most significant bit of the int
    for(i = 31; i >=0; i --)
    {
        if(bytes[i/8] & (0x01 << (i-((i/8)*8))))
            break;
    }


    //and adding the bias, input it into the exponent of the float
    //because the exponent says where the decimal (or binary) point is placed relative to the beginning of the mantissa
    result.float_parts.exponent = i+127;


    //now let's prepare for mantissa calculation
    result.float_parts.mantissa = (bytes[2] <<  16 | bytes[1] << 8 | bytes[0]);

    //actual calculation of the mantissa
    i= 0;
    while(!(result.float_parts.mantissa & (0x01<<22)) && i<23) //the i is to make sure that
    {                                                          //for all zero mantissas we don't
        result.float_parts.mantissa <<=1;                      //get infinite loop
        i++;
    }
    result.float_parts.mantissa <<=1;


    //finally we got the number
    return result;
}
\u浮点intToFloat(整数)
{
int i;
//将保留生成的浮动
_浮动结果;
//根据数字的符号确定浮点数的符号
如果(数字>0)
result.float_parts.sign=0;
否则如果(数字<0)
{
number*=-1;//因为它应该是两个补码
//消极的
result.float_parts.sign=1;
}
else//0是一种特殊情况
{
parseFloat(0.0和结果);
返回结果;
}
//获取单个字节(此处不考虑endiannes,因为它仅适用于机器人)
无符号字符*字节=(无符号字符*)&数字;
//我们必须得到int的最高有效位
对于(i=31;i>=0;i--)
{

如果(bytes[i/8]&(0x01,因为这是家庭作业,我将只发布一些我认为棘手的部分的注释-当整数的大小大于浮点的精度时进行舍入。听起来你已经有了获得指数和尾数的基本解决方案

我将假设您的浮点表示是IEEE 754,并且舍入的执行方式与MSVC和MinGW相同:使用“银行家舍入”方案(老实说,我不确定该特定舍入方案是否是标准所要求的;不过这是我测试的结果)。剩下的讨论假定int的转换大于
0
。负数可以通过处理其绝对值并在末尾设置符号位来处理。当然,
0
在任何情况下都需要特别处理(因为找不到msb)

由于尾数中有24位精度(包括msb的隐含
1
),因此整数最多为
16777215
(或
0x00ffffff
)可以精确地表示。没有什么特别的事情要做,除了通过位移位把东西放到正确的位置,并根据移位计算出正确的指数

但是,如果int值的精度超过24位,则需要舍入。我使用以下步骤执行舍入:

  • 如果丢弃位的msb为
    0
    ,则无需执行更多操作。尾数和指数可以单独使用
  • 如果已删除位的msb为
    1
    ,而其余已删除位设置了一个或多个位,则尾数需要递增。如果尾数溢出(超过24位,假设尚未删除隐含的msb),则尾数需要右移,且指数递增
  • 如果已删除位的msb为1,而其余已删除位均为
    0
    ,则仅当lsb为
    1
    时,尾数才会增加。处理尾数溢出的方法与案例2类似

由于尾数增量只有在全部为
1
时才会溢出,如果您没有携带尾数的msb(即,如果您已经丢弃了它,因为它将在最终浮点表示中丢弃),那么尾数增量溢出的情况可以通过简单地将尾数设置为零并增加指数来解决。

感谢大家提供的非常有用的帮助!尤其是四舍五入规则特别有用

我很高兴地说,在这个问题的回答的帮助下,所有光荣的人们,我成功地实现了这个功能。我的最终功能是:

unsigned float_i2f(int x) {
    /* Apply a complex series of operations to make the cast.  Rounding was achieved with the help of my post http://stackoverflow.com/questions/9288241/rules-for-explicit-int32-float32-casting. */
    int sign, exponent, y;
    int shift, shift_is_pos, shifted_x, deshifted_x, dropped;
    int mantissa;

    if (x==0) return 0;

    sign = x<0 ? 0x80000000 : 0; //extract sign
    x = sign ? -x : x; //absolute value, sorta

    //Check how big the exponent needs to be to offset the necessary shift to the mantissa.
    exponent = 0;
    y = x;
    while (y/=2) {
        ++exponent;
    }

    shift = exponent - 23; shift_is_pos = shift >= 0; //How much to shift x to get the mantissa, and whether that shift is left or right.

    shifted_x = (shift_is_pos ? (x>>shift) : (x<<-shift)); //Shift x
    deshifted_x = (shift_is_pos ? (shifted_x<<shift) : (shifted_x>>-shift)); //Unshift it (fills right with zeros)
    dropped = x - deshifted_x; //Subtract the difference.  This gives the rounding error.

    mantissa = 0x007FFFFF & shifted_x; //Remove leading MSB (it is represented implicitly)

    //It is only possible for bits to have been dropped if the shift was positive (right).
    if (shift_is_pos) {
        //We dropped some bits.  Rounding may be necessary.
        if ((0x01<<(shift-1))&dropped ) {
            //The MSB of the dropped bits is 1.  Rounding may be necessary.

            //Kill the MSB of the dropped bits (taking into account hardware ignoring 32 bit shifts).
            if (shift==1) dropped = 0;
            else dropped <<= 33-shift;

            if (dropped) {
                //The remaining dropped bits have one or more bits set.
                goto INC_MANTISSA;
            }
            //The remaining dropped bits are all 0
            else if (mantissa&0x01) {
                //LSB is 1
                goto INC_MANTISSA;
            }
        }
    }

    //No rounding is necessary
    goto CONTINUE;

    //For incrementing the mantissa.  Handles overflow by incrementing the exponent and setting the mantissa to 0.
INC_MANTISSA:
    ++mantissa;
    if (mantissa&(0x00800000)) {
        mantissa = 0;
        ++exponent;
    }

    //Resuming normal program flow.
CONTINUE:
    exponent += 127; //Bias the exponent

    return sign | (exponent<<23) | mantissa; //Or it all together and return.
}
unsigned float_i2f(int x){
/*应用一系列复杂的操作来制作石膏。在我的帖子的帮助下,实现了四舍五入http://stackoverflow.com/questions/92882