Convirtiendo decimal a binario en R?
(10)
--originalmente agregado como una edición a la respuesta de @ JoshuaUlrich, ya que es totalmente un corolario de él y @ nico; sugirió que agregue una respuesta por separado, ya que presenta un paquete fuera de su ken--
Dado que la respuesta de @ JoshuaUlrich es tan funcional (6 funciones consecutivas), encuentro que el operador de pipe ( %>%
) de magrittr
/ tidyverse
hace que la siguiente solución sea más elegante:
library(magrittr)
intToBits(12) %>% rev %>% as.integer %>% paste(collapse = '''')
# [1] "00000000000000000000000000001100"
También podemos agregar una llamada final as.integer
para truncar todos los ceros a la izquierda:
intToBits(12) %>% rev %>% as.integer %>% paste(collapse = '''') %>% as.integer
# [1] 1100
(Nótese, por supuesto, que esto también se almacena como un integer
, lo que significa que R lo considera como 1100 representado en la base 10, no 12 representados en la base 2)
Tenga en cuenta que @ ramanudle (y otros, notablemente @russellpierce, que ofrece una implementación en C ++) es a menudo el estándar sugerido en los lenguajes de bajo nivel, ya que es un enfoque bastante eficiente (y funciona para cualquier número que se pueda almacenar en R, es decir, no limitado a integer
rango integer
).
También vale la pena mencionar que la github.com/wch/r-source/blob/… es notablemente directa (excepto que no conozco los operadores &
o >>=
en C)
¿Cuál sería la forma más fácil de convertir un número a base 2 (en una cadena, como por ejemplo 5 se convertiría a "0000000000000101"
) en R? Hay intToBits
, pero devuelve un vector de cadenas en lugar de una cadena:
> intToBits(12)
[1] 00 00 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[26] 00 00 00 00 00 00 00
He intentado algunas otras funciones, pero no tuve éxito:
> toString(intToBits(12))
[1] "00, 00, 01, 01, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00"
Ah, pero ¿qué hacer si tienes un entero de 64 bits habilitado por el paquete bit64? Cada respuesta dada, que no sea la de @epwalsh, no operará en el entero de 64 bits porque las partes internas basadas en C de R y R.utils no lo admiten. La solución de @epwalsh es excelente y funciona en R si primero se carga el paquete bit64
, excepto que (usando bucles) en R es lento (todas las velocidades son relativas).
o.dectobin <- function(y) {
# find the binary sequence corresponding to the decimal number ''y''
stopifnot(length(y) == 1, mode(y) == ''numeric'')
q1 <- (y / 2) %/% 1
r <- y - q1 * 2
res = c(r)
while (q1 >= 1) {
q2 <- (q1 / 2) %/% 1
r <- q1 - q2 * 2
q1 <- q2
res = c(r, res)
}
return(res)
}
dat <- sort(sample(0:.Machine$integer.max,1000000))
system.time({sapply(dat,o.dectobin)})
# user system elapsed
# 61.255 0.076 61.256
Podemos mejorar esto si lo compilamos por byte ...
library(compiler)
c.dectobin <- cmpfun(o.dectobin)
system.time({sapply(dat,c.dectobin)})
# user system elapsed
# 38.260 0.010 38.222
... pero todavía es bastante lento. Podemos obtener mucho más rápido si escribimos nuestras propias partes internas en C (que es lo que he hecho aquí tomando prestado del código de @epwalsh, obviamente no soy un programador de C) ...
library(Rcpp)
library(inline)
library(compiler)
intToBin64.worker <- cxxfunction( signature(x = "string") , ''
#include <string>
#include <iostream>
#include <sstream>
#include <algorithm>
// Convert the string to an integer
std::stringstream ssin(as<std::string>(x));
long y;
ssin >> y;
// Prep output string
std::stringstream ssout;
// Do some math
int64_t q2;
int64_t q1 = (y / 2) / 1;
int64_t r = y - q1 * 2;
ssout << r;
while (q1 >= 1) {
q2 = (q1 / 2) / 1;
r = q1 - q2 * 2;
q1 = q2;
ssout << r;
}
// Finalize string
//ssout << r;
//ssout << q1;
std::string str = ssout.str();
std::reverse(str.begin(), str.end());
return wrap(str);
'', plugin = "Rcpp" )
system.time(sapply(as.character(dat),intToBin64.worker))
# user system elapsed
# 7.166 0.010 7.168
`` `
Creo que puede usar el paquete R.utils, luego la función intToBin ()
>library(R.utils)
>intToBin(12)
[1] "1100"
> typeof(intToBin(12))
[1] "character"
Eche un vistazo al paquete R.utils; allí tiene una función llamada intToBin ...
http://rss.acs.unt.edu/Rdoc/library/R.utils/html/intToBin.html
Esta función tomará un número decimal y devolverá la secuencia binaria correspondiente, es decir, un vector de 1 y 0
dectobin <- function(y) {
# find the binary sequence corresponding to the decimal number ''y''
stopifnot(length(y) == 1, mode(y) == ''numeric'')
q1 <- (y / 2) %/% 1
r <- y - q1 * 2
res = c(r)
while (q1 >= 1) {
q2 <- (q1 / 2) %/% 1
r <- q1 - q2 * 2
q1 <- q2
res = c(r, res)
}
return(res)
}
Prueba »binaryLogic«
library(binaryLogic)
ultimate_question_of_life_the_universe_and_everything <- as.binary(42)
summary(ultimate_question_of_life_the_universe_and_everything)
#> Signedness Endianess value<0 Size[bit] Base10
#> 1 unsigned Big-Endian FALSE 6 42
> as.binary(0:3, n=2)
[[1]]
[1] 0 0
[[2]]
[1] 0 1
[[3]]
[1] 1 0
[[4]]
[1] 1 1
Tenga en cuenta que intToBits()
devuelve un vector ''raw'', no un vector de caracteres (strings). Tenga en cuenta que mi respuesta es una pequeña extensión de la respuesta original de @ nico que elimina el "0" inicial de cada bit:
paste(sapply(strsplit(paste(rev(intToBits(12))),""),`[[`,2),collapse="")
[1] "00000000000000000000000000001100"
Para desglosar los pasos, para mayor claridad:
# bit pattern for the 32-bit integer ''12''
x <- intToBits(12)
# reverse so smallest bit is first (little endian)
x <- rev(x)
# convert to character
x <- as.character(x)
# Extract only the second element (remove leading "0" from each bit)
x <- sapply(strsplit(x, "", fixed = TRUE), `[`, 2)
# Concatenate all bits into one string
x <- paste(x, collapse = "")
x
# [1] "00000000000000000000000000001100"
O, como mostró @nico , podemos usar as.integer()
como una forma más concisa de eliminar el cero as.integer()
de cada bit.
x <- rev(intToBits(12))
x <- paste(as.integer(x), collapse = "")
# [1] "00000000000000000000000000001100"
Solo para la conveniencia de copiar y pegar, aquí hay una versión de función de lo anterior:
dec2bin <- function(x) paste(as.integer(rev(intToBits(x))), collapse = "")
intToBits
está limitado a un máximo de 2 ^ 32, pero ¿qué ocurre si queremos convertir 1e10 en binario? Aquí está la función para convertir números flotantes a binarios, asumiendo que son enteros grandes almacenados como numeric
.
dec2bin <- function(fnum) {
bin_vect <- rep(0, 1 + floor(log(fnum, 2)))
while (fnum >= 2) {
pow <- floor(log(fnum, 2))
bin_vect[1 + pow] <- 1
fnum <- fnum - 2^pow
} # while
bin_vect[1] <- fnum %% 2
paste(rev(bin_vect), collapse = "")
} #dec2bin
Esta función comienza a perder dígitos después de 2 ^ 53 = 9.007199e15, pero funciona bien para números más pequeños.
microbenchmark(dec2bin(1e10+111))
# Unit: microseconds
# expr min lq mean median uq max neval
# dec2bin(1e+10 + 111) 123.417 125.2335 129.0902 126.0415 126.893 285.64 100
dec2bin(9e15)
# [1] "11111111110010111001111001010111110101000000000000000"
dec2bin(9e15 + 1)
# [1] "11111111110010111001111001010111110101000000000000001"
dec2bin(9.1e15 + 1)
# [1] "100000010101000110011011011011011101001100000000000000"
paste(rev(as.integer(intToBits(12))), collapse="")
hace el trabajo
paste
con el parámetro de colapso colapsa el vector en una cadena. Sin embargo, debes usar la función rev
para obtener el orden de bytes correcto.
as.integer
elimina los ceros extra
decimal.number<-5
i=0
result<-numeric()
while(decimal.number>0){
remainder<-decimal.number%%2
result[i]<-remainder
decimal.number<-decimal.number%/%2
i<-i+1
}