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

how to display DEC floating point format given 32 bits in IEEE standard

我目前获得了 32 位数据,这些数据采用数字设备公司 (DEC) 浮点格式或 PDP-11(或 fp-11)。数据以小端形式给出。在 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 方面,以及如何将其转化为 printf 的人类可读格式。这是我到目前为止尝试过的:

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, 0x00, 0x00, 0x00}, // smallest normal
                           {0x7f, 0x00, 0x00, 0x00}, // pseudo-zero
                           {0x00, 0x00, 0x00, 0x00}, // true zero
                           {0xff, 0xff, 0xff, 0xff}, // -largest normal
                           {0x80, 0xc0, 0x00, 0x00}, // -1.0f
                           {0x80, 0x80, 0x00, 0x00}, // -smallest normal
                           {0x7f, 0x80, 0x00, 0x00}, // -pseudo-zero
                           {0x00, 0x80, 0x00, 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