亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Util 從字節數組中提取位到一個新的 byte[]

Util 從字節數組中提取位到一個新的 byte[]

手掌心 2023-03-23 14:55:17
我正在嘗試構建一個實用程序類以使按位操作和轉換更具可讀性。目前我一直在構建一種方法來從字節數組中提取位并從中形成一個新的 byte[]。不用說我對按位運算不是很流利。我相信它可能可以使用 BitSet 來實現,但是會有太多的轉換并且實現將是特定于 Java 的。如果有一個清晰的算法可以在以后輕松移植到其他語言,那就太好了。到目前為止,我已經做到了:    public static byte[] toBytes(int offset /*full bytes*/, int bitsOffset /*bytes + bits*/, int bitsCount, byte... bytes) {        int bytesCount = bitsCount / 8;        int paddingBits = bitsCount % 8;        int partialBits = 8 - paddingBits;        if (paddingBits > 0) {            bytesCount++;        }        byte[] data = new byte[bytesCount];        return data;    }我已經評論了上面的內容并將其臨時替換為    public static byte[] toBytes(int offset, int bitsOffset, int bitsCount, byte... bytes) {        int firstBitIndex = (offset * 8) + bitsOffset;        return new BigInteger(new BigInteger(1, bytes).toString(2).substring(firstBitIndex, firstBitIndex + bitsCount), 2).toByteArray();    }但是我仍然希望有一個盡可能少的開銷并且不特定于 Java 的正確實現(不使用特定于 Java 的工具,如 BitSet)這是我期望它做什么的暗示   /**     * [0000 0110   1111 0010] = toBytes(1, 4, 12, [xxxx xxxx   xxxx 0110   1111 0010   xxxx xxxx])     * [0000 0110   1111 0010] = toBytes(1, 5, 12, [xxxx xxxx   xxxx x011   0111 1001   0xxx xxxx])     * [0000 0110   1111 0010] = toBytes(1, 6, 12, [xxxx xxxx   xxxx xx01   1011 1100   10xx xxxx])     */
查看完整描述

1 回答

?
搖曳的薔薇

TA貢獻1793條經驗 獲得超6個贊

到目前為止,我已經 [...]byte[] data = new byte[bytesCount];

不幸的是,這種方法只有在您的位偏移量是 8 的倍數時才有效。在所有其他情況下,您必須劃分要復制的每個字節。下圖說明了如何劃分每個字節以及將劃分的部分放在哪里。

MSB = 最高有效位
LSB = 最低有效位

http://img1.sycdn.imooc.com//641bf7f600015ed106530568.jpg

由于有很多極端情況,實現上述算法有點棘手。以下實現通過了您的所有測試和我的所有測試。我使用了許多變量來為所有計算賦予有意義的名稱,希望它更容易理解。您可以通過消除其中一些變量并就地計算一些值來縮短實施時間。


我冒昧地將您的功能重命名toBytes為bitSubstring. 對于已經將字節作為輸入的方法,以前的名稱toBytes似乎有點不合時宜。


public static byte[] bitSubstring(int byteOffset, int bitOffset,

                                  int lengthInBits, byte... source) {

    return bitSubstring(8 * byteOffset + bitOffset, lengthInBits, source);

}

public static byte[] bitSubstring(int startBit, int lengthInBits,

                                  byte... source) {

    assert startBit >= 0 && startBit < 8 * source.length;

    assert lengthInBits >= 0 && startBit + lengthInBits <= 8 * source.length;


    int lengthInBytes = (int) Math.ceil(lengthInBits / 8.0);

    byte[] target = new byte[lengthInBytes];

    int startByte = startBit / 8;

    int endBitExclusive = startBit + lengthInBits;

    int endByteExclusive = (int) Math.ceil(endBitExclusive / 8.0);

    int sourceBytesToRead = endByteExclusive - startByte;

    int lowerPartSize = 8 * endByteExclusive - endBitExclusive;

    int shiftLowerUp = (8 - lowerPartSize);

    int shiftUpperDown = lowerPartSize;

    int lastSrc = 0;

    if (sourceBytesToRead > lengthInBytes) {

        lastSrc = source[startByte] & 0xFF;

        startByte++;

    }

    for (int targetByte = 0; targetByte < target.length; ++targetByte) {

        int curSrc = source[startByte + targetByte] & 0xFF;

        target[targetByte] |= (lastSrc << shiftLowerUp)

                            | (curSrc >>> shiftUpperDown);

        lastSrc = curSrc;

    }

    int overhang = 8 * lengthInBytes - lengthInBits;

    if (overhang > 0) {

        target[0] &= 0xFF >>> overhang;

    }

    return target;

}

上面的算法應該相當快。但是,如果您只對實現大小和可讀性感興趣,那么逐位復制的方法會更好。


public static byte[] bitSubstringSlow(int startBitSource, int lengthInBits,

                                      byte... source) {

    byte[] target = new byte[(int) Math.ceil(lengthInBits / 8.0)];

    int startBitTarget = (8 - lengthInBits % 8) % 8;

    for (int i = 0; i < lengthInBits; ++i) {

        setBit(target, startBitTarget + i, getBit(source, startBitSource + i));

    }

    return target;

}


public static int getBit(byte[] source, int bitIdx) {

    return (source[bitIdx / 8] >>> (7 - bitIdx % 8)) & 1;

}


public static void setBit(byte[] target, int bitIdx, int bitValue) {

    int block = bitIdx / 8;

    int shift = 7 - bitIdx % 8;

    target[block] &= ~(1 << shift);

    target[block] |= bitValue << shift;

}

......或更少可重復使用但更短:


public static byte[] bitSubstringSlow2(int startBitSource, int lengthInBits,

                                       byte... source) {

    byte[] target = new byte[(int) Math.ceil(lengthInBits / 8.0)];

    int startBitTarget = (8 - lengthInBits % 8) % 8;

    for (int i = 0; i < lengthInBits; ++i) {

        int srcIdx = startBitSource + i;

        int tgtIdx = startBitTarget + i;

        target[tgtIdx / 8] |= ((source[srcIdx / 8] >>> (7 - srcIdx % 8)) & 1)

                              << (7 - tgtIdx % 8);

    }

    return target;

}


查看完整回答
反對 回復 2023-03-23
  • 1 回答
  • 0 關注
  • 119 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號