R предоставляет функцию set.seed для заполнения ГСЧ целым числом. Стандартный пакет digest может хэшировать объекты с помощью различных хэш-алгоритмов и может выводить ASCII-представление хеша или вектор необработанных байтов, но не может создавать целое число. Как я могу использовать хэш произвольного объекта для заполнения ГСЧ?

1
Kodiologist 14 Сен 2018 в 17:50

2 ответа

Лучший ответ

Похоже, что set.seed - единственный интерфейс для заполнения RNG R. И целые числа R всегда 32-битные, даже на 64-битных машинах. Итак, нам нужно использовать 32-битный хеш. digest предоставляет несколько 32-битных хэшей, но raw = TRUE игнорируется для всех из них, поэтому нам нужно выполнить некоторые строковые операции с шестнадцатеричным представлением хэша. Собираем все вместе:

set.seed.obj = function(x)
   {x = as.raw(as.hexmode(substring(
        digest::digest(x, algo = "xxhash32"),
        c(1, 3, 5, 7),
        c(2, 4, 6, 8))))
    x = rawConnection(x)
    set.seed(readBin(x, "int"))
    close(x)}

set.seed.obj("hello world")
print(rnorm(3))
set.seed.obj("goodbye world")
print(rnorm(3))
set.seed.obj("hello world")
print(rnorm(3))

Удивительно, но первое присвоение x необходимо: вызов rawConnection для выражения as.raw(...) напрямую приводит к Error in rawConnection…: invalid 'description' argument. Очевидно, R дает сбой при попытке создать строковое представление аргумента для атрибута соединения description.

1
Kodiologist 12 Окт 2018 в 21:15

Интерфейс для set.seed() действительно задан и принимает только целое число. Это дизайнерское решение, и оно неплохое: set.seed(123) легко записать, и впоследствии гарантируется контролируемое поведение.

Если вы действительно копнете глубже, то внутри нескольких (!!) ГСЧ, используемых R, есть намного больше , и они разные, между ними можно переключаться, и даже по умолчанию вы получаете (насколько я помню) разные для равномерных и обычных розыгрышей. Тем не менее, интерфейс раздачи охватывает и то, и другое.

А на уровне C задействована гораздо большая (более сложная) структура данных.

Теперь мой пакет дайджест. Он действительно работает с произвольными объектами R, возвращающими строковые объекты. Таким образом, это не помогает с set.seed(), поскольку эти символы не являются целыми числами. Но вы можете, например, установить промежуточный слой, где вы снова «хэшируете» эти символьные строки в целые числа.

Короче, думаю, нужно немного переосмыслить свой дизайн.

Изменить: По запросу, даже если я думаю, что это не способ сделать это:

 R> c2i <- function(s) sum(as.integer(charToRaw(s)))
 R> c2i(digest(42))
 [1] 2332
 R> set.seed(c2i(digest(42)))
3
Dirk Eddelbuettel 14 Сен 2018 в 15:28