簡體   English   中英

將字節數組(uint8_t)轉換為單詞數組(uint16_t),反之亦然

[英]Converting an array of bytes (uint8_t) into an array of words (uint16_t) and vice versa

我有一段非常耗時的代碼要優化,它的確會將字節數組轉換成單詞數組,反之亦然。 該操作用於在8位和16位圖像數據之間轉換。

該數組是qword對齊的,並且足夠存儲結果。

從字節到字的轉換需要乘以257(因此0被轉換為0,而255得到65535)

一個簡單的解決方案可能是

void simpleBytesToWords(void *ptr, int pixelCount)
{
    for (int i = pixelCount - 1; i >= 0; --i)
        reinterpret_cast<uint16_t*>(ptr)[i] = reinterpret_cast<uint8_t*>(ptr)[i] * 0x101;
}

我還嘗試通過一次轉換4個字節以使用64位寄存器來提高性能:

void bytesToWords(void *ptr, int pixelCount)
{
    const auto fastCount = pixelCount / 4;

    if (fastCount > 0)
    {
        for (int f = fastCount-1; f >= 0; --f)
        {
            auto bytes = uint64_t{ reinterpret_cast<const uint32_t*>(ptr)[f] };

            auto r2 = uint64_t{ bytes & 0xFF };
            bytes <<= 8;
            r2 |= bytes & 0xFF0000;
            bytes <<= 8;
            r2 |= bytes & 0xFF00000000ull;
            bytes <<= 8;
            r2 |= bytes & 0xFF000000000000ull;

            r2 *= 0x101;

            reinterpret_cast<uint64_t*>(ptr)[f] = r2; 
        }
    }

    if (pixelCount % 4)
    {
        auto source = reinterpret_cast<const uint8_t*>(ptr);
        auto target = reinterpret_cast<uint16_t*>(ptr);

        for (int i = fastCount * 4; i < pixelCount; ++i)
        {
            target[i] = (source[i] << 8) | source[i];
        }
    }

}

它正在工作,並且比簡單的解決方案要快一些。

另一個方向(字到字節)通過以下代碼完成:

for (int i = 0; i < pixelCount; ++i)
    reinterpret_cast<uint8_t*>(bufferPtr)[i] = reinterpret_cast<uint16_t*>(bufferPtr)[i] / 256;

我一直在尋找編譯器內部函數來加快此轉換的速度,但沒有發現任何有用的東西。 還有其他方法可以改善轉換效果嗎?

編譯代碼后,我嘗試了兩種方法(我只是將bytesToWords()重命名,現在groupedBytesToWords()其改名為bytesToWords() ):

  • 測試您的兩個功能:它們不會產生相同的結果。 使用simpleBytesToWords()我得到一個零填充的數組。 使用groupedBytesToWords()我最終得到的是有效結果和零的交替。

  • 如果沒有更改它們,假設錯誤修正不會改變其復雜性,我嘗試編寫的第三篇文章使用了預先計算的uint8_t > uint16_t表,該表必須首先構建:

這是這張桌子。 這是一個很小的條目,因為它只有255個條目,每個可能的uint8_t

// Build a precalculation table for each possible uint8_t -> uint16_t conversion 
const size_t sizeTable(std::numeric_limits<uint8_t>::max());

uint16_t * precalc_table = new uint16_t[sizeTable];

for (uint16_t i = 0; i < sizeTable; ++i)
{
    precalc_table[i] = i * 0x101;
}

我嘗試的第三個功能如下:

void hopefullyFastBytesToWords(uint16_t *ptr, size_t pixelCount, uint16_t const * precalc_table)
{
    for (size_t i = 0; i < pixelCount; ++i)
    {
        ptr[i] = precalc_table[ptr[i]];
    }
}

我當然對其進行了測試,並且根據您在原始帖子中所做的描述,它產生的結果看起來很不錯。 通過傳遞與我們對其他兩個函數相同的參數以及預先計算的轉換表來調用此函數:

hopefullyFastBytesToWords(buffer, sizeBuf, precalc_table);

然后,我使用500000000 uint16_t長數組進行了一些比較,該數組最初填充了隨機的uint8_t值。 這是使用您編寫的simpleBytesToWords()的示例:

fillBuffer(buffer, sizeBuf);
begin = clock();
simpleBytesToWords(buffer, sizeBuf);
end = clock();
std::cout << "simpleBytesToWords(): " << (double(end - begin) / CLOCKS_PER_SEC) << std::endl;

我獲得了以下結果(您會看到我使用的是小型且緩慢的筆記本電腦)。 這是三個示例,但是它們始終會產生相似大小的值:

$ Sandbox.exe
simpleBytesToWords(): 0.681
groupedBytesToWords(): 1.2
hopefullyFastBytesToWords(): 0.461

$ Sandbox.exe
simpleBytesToWords(): 0.737
groupedBytesToWords(): 1.251
hopefullyFastBytesToWords(): 0.414

$ Sandbox.exe
simpleBytesToWords(): 0.582
groupedBytesToWords(): 1.173
hopefullyFastBytesToWords(): 0.436

當然,這並不代表真實的實際有效基准,但是它表明您的“分組”功能在我的計算機上運行速度較慢,這與您獲得的結果不一致。 它也顯示出比預先計算乘法而不是即時進行轉換/乘法有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM