使用 6 位设置浮点数的小数部分

Set A Float's Fractional Part Using 6 Bits

本文关键字:小数部 浮点数 设置 使用      更新时间:2023-10-16

我正在从双字中解压缩一些数据。

unsigned char * current_word = [address of most significant byte]

我的前14个MSB是一个int值。我计划使用0xFFFC的逐位AND来提取它们。

int value = (int)( (uint_16)current_word & 0xFFFC );

我接下来的6位是一个小数值。在这里,我被一个高效的实现所困扰。我可以一次提取一个比特,并构建分数1/2*比特+1/4+比特+1/8*比特等。。。但这并不有效。

float fractional = ?

最后12个LSB是另一个int值,我觉得我可以再次使用逐位AND来提取它。

int other_value = (int) ( (uint_16)current_word[2] & 0x0FFF );    

此操作将在16348个双字上完成,需要在0.05ms内完成才能运行至少20Hz。

我对钻头操作很陌生,但我很兴奋能学习。阅读材料和/或示例将不胜感激!

编辑:当我指的是AND 时,我写了OR

由于您从[address of most significant byte]开始并使用从那里开始增加的地址,因此您的数据显然是按Big Endian字节顺序排列的。因此,在几乎所有使用Little Endian字节顺序的台式机上,投射指针都会失败。

无论本机字节顺序如何,以下代码都可以工作:

int value = (current_word[0] << 6) | (current_word[1] >> 2);
double fractional = (current_word[1] & 0x03) / 4.0 + (current_word[2] & 0xF0) / 1024.0;
int other_value = (current_word[2] & 0x0F) << 8 | current_word[3];

首先,将双字同时放入int并从中屏蔽/移位会更有效。

从中得到分数部分很容易:掩码和移位得到一个整数,然后除以浮点值来缩放结果。

float fractional = ((current_int >> 12) & 0x3f) / 64.;

有5种移位指令:

  1. 符号扩展右移:在将所有位右移后,它会将当前最左边的位复制为最左边的新位。最右边的一个掉了
  2. 使用零扩展右移:与(1)相同,但假设新的最左边的位始终为零
  3. 向左移位:将(1)和(2)中的right替换为left,将left更改为right并再次读取(2)
  4. 向右滚动:将你的比特向右移动,而不是最右边的一个,它变成了你的最左边
  5. 向左滚动:用替换(4)中的,用替换并再次读取(4)

你可以随心所欲地变换。在C中,超过数据类型中的位数是未定义的。尽管语法相同,但无符号类型和有符号类型的偏移不同。

如果您将数据读取为无符号char*,则一次无法获得超过8位的数据,因此您的示例需要更改。如果你的地址是对齐的,或者你的平台允许,你应该以int*的形式读取数据,但这也引出了如何存储数据的问题。它是每个整数存储20位,还有12位其他信息,还是一个需要跟踪位指针的20位流。如果是第二个,它甚至比你意识到的更复杂。一旦我对你的数据在RAM中的布局有了感觉,我会进一步发布。