这里的线索是,Cinema 4D在 Commodore Amiga 平台上首次亮相,该平台使用 FFP 浮点格式,该格式似乎是为简单的软件仿真而设计的。Amiga ROM Kernel Reference Manual的第 35 章对此进行了解释:
尾数被认为是二进制定点分数;除了 0,它总是被归一化(尾数被移动并调整指数,因此尾数在其最高位置有一个 1 位)。因此,它表示小于 1 但大于或等于 1/2 的值。
指数是正确定位尾数以反映数字的真实算术值所需的二的幂。它以超 64 表示法保存,这意味着将二进制补码值向上调整 64,从而将 $40 (-64) 到 $3F (+63) 更改为 $00 到 $7F
0 的值定义为所有 32 位为 0
尾数位存储在最高有效三个字节中,而最低有效字节由最高有效位中的符号位和最低有效六位中的偏置指数组成。因此,除零外,32 位数字的数值x
为 (-1) x<7> * (x<31:8> / 2 24 ) * 2 (x<6:0> - 64)。
基于此,以下 ISO-C99 代码提供了一个函数,该函数decode_ffp()
返回以无符号 32 位整数形式提供的 FFP 浮点数的数值。请注意,伪零和非规范化编码的行为未定义,因为官方文档没有说明应如何处理它们。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
float decode_ffp (uint32_t a)
{
const uint32_t FFP_EXPO_BIAS = 64;
const uint32_t FFP_MANT_BITS = 24;
const uint32_t FFP_EXPO_BITS = 7;
const uint32_t FFP_EXPO_MASK = (1 << FFP_EXPO_BITS) - 1;
uint32_t mant = a >> (FFP_EXPO_BITS + 1);
uint32_t sign = (a >> FFP_EXPO_BITS) & 1;
int32_t expo = (a & FFP_EXPO_MASK) - FFP_EXPO_BIAS;
float val;
if (a == 0) {
val = 0.0f;
} else {
val = exp2f (expo) * mant / (1 << FFP_MANT_BITS);
val = (sign) ? (-val) : val;
}
return val;
}
int main (void)
{
uint32_t test_vec[] = {
0x00000000,
0x80000041,
0x80000042,
0x80000043,
0x80000044,
0x8000003F,
0x8000004F,
0xC0000041,
0xA0000042,
0x800000C1,
0xC00000C1,
0x800000C2,
0xC00000C2
};
int num_test_vec = sizeof test_vec / sizeof test_vec[0];
for (int i = 0; i < num_test_vec; i++) {
printf ("%08x ==> % 15.8e\n", test_vec[i], decode_ffp (test_vec[i]));
}
return EXIT_SUCCESS;
}