2012-01-30 86 views
0

我從雙字解壓縮一些數據。使用6位設置浮點數的小數部分

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

我的第14個MSB是一個int值。我打算使用帶有0xFFFC的按位來提取它們。

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

我的下一個6位是小數值。在這裏,我被困在一個有效的實現中。我可以一次提取一個位,然後構建分數1/2 *位+ 1/4 +位+1/8 *位等等,但這樣做效率不高。

float fractional = ? 

最後12 LSB是另一個int值,這是我覺得我可以拉出來使用逐又一次。

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

該操作將在16348雙字上完成,並且需要在0.05 ms內完成以至少運行20Hz。

我對位操作非常陌生,但我很高興能夠學習。閱讀材料和/或例子將不勝感激!

編輯:我寫了或當我的意思,

+0

你將指向整數,不這樣做。而是將'char *'轉換爲'unsigned *'並將其解引用。另外,根據您使用的處理器,它看起來像顛倒了字節順序。在這種情況下,您需要分別抓取每個字節(或其中的一部分),並將它們移到正確的位置。 – 2012-01-30 22:04:49

+0

我很困惑,你的靜態施法方法與我的方法有什麼不同? – Constantin 2012-01-30 22:08:47

+0

你的第二行代碼評估'(uint_16)current_word'。 'current_word'是一個地址(見代碼的第一行),你從地址中獲取14位,而不是從數據中獲取。你需要'*(uint_16 *)current_word'。除了使字節順序錯誤。 – 2012-01-30 22:09:49

回答

2

由於您從[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]; 
+0

哇,這太棒了。雖然我對字節順序感到困惑,但我可以谷歌。 – Constantin 2012-01-30 22:19:51

+0

我喜歡調整常量以避免輪班的方式。 – 2012-01-30 22:23:25

+0

@Mark:是的,但我一直在從小字節1中選取錯誤的2位作爲小數部分。 – 2012-01-30 22:32:01

0

有5種移位指令:

  1. 右移帶符號的擴展:將當前的最左邊位複製爲新位到將所有位移到最右邊後最左邊。最右邊的一個被丟棄。
  2. 向右移動零擴展:與(1)相同,但假定您的新最左邊位始終爲零。
  3. 左移:取代在(1)和(2)與和讀(2)一次。
  4. 向右滾動:將您的位移到右側,而不是最右側的位置,它會成爲您的最左側。
  5. 卷左:更換(4)留下和閱讀(4)一次。

您可以多次換班。在C中,超過數據類型的位數是未定義的。雖然語法相同,但無符號和有符號類型的轉換方式不同。

+0

FWIW,我知道它是左轉,右轉,左轉,右轉。 – 2012-01-30 21:51:46

+0

恩,是的,隨身攜帶。我忘記了進位標誌。在大多數情況下,您可以將其視爲第33位。 – artificialidiot 2012-01-30 21:58:18

2

首先,您可以更有效地將所有雙字一次全部放入int並從那裏屏蔽/移位。

從中獲取小數部分很簡單:掩碼和移位以獲取整數,然後除以浮點數以縮放結果。

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

你完全正確!讓我編輯我的例子。我的形式是使用無符號字符*指向每個雙字的第一個最高有效字節,然後靜態轉換爲我想要的表示形式嗎?我覺得在這種情況下我會知道傳遞的數據。有更好的方法嗎? – Constantin 2012-01-30 22:10:59

+0

@Constantin,Ben Voigt在評論中說得很對 - 使用'uint_32 *',除非存在endian不匹配,否則按char排序。我看不到'uint_16'的任何優勢。 – 2012-01-30 22:20:55

0

如果你正在讀你的數據unsigned char型*,你是不是要能夠在數據的時間獲得超過8位和你的榜樣需要改變。如果你的地址是一致的,或者你的平臺允許的話,你應該以int *的形式讀取你的數據,但是這也會引發數據存儲的問題。它是以每個整數的20位與其他信息的12位存儲的,還是20位的流,您需要跟蹤您的位指針。如果第二個,它比你意識到的更復雜。一旦我感覺到你的數據是如何佈置在RAM中的,我會進一步發佈。

+0

我讀到這個問題,說每個數據是14 + 6 + 12 = 32位。 – 2012-01-30 22:05:03

+0

@MarkRansom是的,這是我的目標,我是否應該以另一種方式解釋它? – Constantin 2012-01-30 22:08:23

+0

@Constantin,我以爲你很清楚。感謝您的確認。 – 2012-01-30 22:11:50

相關問題