警告:我从未使用过 PDP-11,因此以下内容完全基于问题中链接的文档。
PDP-11 是使用 16 位字的 16 位机器。32 位单精度浮点数据以“混合端”格式存储:高位字存储在低位地址,但在每个字中,低位字节存储在低位地址。也就是说,按照地址递增的顺序,四个字节按2、3、0、1的顺序存储。
PDP-11 浮点格式类似于 IEEE-754binary32
格式,使用具有 8 个指数位和一个有效位(尾数)的符号幅度表示,其最高有效位假定为 1,因此不存储。IEEE-754 的指数偏差为 128 而不是 127,binary32
有效数被标准化为 [0.5, 1) 而不是 IEEE-754 的 [1, 2) binary32
。此外,不支持次正规、无穷大和 NaN。
这意味着转换永远不会溢出,但它可能会下溢(伴随着精度的潜在降低)到 IEEE-754binary
次规范。以下程序假设我们在具有 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