首页 文章

如何仅使用整数运算生成IEEE 754单精度浮点数?

提问于
浏览
0

假设没有浮点运算的低端微处理器,我需要生成一个IEE754单精度浮点格式数来推送到文件 .

我需要编写一个函数,它将三个整数作为符号,整数和分数,并返回一个字节数组,其中4个字节是IEEE 754单精度表示 .

就像是:

// Convert 75.65 to 4 byte IEEE 754 single precision representation
char* float = convert(0, 75, 65);

有没有人有任何指针或示例C代码?我特别努力了解如何转换尾数 .

5 回答

  • 1

    您需要生成符号(1位),指数(8位,2的偏置幂)和分数/尾数(23位) .

    请记住,该分数具有隐含的前导'1'位,这意味着最重要的前导'1'位(2 ^ 22)不以IEEE格式存储 . 例如,给定一小部分0x755555(24位),存储的实际位将为0x355555(23位) .

    还要记住,分数被移位,以便二进制点紧靠隐含的前导'1'位的右侧 . 因此IEEE 11位11 0101 0101 ...表示24位二进制分数1.11 0101 0101 ......这意味着必须相应地调整指数 .

  • 0

    值是否必须写成大端或小端?反转位排序?

    如果您是自由的,您应该考虑将值写为字符串文字 . 这样你就可以轻松转换整数:只需编写int部分并将“e0”写为指数(或省略指数并写入“.0”) .

    对于二进制表示,您应该看一下Wikipedia . 最好是首先将位域组装成 uint32_t - 结构在链接文章中给出 . 请注意,如果整数值超过23位,则可能必须舍入 . 请记住规范化生成的值 .

    第二步是将 uint32_t 序列化为 uint8_t -array . 记住结果的结束!

    另请注意,如果您真的需要8位值,请使用 uint8_t 作为结果;你应该使用无符号类型 . 对于中间表示,建议使用 uint32_t ,因为这将保证您在32位值上运行 .

  • 0

    你没有去过,所以没有放弃 .

    请记住,您可以将两个32位整数a和b视为十进制a.b,作为单个64位整数,指数为2 ^ -32(其中^为指数) .

    因此,如果没有做任何事情你就会在表格中得到它:

    s * m * 2^e
    

    唯一的问题是你的尾数太长而你的号码没有标准化 .

    通过可能的舍入步骤进行一些移位和加/减,你就完成了 .

  • 0

    您可以使用软件浮点编译器/库 .
    https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html

  • 0

    基本前提是:

    • 鉴于binary32 float .

    • 形成组合 whole 和派系部分 hundredths 的二进制定点表示 . 此代码使用分别编码整数和百分之一字段的结构 . 重要的是 whole 字段至少为32位 .

    • 左/右移位(* 2和/ 2),直到MSbit处于隐含位位置,同时计算移位 . 一个强大的解决方案还会注意到非零位移出 .

    • 形成有偏见的指数 .

    • 圆形尾数和下降隐含位 .

    • 表格标志(此处未完成) .

    • 结合以上3个步骤形成答案 .

    • 作为子法线,infinites和Not-A-Number不会产生 whole, hundredths 输入,生成那些 float 特殊情况不在这里解决 .

    .

    #include <assert.h>
    #include <stdint.h>
    #define IMPLIED_BIT 0x00800000L
    
    typedef struct {
      int_least32_t whole;
      int hundreth;
    } x_xx;
    
    int_least32_t covert(int whole, int hundreth) {
      assert(whole >= 0 && hundreth >= 0 && hundreth < 100);
      if (whole == 0 && hundreth == 0) return 0;
      x_xx x = { whole, hundreth };
      int_least32_t expo = 0;
      int sticky_bit = 0; // Note any 1 bits shifted out
      while (x.whole >= IMPLIED_BIT * 2) {
        expo++;
        sticky_bit |= x.hundreth % 2;
        x.hundreth /= 2;
        x.hundreth += (x.whole % 2)*(100/2);
        x.whole /= 2;
      }
      while (x.whole < IMPLIED_BIT) {
        expo--;
        x.hundreth *= 2;
        x.whole *= 2;
        x.whole += x.hundreth / 100;
        x.hundreth %= 100;
      }
      int32_t mantissa = x.whole;
      // Round to nearest - ties to even
      if (x.hundreth >= 100/2 && (x.hundreth > 100/2 || x.whole%2 || sticky_bit)) {
        mantissa++;
      }
      if (mantissa >= (IMPLIED_BIT * 2)) {
        mantissa /= 2;
        expo++;
      }
      mantissa &= ~IMPLIED_BIT;  // Toss MSbit as it is implied in final
      expo += 24 + 126; // Bias: 24 bits + binary32 bias
      expo <<= 23; // Offset
      return expo | mantissa;
    }
    
    void test_covert(int whole, int hundreths) {
      union {
        uint32_t u32;
        float f;
      } u;
      u.u32 = covert(whole, hundreths);
      volatile float best = whole + hundreths / 100.0;
      printf("%10d.%02d --> %15.6e %15.6e Same:%d\n", whole, hundreths, u.f, best,
          best == u.f);
    }
    
    #include <limits.h>
    int main(void) {
      test_covert(75, 65);
      test_covert(0, 1);
      test_covert(INT_MAX, 99);
      return 0;
    
    }
    

    产量

    75.65 -->    7.565000e+01    7.565000e+01 Same:1
             0.01 -->    1.000000e-02    1.000000e-02 Same:1
    2147483647.99 -->    2.147484e+09    2.147484e+09 Same:1
    

    已知问题:未应用签名 .

相关问题