2015-06-11 40 views
0

假设一个没有浮点运算的低端微处理器,我需要生成一个IEE754单精度浮点格式的数字来推送到一个文件。如何仅使用整数算术生成IEEE 754单精度浮点数?

我需要编写一个函数,采用三个整数作为符号,整数和分数,并返回4个字节是所述IEEE 754单精度表示的字节数组。

喜欢的东西:

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

没有任何人有任何指针或C语言代码吗?我特别努力了解如何转换尾数。

+3

几乎所有的嵌入式编译器都内置了对IEEE浮点算法软件仿真的支持。即使是微小的8位MCU。你的目标是什么,你是否试图哄骗编译器为你做这件事?但是,您经常需要在编译器设置中明确启用此功能。 – doynax

+1

@doynax:这种库的问题是它们往往会膨胀产生的固件。对于小型MCU来说,这可以轻松地将二进制数翻倍。 – Olaf

+0

函数定义有问题:函数应该采用“符号,整数和百分之一”。说“分数”,只提供“65”给出分数的分子,但没有分母 - 除非当然,分母是暗示的100.否则,你如何编码'75.01'? – chux

回答

1

你将需要生成的符号(1位),指数(8个比特,2的偏置功率),并将级分/尾数(23位)。

记住,所述级分具有一个隐含的前导“1”位,这意味着,最显著导致“1”位(2^22)没有被存储在IEEE格式。例如,给定0x755555(24位)的一部分,存储的实际位数将是0x355555(23位)。

的同时也要记住的是,部分被移动,以使得二进制点是立即隐含领先的“1”位的右边。因此,IEEE 23位小数11 0101 0101 ...表示24位二进制小数1.11 0101 0101 ... 这意味着必须相应地调整指数。

0

这个值必须写成big endian还是little endian?颠倒位排序?

如果你是自由的,你应该想想写值作为字符串文字。这样你可以很容易地转换整数:只需写入int部分并将“e0”指定为指数(或者省略指数并写入“.0”)。

对于二进制表示,你应该看看Wikipedia。最好的方法是首先将位域组装成一个uint32_t - 结构在链接文章中给出。请注意,如果整数的值超过23位,则可能需要轮换。请记住规范化生成的值。

第二步将序列化uint32_tuint8_t-阵列。注意结果的永恒性!

如果您确实需要8位值,也请注意使用uint8_t作为结果;你应该使用一个无符号类型。对于中间表示,建议使用uint32_t,因为这可以保证您在32位值上运行。

+0

转换为字符串比位操作要贵一到两个数量级。 –

+0

取决于你如何实现这个部门(有10个常规部门的高度优化版本)。优点是你在二进制格式上是独立的。但是,我不提议 - 请注意“思考”。这是qhy我添加到二进制转换的基础知识。 – Olaf

0

你还没有去过,所以没有放弃。请记住,您可以将两个32位整数a & b解释为十进制a.b,因为它是指数为2^-32(其中^为指数)的单个64位整数。

所以没有做任何事情,你已经在形式得到它:

s * m * 2^e 

唯一的问题是你的尾数太长,你的号码是不归。

用一个可能的舍入步骤进行一些移位和加/减操作,就完成了。

+0

你为什么认为尾数太长? – Olaf

+0

@Olaf因为它是64位的。很明显,设置位的范围可能意味着它可以移位。但在我描述的原始形式中,在标准化的IEEE 75单精度浮点上有一个64位尾数标题为24位。 – Persixty

+1

对不起,我不清楚我的意思。为什么你认为它太长的OP?由于这是一个小型MCU,int可能只有16位(如果int16_t则为15)。有一小部分显然不超过128位(他似乎提供了1/100),它非常适合f32尾数。但显然他对他的问题失去了兴趣,所以让我们把它留在这里。 – Olaf

0

的基本前提是:

  1. 鉴于binary32float
  2. 形成组合的whole和派系零件hundredths的二进制定点表示。该代码使用分别编码整个和百分之一个字段的结构。重要的是,whole字段至少为32位。
  3. 左移/右移(* 2和/ 2)直到MSbit位于隐含位的位置,同时对移位进行计数。一个可靠的解决方案还会记录移出的非零位。
  4. 形成一个有偏指数。
  5. 圆形尾数和隐含位。
  6. 表单标志(这里没有完成)。
  7. 结合以上3个步骤形成答案。
  8. 作为子法线,infinites &非数字不会导致与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 

已知问题:登录不适用。

相关问题