Search code examples
rbinarydecimaldata-conversionradix

Convert a base2 number (with fractional part) to a base10 number in R?


How to convert a base2 number (with fractional part) to a base10 number in R? The number can be negative as well.

Examples:

from2to10(10100101) # "165"
from2to10(0) # "0"
from2to10(10100101.01) # "165.25"
from2to10(-10100101) # "-165"
from2to10(-10100101.01) # "-165.25"
from2to10(111101111.010111) # "495.359375"

Solution

  • Edit: I realize I was assuming that the input would be character, perhaps a bad assumption on my part. I believe trusting R to preserve all of your 0s and 1s (with R FAQ 7.31 in mind) is a bit trusting, but I'll keep my answer as-is unless/until something better comes along.


    This was interesting ... not certain if there's an R function that deals with floating-point in non-decimal, so here's one ...

    #' Convert floating-point binary to decimal
    #'
    #' @param s 'character'
    #' @return 'numeric'
    #' @examples
    #' tests <- c("10100101", "0", "10100101.01", "-10100101", "-10100101.01", "111101111.010111")
    #' base2float(tests)
    #' # [1]  165.0000    0.0000  165.2500 -165.0000 -165.2500  495.3594
    base2float <- function(s, base = 2L) {
      # ensure the strings seem logical:
      # - start with "-", "+", or "[01]"
      # - zero or more "[01]"
      # - optional decimal "." (can easily change to "," for alternate reps)
      # - zero or more "[01]"
      stopifnot(all(grepl("^[-+]?[01]*\\.?[01]*$", s)))
      splits <- strsplit(s, "\\.")
      wholes <- sapply(splits, `[[`, 1L)
      wholes[wholes %in% c("", "-", "+")] <- paste0(wholes[wholes %in% c("", "-", "+")], "0")
      fracs <- sapply(splits, `[`, 2L)
      fracs[is.na(fracs)] <- "0"
      # because string-length is used in our calcs ...
      fracs <- gsub("0+$", "0", fracs)
      whole10 <- strtoi(wholes, base = base)
      frac10 <- strtoi(fracs, base = base) / (base^nchar(fracs))
      whole10 + sign(whole10)*frac10
    }