В книге AssemblyScript упоминается, что Math.random() принимает начальное значение и возвращает значение <f64>. Мне просто нужно случайное значение <u64>. Как мне этого добиться?
Я попытался
(Math.random() * 0xffffffffffffffff) as u64
<u64>(<f64>Math.random() * <f64>0xffffffffffffffff)
(<f64>Math.random() * <f64>0xffffffffffffffff) as u64
или с f64.MAX_VALUE вместо 0xffffffffffffffff и еще много чего.
но я продолжаю получать 0.
Я могу получить <U32> случайные значения просто отлично, но когда я умножаю два <U32> случайных значения, я получаю около 52 случайных битов, а остальное равно 0. Я понимаю, почему это происходит из моего фона JS, все еще из типизированной структуры и абстракций более низкого уровня AS I надеялся, что трений не будет.
Как именно я могу правильно получить <u64> случайное целое число с помощью AssemblyScript?
Редактировать:
Я думаю, что наконец-то сделал это так, как
(<u64>(Math.random() * u32.MAX_VALUE) << 32) | <u32>(Math.random() * u32.MAX_VALUE)
но так ли это на самом деле?
@ Bbrk24 Нет ... только что проверил ((<u32>Math.random() << 32) * 0xffffffffffffffff) as u64 все еще дает 0.
Вы уверены, что <u32>Math.random() работает? Math.random() генерирует в диапазоне [0, 1), который всегда будет давать 0 при преобразовании в целое число. Я представлял, что u32.random больше похож на <u32>(Math.random() * <f64>0xffffffff).
@Bbrk24 Bbrk24 Я не конвертирую Math.random() в целое число, пока не умножу его на достаточно большое число, и да, <u32>(Math.random() * u32.MAX_VALUE) просто отлично работает.
Вот что я имел в виду под u32.random. Я просто использовал его как сокращение, так как не знал точного синтаксиса/реализации.
@ Bbrk24 Bbrk24 Теперь я понял вашу точку зрения в вашем первом комментарии, но со всеми этими типами и всем остальным я думаю, что должен быть более простой способ. Почему бы вам не выполнить эту операцию сразу в 64-битной среде? Особенно Math.random() * 0xffffffffffffffff получение 0 сбивает с толку, учитывая, что Math.random() возвращает <f64>. Возможно, ошибка или что-то, чего мне очень не хватает в общем двоичном представлении чисел.





Прочитав ваш вопрос, я решил изучить, как AssemblyScript реализует Math.random в стандартной библиотеке , чтобы посмотреть, смогу ли я получить вдохновение для решения вашей проблемы.
Забавно, кажется, что он использует murmurhash3 и некоторые дополнительные хэши. Прямо перед возвратом он переинтерпретирует значение u64 в f64 после некоторой дополнительной обработки:
let r = (s0 >> 12) | 0x3FF0000000000000;
return reinterpret<f64>(r) - 1;
Мне стало любопытно, можем ли мы использовать это значение u64 напрямую как число в случайной последовательности, поэтому я переработал задействованные биты и разместил их на github здесь, но основная функция такова:
export function randomU64(): u64 { // see: v8/src/base/utils/random-number-generator.cc
if (!random_seeded) seedRandom(reinterpret<i64>(0)); // TODO: for now, the seed is always 0.
let s1 = random_state0_64;
let s0 = random_state1_64;
random_state0_64 = s0;
s1 ^= s1 << 23;
s1 ^= s1 >> 17;
s1 ^= s0;
s1 ^= s0 >> 26;
random_state1_64 = s1;
return s0;
}
Очень краткий тест показывает, что, по крайней мере, на первый взгляд, он дает довольно хорошие случайные результаты:
Test randomU64 distribution. All values should be fairly close.
Map(19) {
0n => 987,
1n => 495, -1n => 515, 2n => 542, -2n => 489,
3n => 518, -3n => 495, 4n => 479, -4n => 510,
5n => 513, -5n => 497, 6n => 473, -6n => 505,
7n => 468, -7n => 528, 8n => 501, -8n => 472,
9n => 519, -9n => 494
}
Спасибо за вашу попытку. Это интересно. Я должен проверить функцию .popcnt(), чтобы увидеть, получим ли мы 32 в среднем за несколько попыток для ввода типа <u64>. Я думаю, что функциональность seedRandom() реализуется так же, как (Math.random() * Date.now()) as u64.
Я не думал о popcnt для случайности. Он получает 31.9805 среднее значение popcnt для следующих 10000 значений, так что кажется достаточно близким. Я отправил еще один тест в репо.
Выглядит хорошо, но, поскольку мы всегда начинаем с 0, что дает золотое сечение, это довольно детерминировано. Чтобы внести некоторую энтропию, я перефразировал строку 36 в репозитории if (!random_seeded) seedRandom(reinterpret<i64>(Math.random()*<f64>Date.now()));. Теперь даже после перекомпиляции мы получаем разные случайные числа. Стандартное отклонение и среднее значение 10 тестов с 1e6 x 64-битными popcnts составляют 0,0059% и 32,0019481 соответственно.
Использование
u32.randomв качестве соломенного человека для случайного u32: сработает ли((u32.random() as u64) << 32) | (u32.random as u64)? Или побитовые операторы AssemblyScript работают только с 32-битными числами, как в JS?