Reputation: 1200
I see that there is a built-in function for the...rather abstract...use of transforming from the a decimal representation to roman numerals (Convert roman numerals to numbers in R), but I'm not able to find a built-in way to convert from decimal to other, similar, systems, like base 3 or base 11. I see that binary and hex (base 16) are well supported, but is there a package for converting to/from an arbitrary positional numeral system.
I could make such a package, but I suspect it already exists and my google-fu is just falling short?
Upvotes: 5
Views: 1368
Reputation: 174328
You could write your own S3 class:
base <- function(b, base = 10)
{
base <- as.integer(base)
if(base > 36 | base < 2) stop("'base' must be between 2 and 36.")
structure(lapply(b, function(x)
{
n <- ceiling(log(x, base))
vec <- numeric()
val <- x
while(n >= 0)
{
rem <- val %/% base^n
val <- val - rem * base^n
vec <- c(vec, rem)
n <- n - 1
}
while(vec[1] == 0 & length(vec) > 1) vec <- vec[-1]
structure(x, base = base, representation = vec)
}), class = "base")
}
Which will need a format
and print
method:
format.base <- function(b, ...)
{
sapply(b, function(x)
{
glyphs <- c(0:9, LETTERS)
base <- attr(x, "base")
vec <- attr(x, "representation")
paste0(glyphs[vec + 1], collapse = "")
})
}
print.base <- function(b, ...) print(format(b), quote = FALSE)
We also need to make sure that maths operations work properly:
Ops.base <- function(e1, e2) {
base <- attr(e1[[1]], "base")
e1 <- unlist(e1)
e2 <- unlist(e2)
base(NextMethod(.Generic), base)
}
Math.base <- function(e1, e2) {
base <- attr(e1[[1]], "base")
e1 <- unlist(e1)
e2 <- unlist(e2)
base(NextMethod(.Generic), base)
}
And if you want to use it inside a data frame you need an as.data.frame
method:
as.data.frame.base <- function(b, ...)
{
structure(list(b),
class = "data.frame",
row.names = seq_along(b))
}
Which all allows the following behaviour:
data.frame(binary = base(1:20, 2), hex = base(1:20, 16), oct = base(1:20, 8))
#> binary hex oct
#> 1 1 1 1
#> 2 10 2 2
#> 3 11 3 3
#> 4 100 4 4
#> 5 101 5 5
#> 6 110 6 6
#> 7 111 7 7
#> 8 1000 8 10
#> 9 1001 9 11
#> 10 1010 A 12
#> 11 1011 B 13
#> 12 1100 C 14
#> 13 1101 D 15
#> 14 1110 E 16
#> 15 1111 F 17
#> 16 10000 10 20
#> 17 10001 11 21
#> 18 10010 12 22
#> 19 10011 13 23
#> 20 10100 14 24
And:
x <- base(67, 11)
y <- base(35, 2)
x + y
#> [1] 93
base(x + y, 10)
#> [1] 102
Upvotes: 11