どのようにシフトをバイト配列により12ビット
質問
たいへのシフトの内容をバイト配列により12ビットの左方向に移動します。
例えば、この配列の型 uint8_t shift[10]
:
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xBC}
思シフトで左12ビットより:
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0xC0, 0x00}
解決
フレーのためのポイント!
このコードによる今後12ビット毎にバイトコピーの適切なビットです。12ビットの下半分(nybble)の次のバイトの上位半分の2バイトを離れます
unsigned char length = 10;
unsigned char data[10] = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0A,0xBC};
unsigned char *shift = data;
while (shift < data+(length-2)) {
*shift = (*(shift+1)&0x0F)<<4 | (*(shift+2)&0xF0)>>4;
shift++;
}
*(data+length-2) = (*(data+length-1)&0x0F)<<4;
*(data+length-1) = 0x00;
ジャスティン書き:
@マイクは、ソリューションでは行いません。
もう普通のシフト操作はそれにはオーバーフロー)、きのビットが落ちてしまうことがあシンプルでなめしたい場合は、すぐに保存し、12ビットを開始する前に、シフトができます。したい円形のシフトを入れるにあふれたビットの底部?したいrealloc配列のでき?のオーバーフローの呼び出し側は?戻り値がbooleanの場合はゼロでのデータが溢れ?いを定義するには何を意味します。
unsigned char overflow[2];
*overflow = (*data&0xF0)>>4;
*(overflow+1) = (*data&0x0F)<<4 | (*(data+1)&0xF0)>>4;
while (shift < data+(length-2)) {
/* normal shifting */
}
/* now would be the time to copy it back if you want to carry it somewhere */
*(data+length-2) = (*(data+length-1)&0x0F)<<4 | (*(overflow)&0x0F);
*(data+length-1) = *(overflow+1);
/* You could return a 16-bit carry int,
* but endian-ness makes that look weird
* if you care about the physical layout */
unsigned short carry = *(overflow+1)<<8 | *overflow;
他のヒント
ここでの私の解決にも重要なのは僕のアプローチを解決するための方法は問題です。
このよ
- 図面の記憶細胞の図の矢印の先のソースです。
- したテーブルの上。
- ラベル各行はテーブルとの相対的なバイトアドレスです。
この案内をしてくれたパターン:
- ましょう
iL
の低nybble(ハーフバイト)a[i]
- ましょう
iH
の高nybbleのa[i]
iH = (i+1)L
iL = (i+2)H
このパターンのために保有するすべてのバイトです。
翻訳する手段
a[i] = (iH << 4) OR iL
a[i] = ((a[i+1] & 0x0f) << 4) | ((a[i+2] & 0xf0) >> 4)
を行うことがありますの考察
- この課題を左右していく必要があるanyの値は、一時的な変数.
- また特別な場合にテール:すべての
12 bits
末尾がゼロになります。 - まれるようなことは避けなければ読書に未定義のメモリの過去の配列になります。しい読み取り
a[i+2]
, この影響がある最後のバイト
そこで、
- 取扱いを一般の場合にループを用
N-2 bytes
を一般、上記の計算式で算出された値 - 取扱いは、次にバイトを設定することで、そ
iH = (i+1)L
- 対応最後のバイトを設定する
0
され a
長さ N
, のになります:
for (i = 0; i < N - 2; ++i) {
a[i] = ((a[i+1] & 0x0f) << 4) | ((a[i+2] & 0xf0) >> 4);
}
a[N-2] = (a[N-1) & 0x0f) << 4;
a[N-1] = 0;
がま...の配列がずれるよ 12 bits
.で容易に一般化への移行 N bits
, ことがあります M
割り算が M = number of bits modulo 8
, 教えて頂けたらと思います。
ループを効率化できる一部の機械翻訳へのポインタ
for (p = a, p2=a+N-2; p != p2; ++p) {
*p = ((*(p+1) & 0x0f) << 4) | (((*(p+2) & 0xf0) >> 4);
}
に最大の整数値データタイプのCPUを搭載しています。
うに入力すので、そういうことを考えると良い時間を誰かが見直しのコードでビットtwiddlingは悪名やすい間違っています。)
でも、シフト N
ビット配列内の8ビット整数です。
N - Total number of bits to shift
F = (N / 8) - Full 8 bit integers shifted
R = (N % 8) - Remaining bits that need to be shifted
私はここからすべき最適な方法を使用ではこれらのデータを移動すint配列.汎用アルゴリズムが適用の整数シフトから右の配列と移動する整数 F
スを作成します。ゼロの新規の空の空間です。そして最後に行 R
ビットシフトすべての指標を再度から始まる。
の場合移転 0xBC
による R
ビットを計算できるオーバーフローすることによってビット単位や、シフトのbitshiftオペレーター:
// 0xAB shifted 4 bits is:
(0xAB & 0x0F) >> 4 // is the overflow (0x0A)
0xAB << 4 // is the shifted value (0xB0)
この4ビット単なるマスク:0x0Fや0b00001111.これは簡単に計算し、動的に構築は、とってもシンプルな静的ルックアップ。
いである。いないC/C++でのすべてのものは、なんだか"ほっとニュースクリーンまでの私の書式がありますが固有のものです。
ボーナス:だcraftyごCることができるかもしれませfudge複数の配列の指数を単一の16,32、64ビット整数のシフトです。そprabablyな携帯用エクスペディアをおすすめ対す。ただきました。
ここは、一時的な変数:
void shift_4bits_left(uint8_t* array, uint16_t size)
{
int i;
uint8_t shifted = 0x00;
uint8_t overflow = (0xF0 & array[0]) >> 4;
for (i = (size - 1); i >= 0; i--)
{
shifted = (array[i] << 4) | overflow;
overflow = (0xF0 & array[i]) >> 4;
array[i] = shifted;
}
}
この関数を呼び出3倍の12ビットのシフトができます。
マイク-ソリューションも高速での使用による一時的な変数.
の32ビットのバージョン---:-)の取り扱1 <=カウント <=num_words
#include <stdio.h>
unsigned int array[] = {0x12345678,0x9abcdef0,0x12345678,0x9abcdef0,0x66666666};
int main(void) {
int count;
unsigned int *from, *to;
from = &array[0];
to = &array[0];
count = 5;
while (count-- > 1) {
*to++ = (*from<<12) | ((*++from>>20)&0xfff);
};
*to = (*from<<12);
printf("%x\n", array[0]);
printf("%x\n", array[1]);
printf("%x\n", array[2]);
printf("%x\n", array[3]);
printf("%x\n", array[4]);
return 0;
}
@Josephので、この変数は8ビット幅のシフトは12ビット幅です。ソリューション作品のみN <=可変サイズです。
できればとご配列は複数の4キャストの配列の配列uint64_tし作業。ない場合、複数の4バイトをすることができますので、64ビットのチャンクしているときは、残ります。このビットより符号化はないと思いますが上品です。
カップルの場合、このコンの問題:
- 入力配列は空の場合もあ
- 最後の次の最後のビットを必要として特にないため、ゼロのビットへとシフトしてい
このシンプルなソリューションループの配列のコピーの低い順nibbleの次のバイトを高めnibbleの高次nibbleのnext(+2)バイトを低めnibble.保存dereferencingの先見のポインタを回ることで二つの要素のバッファの"最終"と"次の"パーバイト:
void shl12(uint8_t *v, size_t length) {
if (length == 0) {
return; // nothing to do
}
if (length > 1) {
uint8_t last_byte, next_byte;
next_byte = *(v + 1);
for (size_t i = 0; i + 2 < length; i++, v++) {
last_byte = next_byte;
next_byte = *(v + 2);
*v = ((last_byte & 0x0f) << 4) | (((next_byte) & 0xf0) >> 4);
}
// the next-to-last byte is half-empty
*(v++) = (next_byte & 0x0f) << 4;
}
// the last byte is always empty
*v = 0;
}
の境界の場合、起動順により部品の機能:
- 時
length
がゼロにして救済に触れずに。 - 時
length
で設定していま唯一の要素をゼロになります。 - 時
length
は、その高次nibbleの最初のバイトを低めnibbleの第バイト目には、ビットを12~16)、第二バイトをゼロになります。しか起動します。 - 時
length
以上の二つのまにループ-シャッフリングのバイト全体の要素のバッファです。
た場合の効率は、この答えに大きく依存してお客様のマシン。一般的にいを維持すべきであり、二つの要素のバッファが取扱う機械語(32/64ビット符号無し整数型)です。いず多くのデータで価値のある処理の最初の数バイトとして特別な場合ができますのでマシン語へのポインタワーが揃います。最Cpuのアクセスメモリーをより効率的な場合にはアクセス秋機械語境界を参考にしています。もちろん、最後のバイトが取り扱う特別にすぎないタッチメモリの後の配列の型になります。