Преобразование десятичного в двоичный в R?
Каким будет самый простой способ преобразования числа в базу 2 (в строке, как, например, 5, будет преобразован в "0000000000000101"
) в R? Существует intToBits
, но он возвращает вектор строк, а не строку:
> 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
Я пробовал некоторые другие функции, но не имел успеха:
> 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"
Ответы
Ответ 1
Обратите внимание, что intToBits()
возвращает "сырой" вектор, а не символьный вектор (строки). Обратите внимание, что мой ответ является небольшим расширением @nico исходного ответа, который удаляет начальный "0" из каждого бита:
paste(sapply(strsplit(paste(rev(intToBits(12))),""),'[[',2),collapse="")
[1] "00000000000000000000000000001100"
Чтобы разбить шаги, для ясности:
# 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"
Или, как показал @nico, мы можем использовать as.integer()
как более краткий способ удаления начального нуля из каждого бита.
x <- rev(intToBits(12))
x <- paste(as.integer(x), collapse = "")
# [1] "00000000000000000000000000001100"
Просто для удобства копирования и вставки здесь приведена функциональная версия выше:
dec2bin <- function(x) paste(as.integer(rev(intToBits(x))), collapse = "")
Ответ 2
paste(rev(as.integer(intToBits(12))), collapse="")
выполняется ли работа
paste
с параметром collapse
свертывает вектор в строку. Вы должны использовать rev
, чтобы получить правильный порядок байтов.
as.integer
удаляет лишние нули
Ответ 3
Я думаю, что вы можете использовать пакет R.utils, тогда функция intToBin()
>library(R.utils)
>intToBin(12)
[1] "1100"
> typeof(intToBin(12))
[1] "character"
Ответ 4
intToBits
ограничено максимум 2 ^ 32, но что, если мы хотим преобразовать 1e10 в двоичный? Вот функция преобразования чисел с плавающей запятой в двоичный код, предполагая, что они являются большими целыми числами, хранящимися как 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
Эта функция начинает потерять цифры после 2 ^ 53 = 9.007199e15, но отлично работает для меньших чисел.
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"
Ответ 5
Посмотрите на пакет R.utils - там у вас есть функция intToBin...
http://rss.acs.unt.edu/Rdoc/library/R.utils/html/intToBin.html
Ответ 6
О, но что делать, если у вас есть 64-битное целое число, включенное пакетом bit64? Каждый ответ, отличный от @epwalsh, не будет работать с 64-битным целым числом, потому что внутренние элементы на основе R из R и R.utils не поддерживают его. Решение @epwalsh отлично работает и работает в R, если вы сначала загрузите пакет bit64
, за исключением того, что он (используя петли) в R является медленным (медленная скорость).
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
Мы можем сделать это лучше, если мы его скомпилируем...
library(compiler)
c.dectobin <- cmpfun(o.dectobin)
system.time({sapply(dat,c.dectobin)})
# user system elapsed
# 38.260 0.010 38.222
... но он все еще довольно медленный. Мы можем получить значительно быстрее, если мы напишем наши собственные внутренности в C (что я сделал здесь заимствование из кода @epwalsh - я не программист на 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
`` `
Ответ 7
Эта функция принимает десятичное число и возвращает соответствующую двоичную последовательность, т.е. вектор 1 и 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)
}
Ответ 8
Попробуйте "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
Ответ 9
--originally добавлено в качестве правки к ответу @JoshuaUlrich, поскольку оно полностью является следствием его и @nico's; он предложил добавить отдельный ответ, поскольку он представляет пакет за пределами его ken--
Поскольку ответ @JoshuaUlrich является настолько функциональным (6 параллельных функций), я считаю, что оператор конвейера (%>%
) из magrittr
/tidyverse
делает следующее решение более элегантным:
library(magrittr)
intToBits(12) %>% rev %>% as.integer %>% paste(collapse = '')
# [1] "00000000000000000000000000001100"
Мы также можем добавить один последний вызов as.integer
, чтобы обрезать все эти ведущие нули:
intToBits(12) %>% rev %>% as.integer %>% paste(collapse = '') %>% as.integer
# [1] 1100
(обратите внимание, что это снова сохраняется как integer
, то есть R рассматривает его как 1100, представленное в базе 10, а не 12, представленное в базе 2)
Обратите внимание, что подход @ramanudle (и других, в частности @russellpierce, который дает реализацию C++) часто является стандартом, предлагаемым в низкоуровневых языках, поскольку это довольно эффективный подход (и он работает для любого числа, которое может храниться в R, т.е. не ограничено диапазоном integer
.
Также стоит отметить, что реализация C intToBits
удивительно проста - смотрите https://en.wikipedia.org/wiki/Bitwise_operations_in_C о деталях, которые могут быть незнакомы пользователям, использующим только R
Ответ 10
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
}