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

发布于 2025-01-01 09:06:41 字数 669 浏览 2 评论 0原文

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

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

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

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

接下来的 6 位是小数值。在这里我陷入了有效的实施。我可以一次提取一位,并构建分数 1/2*bit + 1/4+bit + 1/8*bit 等...但这效率不高。

float fractional = ?

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

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

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

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

编辑:当我的意思是“AND”时,我写了“OR”

I am uncompressing some data from double words.

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

My first 14 MSB are an int value. I plan to extract them using a bitwise AND with 0xFFFC.

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

My next 6 bits are a fractional value. Here I am stuck on an efficient implementation. I could extract one bit at a time, and build the fraction 1/2*bit + 1/4+bit + 1/8*bit etc ... but that's not efficient.

float fractional = ?

The last 12 LSB are another int value, which I feel I can pull out using bitwise AND again.

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

This operation will be done on 16348 double words and needs to be finished within 0.05 ms to run at least 20Hz.

I am very new to bit operations, but I'm excited to learn. Reading material and/or examples would be greatly appreciated!

Edit: I wrote OR when I meant AND

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

时光与爱终年不遇 2025-01-08 09:06:41

由于您从 [最高有效字节的地址] 开始并使用从那里开始递增的地址,因此您的数据显然采用 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];

Since you're starting with [address of most significant byte] and using increasing addresses from there, your data is apparently in Big-Endian byte order. Casting pointers will therefore fail on nearly all desktop machines, which use Little-Endian byte order.

The following code will work, regardless of native byte order:

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];
奢望 2025-01-08 09:06:41

首先,您可以更有效地将双字一次性全部放入 int 中,并从那里进行掩码/移位。

从中获取小数部分很容易:掩码和移位以获得整数,然后除以浮点数以缩放结果。

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

Firstly you'd be more efficient getting the double-word all at once into an int and masking/shifting from there.

Getting the fractional part from that is easy: mask and shift to get an integer, then divide by a float to scale the result.

float fractional = ((current_int >> 12) & 0x3f) / 64.;
荒岛晴空 2025-01-08 09:06:41

移位指令有 5 种:

  1. 带符号扩展右移:将所有位右移后,将当前最左边的位复制为新的位到最左边。最右边的一个被丢弃。
  2. 零扩展右移:与 (1) 相同,但假设新的最左边位始终为零。
  3. 左移:将 (1) 和 (2) 中的 right 替换为 left ,将 left 替换为 right 并读取 ( 2)再次。
  4. 向右滚动:将您的位向右移动,而不是最右边的一位下降,它变成您的最左边。
  5. 向左滚动:将(4)中的替换为,将替换为,然后再次阅读(4)。

您可以根据需要多次移动。在 C 中,数据类型中未定义的位数不止是位数。尽管语法相同,但无符号和有符号类型的转换方式不同。

there are 5 kinds of shift instructions:

  1. Shift right with sign extend: It will copy your current leftmost bit as the new bit to the leftmost after shifting all the bits to the right. Rightmost one gets dropped.
  2. Shift right with zero extend: Same as (1) but assume that your new leftmost bit is always zero.
  3. Shift left: replace right in (1) and (2) with left , left with right and read (2) again.
  4. Roll right: Shift your bits to the right, instead of rightmost one dropping, it becomes your leftmost.
  5. Roll left: Replace right in (4) with left , left with right and read (4) again.

You can shift as many times you want. In C, more than the amount of bits in your datatype is undefined. Unsigned and signed types shift differently although the syntax is same.

最单纯的乌龟 2025-01-08 09:06:41

如果您将数据读取为 unsigned char *,则一次无法获取超过 8 位的数据,并且您的示例需要更改。如果您的地址是对齐的,或者您的平台允许,您应该以 int * 的形式读取数据,但这也引出了数据如何存储的问题。它是每个整数存储 20 位以及 12 位其他信息,还是需要跟踪位指针的 20 位流。如果是第二种,它比你想象的还要复杂。一旦我了解了您的数据在 RAM 中的布局方式,我将进一步发布。

If you are reading your data as unsigned char *, you are not going to be able to get more than 8-bits at a time of data and your example needs to change. If your address is aligned, or your platform allows, you should read your data in as an int *, but then that also begs the question of just how your data is stored. Is it stored 20-bits per integer with 12-bits of other info, or is it a 20-bit stream where you need to keep track of your bit pointer. If the second, it's even more complex than you realize. I'll post further once I have a feel for how your data is laid out in RAM.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文