如何显示IEEE标准中给定的32位DEC浮点格式

问题描述

我目前获得了数字设备公司(DEC)浮点格式或PDP-11(或fp-11)的32位数据。数据以小尾数形式给出。在C语言中,如何从中获得常规的IEEE-754单精度浮点数?

我找到了一些参考,但它们非常令人困惑: http://home.kpn.nl/jhm.bonten/computers/bitsandbytes/wordsizes/hidbit.htm

http://www.bitsavers.org/pdf/dec/pdp11/1160/EK-FP11E-UG-001_FP11-E_Users_Guide_Dec77.pdf

编辑:(回应评论) 通过混淆,我指的是符合little endian的msb和lsb方面,以及如何将其转换为可打印格式的可读格式。这是我到目前为止尝试过的:

float getLatitude(){
    uint16_t lat1 = ((0x0000 | rx_data[32]) << 8)| rx_data[31];
    uint16_t lat2 = ((0x0000 | rx_data[34]) << 8)| rx_data[33];
    uint32_t lat = (0x00000000 | lat1 << 16) | lat2;
    uint8_t ex = (lat >> 23) & 0xFF;
    uint32_t frac = lat & 0x7FFFFF;
    float latitude = 
    if(((lat & 0x80000000) >> 31) == 1){latitude = latitude * -1}
    return latitude;
}

解决方法

注意:我从未使用过PDP-11,因此以下内容完全基于问题中链接的文档。

PDP-11是使用16位字的16位计算机。 32位单精度浮点数据以“混合字节序”格式存储:较高位的字存储在低位地址,但是在每个字内,较低位的字节存储在低位地址。换句话说,以地址增加的顺序,四个字节以2、3、0、1的顺序存储。

PDP-11浮点格式类似于IEEE-754 binary32格式,使用具有八个指数位和一个最高有效位为1的有效位(尾数)的符号幅度表示。因此不存储。对于IEEE-754 binary32,指数偏差是128,而不是127;对于IEEE-754 binary32,有效数被标准化为[0.5,1)而不是[1,2)。另外,不支持次法线,无穷和NaN。

这意味着转换永远不会溢出,但可能会下溢(随之而来的是精度降低)到IEEE-754 binary次规范。以下程序假定我们在具有IEEE-754浮点数的计算机上运行,​​并以PDP-11浮点数数据按字节顺序以内存顺序显示。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <limits.h>
#include <math.h>

float uint32_as_float (uint32_t a)
{
    float r;
    memcpy (&r,&a,sizeof r);
    return r;
}

float single_precision_pdp11_to_ieee754 (uint8_t *data)
{
    /* mixed-endian: more significant word at lower address,but within word less significant byte at lower address
    */
    uint32_t raw = (((uint32_t)data[0] << 2 * CHAR_BIT) |
                    ((uint32_t)data[1] << 3 * CHAR_BIT) |
                    ((uint32_t)data[2] << 0 * CHAR_BIT) |
                    ((uint32_t)data[3] << 1 * CHAR_BIT));
    uint32_t expo = (raw >> 23) & 0xff;
    float res;

    if (expo == 0x00) {
        res = copysignf (0.0f,uint32_as_float (raw));
    } else if (expo == 0xff) {
        raw = raw - (2 << 23); // decrement exponent by 2
        res = uint32_as_float (raw);
    } else {
        res = 0.25f * uint32_as_float (raw);
    }
    return res;
}

int main (void)
{
    uint8_t data[11][4] = {{0xff,0x7f,0xff,0xff},// largest normal
                           {0x80,0x40,0x00,0x00},// 1.0f
                           {0x80,// smallest normal
                           {0x7f,// pseudo-zero
                           {0x00,// true zero
                           {0xff,// -largest normal
                           {0x80,0xc0,// -1.0f
                           {0x80,0x80,// -smallest normal
                           {0x7f,// -pseudo-zero
                           {0x00,// -true zero
                           {0x3F,0x16,0x9E,0xB3}};// from question

    printf ("% 15.8e\n",single_precision_pdp11_to_ieee754 (data[0]));
    printf ("% 15.8e\n",single_precision_pdp11_to_ieee754 (data[1]));
    printf ("% 15.8e\n",single_precision_pdp11_to_ieee754 (data[2]));
    printf ("% 15.8e\n",single_precision_pdp11_to_ieee754 (data[3]));
    printf ("% 15.8e\n",single_precision_pdp11_to_ieee754 (data[4]));
    printf ("% 15.8e\n",single_precision_pdp11_to_ieee754 (data[5]));
    printf ("% 15.8e\n",single_precision_pdp11_to_ieee754 (data[6]));
    printf ("% 15.8e\n",single_precision_pdp11_to_ieee754 (data[7]));
    printf ("% 15.8e\n",single_precision_pdp11_to_ieee754 (data[8]));
    printf ("% 15.8e\n",single_precision_pdp11_to_ieee754 (data[9]));
    printf ("% 15.8e\n",single_precision_pdp11_to_ieee754 (data[10]));
    return EXIT_SUCCESS;
}

以上程序的输出应类似于以下内容:

 1.70141173e+038
 1.00000000e+000
 2.93873588e-039
 0.00000000e+000
 0.00000000e+000
-1.70141173e+038
-1.00000000e+000
-2.93873588e-039
-0.00000000e+000
-0.00000000e+000
 3.87138358e-026