【问题标题】:How to convert decimal (base 10) numbers to ternary (base 3)如何将十进制(以 10 为底)数字转换为三进制(以 3 为底)
【发布时间】:2022-12-07 06:03:53
【问题描述】:

我想知道是否有一种方法可以将十进制数转换为三进制数,因为有一个函数 intToBits 用于转换为二进制数。

我实际上需要转换一个字符串

> S0 <- c("Hello Stac")

以 3 为底数。我想先将它转换为十进制

> S01 <- utf8ToInt(S0)
> S01
## [1]  72 101 108 108 111  32  83 116  97  99

然后将结果转换为基数 3。我想获得这样的东西:

> S1
## [1] 2200 10202 11000 11010  11022 1012 10002 11022 10121 10200

【问题讨论】:

  • 是的,对不起,我编辑了问题,所以我希望它能提供更多信息

标签: r base base-conversion


【解决方案1】:

作为练习,我想你可以尝试编写自己的转换器函数,如下所示

f <- function(x, base = 3) {
  q <- c()
  while (x) {
    q <- c(x %% base, q)
    x <- x %/% base
  }
  # as.numeric(paste0(q, collapse = ""))
  sum(q * 10^(rev(seq_along(q) - 1)))
}

或与递归

f <- function(x, base = 3) {
  ifelse(x < base, x, f(x %/% base) * 10 + x %% base)
}

然后你可以运行

> sapply(utf8ToInt(S0),f)
 [1]  2200 10202 11000 11000 11010  1012 10002 11022 10121 10200

【讨论】:

    【解决方案2】:

    不错的编程练习。我对@ThomasIsCoding 的答案进行了矢量化处理,以避免对字符串和字符串中的字符进行昂贵的循环。这个想法是循环数字,因为 Unicode 代码点在任何基数中都不超过 21 位数字,而字符向量中的字符总数可以大几个数量级。

    下面的函数将字符向量 x、基数 b(从 2 到 10)和逻辑标志 double 作为参数。它返回一个列表res,使得res[[i]] 是一个nchar(x[i])-length 向量,给出x[i] 的base-b 表示。列表元素是双精度向量或字符向量,具体取决于 double

    utf8ToBase <- function(x, b = 10, double = TRUE) {
        ## Do some basic checks
        stopifnot(is.character(x), !anyNA(x), 
                  is.numeric(b), length(b) == 1L, 
                  b %% 1 == 0, b >= 2, b <= 10)
        
        ## Require UTF-8 encoding
        x <- enc2utf8(x)
        
        ## Operate on concatenation to avoid loop over strings
        xx <- paste(x, collapse = "")
        ixx <- utf8ToInt(xx)
        
        ## Handle trivial case early
        if (length(ixx) == 0L) {
            el <- if (double) base::double(0L) else character(0L)
            res <- rep.int(list(el), length(x))
            names(res) <- names(x)
            return(res)
        }
        
        ## Use common field width determined from greatest integer
        width <- as.integer(floor(1 + log(max(ixx, 1), base = b)))
        res <- rep.int(strrep("0", width), length(ixx))
        
        ## Loop over digits
        pos <- 1L
        pow <- b^(width - 1L)
        while (pos <= width) {
            quo <- ixx %/% pow
            substr(res, pos, pos) <- as.character(quo)
            ixx <- ixx - pow * quo
            pos <- pos + 1L
            pow <- pow %/% b
        }
        
        ## Discard leading zeros
        if (double) {
            res <- as.double(res)
            if (b == 2 && any(res > 0x1p+53)) {
                warning("binary result not guaranteed due to loss of precision")
            }
        } else {
            res <- sub("^0+", "", res)
        }
        
        ## Return list
        res <- split(res, rep.int(gl(length(x), 1L), nchar(x)))
        names(res) <- names(x)
        res
    }
    
    x <- c(foo = "Hello Stack Overflow!", bar = "Hello world!")
    utf8ToBase(x, 2)
    
    $foo
     [1] 1001000 1100101 1101100 1101100 1101111  100000
     [7] 1010011 1110100 1100001 1100011 1101011  100000
    [13] 1001111 1110110 1100101 1110010 1100110 1101100
    [19] 1101111 1110111  100001
    
    $bar
     [1] 1001000 1100101 1101100 1101100 1101111  100000
     [7] 1110111 1101111 1110010 1101100 1100100  100001
    
    utf8ToBase(x, 3)
    
    $foo
     [1]  2200 10202 11000 11000 11010  1012 10002 11022 10121 10200
    [11] 10222  1012  2221 11101 10202 11020 10210 11000 11010 11102
    [21]  1020
    
    $bar
     [1]  2200 10202 11000 11000 11010  1012 11102 11010 11020 11000
    [11] 10201  1020
    
    utf8ToBase(x, 10)
    
    $foo
     [1]  72 101 108 108 111  32  83 116  97  99 107  32  79 118 101
    [16] 114 102 108 111 119  33
    
    $bar
     [1]  72 101 108 108 111  32 119 111 114 108 100  33
    

    一些警告:

    • 为了提高效率,该函数连接 x 中的字符串,而不是遍历它们。如果连接超过 2^31-1 字节,它会抛出错误,这是 R 允许的最大字符串大小。

      x <- strrep(letters[1:2], 0x1p+30)
      log2(sum(nchar(x))) # 31
      utf8ToBase(x, 3)
      
      Error in paste(x, collapse = "") : result would exceed 2^31-1 bytes
      
    • 最大的 Unicode 代码点是 0x10FFFF。当解释为十进制时,此数字的二进制表示形式超过 2^53,因此它不能在不损失精度的情况下存储在双精度向量中:

      x <- sub("^0+", "", paste(rev(as.integer(intToBits(0x10FFFF))), collapse = ""))
      x
      ## [1] "100001111111111111111"
      sprintf("%.0f", as.double(x))
      ## [1] "100001111111111114752"
      

      作为一种防御措施,如果在b = 2double = TRUE时超过2^53,该函数会发出警告。

      utf8ToBase("U10FFFF", b = 2, double = TRUE)
      
      [[1]]
      [1] 1.000011e+20
      
      Warning message:
      In utf8ToBase("U{10ffff}", b = 2, double = TRUE) :
        binary result not guaranteed due to loss of precision
      
      utf8ToBase("U10FFFF", b = 2, double = FALSE)
      
      [[1]]
      [1] "100001111111111111111"
      

    【讨论】:

      【解决方案3】:

      你可以使用cwhmisc::int2B

      library(cwhmisc)
      int2B(utf8ToInt(S0), 3)[[1]] |> as.numeric()
      # [1]  2200 10202 11000 11000 11010  1012 10002 11022 10121 10200
      

      【讨论】:

        猜你喜欢
        • 2020-10-04
        • 2012-03-14
        • 1970-01-01
        • 2012-03-15
        • 2021-05-28
        • 1970-01-01
        • 2010-10-14
        • 2020-12-29
        • 1970-01-01
        相关资源
        最近更新 更多