用零读取n位和填充的通用算法

时间:2016-03-26 09:08:44

标签: c++ file bitmap bit-manipulation

我需要一个函数从位x开始读取n位(位索引应该从零开始),如果结果不是字节对齐,则用零填充它。该函数将在输入上接收uint8_t数组,并且还应返回uint8_t数组。例如,我有以下内容的文件:

1011 0011 0110 0000

从第三位读取三位(x = 2,n = 3);结果:

1100 0000

输入和位模式长度没有(理论上的)限制

2 个答案:

答案 0 :(得分:0)

在不超出直接位串行算法的情况下有效地实现这样的位域提取并不是很难,但有点麻烦。

实际上它归结为内循环从每个输出字节的输入读取一对字节,根据源位偏移将结果字移位到位,并写回高位或低位字节。此外,最终输出字节将根据长度进行屏蔽。

以下是我的(测试不佳)尝试实施:

void extract_bitfield(unsigned char *dstptr, const unsigned char *srcptr, size_t bitpos, size_t bitlen) {
    // Skip to the source byte covering the first bit of the range
    srcptr += bitpos / CHAR_BIT;
    // Similarly work out the expected, inclusive, final output byte
    unsigned char *endptr = &dstptr[bitlen / CHAR_BIT];
    // Truncate the bit-positions to offsets within a byte
    bitpos %= CHAR_BIT;
    bitlen %= CHAR_BIT;
    // Scan through and write out a correctly shifted version of every destination byte
    // via an intermediate shifter register
    unsigned long accum = *srcptr++;
    while(dstptr <= endptr) {
        accum = accum << CHAR_BIT | *srcptr++;
        *dstptr++ = accum << bitpos >> CHAR_BIT;
    }
    // Mask out the unwanted LSB bits not covered by the length
    *endptr &= ~(UCHAR_MAX >> bitlen);
}

请注意上面的代码可能会读取超过源缓冲区的末尾,如果您无法设置开销以允许此操作,则需要进行一些混乱的特殊处理。它还假定为sizeof(long) != 1

当然,为了提高效率,你需要尽可能广泛地使用本地词。但是,如果目标缓冲区必然是字对齐的,那么事情就会变得更加混乱。此外,little-endian系统需要字节调整修复。

需要注意的另一个微妙之处是可能无法移动整个单词,即移位计数通常被解释为单词长度的模数。

无论如何,快乐的黑客攻击!

答案 1 :(得分:0)

基本上它仍然是一堆移位和加法操作。

我将使用一个稍微大一些的例子来证明这一点。

假设我们输入4个字符,x = 10,n = 18。

## app.R ##
library(shiny)
library(shinydashboard)
library(dplyr)
library(arm)
library(texreg)

header <- dashboardHeader()

sidebar <- dashboardSidebar(column(3, actionButton(inputId = "go", label = "Run Analysis!")))

body <- dashboardBody(fluidPage(fluidRow(
  box(
    title = "Regression Table",
    status = "primary",
    solidHeader = TRUE,
    width = 6,
    uiOutput("mybayesglm")
  )
)))



ui <- dashboardPage(header, sidebar, body)

server <- function(input, output) { 
  results <- reactiveValues()

  observeEvent(input$go, {
    # Gen fake data
    N<-1000
    df1 <- data.frame(v1=sample(c(0,1),N,replace = T),
                      v2=sample(c(0,1),N,replace = T),
                      Treatment=sample(c("A", "B", "C"), N, replace = T),
                      noise=rnorm(N)) %>% 
      mutate(Y=0.5*v1-0.7*v2+2*I(Treatment=="B")+3*I(Treatment=="C")+noise)
    # Run regression
    mybayesglm <- bayesglm(data = df1, formula = Y~Treatment+v1+v2)
    #ouput results in a reactive list
    results[[as.character(length(names(results)) + 1)]] <- mybayesglm
    return(results)
  }) #<-end observeEvent

  output$mybayesglm <- renderUI({
    HTML(
      htmlreg(reactiveValuesToList(results), ci.force = TRUE, ci.force.level = .95, caption = "")
    )
  })
  }

shinyApp(ui, server)

首先我们需要找到包含我们的第一位的字符00101011 10001001 10101110 01011100 ,在这种情况下我们给出1(第二个字符)。我们还需要该字符的偏移量x / 8,等于2.

现在我们可以在三个操作中找到解决方案的第一个字符。

  1. 左移第二个字符10001001 2位,给我们00100100。
  2. 右移第三个字符10101110,其中6(来自x % 8)位,给我们00000010。
  3. 添加这两个字符为我们提供返回字符串中的第一个字符,给出00100110。
  4. 将此例程循环到8 - 2轮。如果n / 8不为0,则从下一个字符中提取多个位,您可以通过多种方法完成。

    所以在这个例子中,我们的第二轮将给出10111001,最后一步得到10,然后用0填充其余位。