Почему мои случайные двоичные данные, сгенерированные в JavaScript, очень сжимаемы?

#javascript

#язык JavaScript

Вопрос:

Моя цель-генерировать несжимаемые данные в Javascript, например /dev/urandom

Я использовал следующую команду со своего Mac, и я получил 31,5 Мб данных, которые невозможно сжать с помощью ZIP или RAR.

 dd if=/dev/urandom of=file.txt bs=1048576 count=30   

Но когда я пытаюсь создать несжимаемые данные в Javascript, например /dev/urandom

Это очень легко сжать в WinRAR. WinRAR сжат до менее чем 1 МБ. В Zip он сжимается до 30 МБ

Вот мой код

 lt;!DOCTYPE htmlgt; lt;html lang="en"gt; lt;headgt;  lt;meta charset="UTF-8"gt;  lt;meta http-equiv="X-UA-Compatible" content="IE=edge"gt;  lt;meta name="viewport" content="width=device-width, initial-scale=1.0"gt;  lt;titlegt;How to generate Incompressible data in Javascript like /dev/urandomlt;/titlegt; lt;/headgt; lt;bodygt;  lt;scriptgt; var ulDataSize = 30; //Mb var mData = new Float64Array(131072); var n = mData.length;  for (var i = 0; i lt; n; i  )  {  mData[i] = Math.random()*9;  } var uploadData = [];  for (var i = 0; i lt; ulDataSize; i  ) uploadData.push(mData);  uploadData = new Blob(uploadData, { type: "application/octet-stream" });  function download(text, name, type) {  var a = document.getElementById("a");  //var file = new Blob([text], {type: type});  a.href = URL.createObjectURL(uploadData);  a.download = name; }   lt;/scriptgt;   lt;a href="" id="a"gt;click here to Download Incompressible datalt;/agt; lt;button onclick="download('file text', 'Incompressibledata.txt', 'text/plain')"gt; Generate Datalt;/buttongt;  lt;/bodygt; lt;/htmlgt;  

Комментарии:

1. Во-первых, попробуйте переключиться на uint8array и вместо этого использовать все значения.

2. Кроме того, в чем смысл повторного использования одних и тех же данных 30 раз? Таким образом, он явно поддается сжатию…

3. Потому что это не совсем случайно. Как отметил @user202729, вы повторяете блок случайных данных 30 раз, что недостаточно случайно

4. Это не те же самые данные. См. Math.random внутри forloop.

5. @user3642342 — for (var i = 0; i lt; ulDataSize; i ) uploadData.push(mData); явно повторно использует те же данные ulDataSize , что и в комментариях выше.

Ответ №1:

Кроме того, ты повторяешь одни и те же данные 30 раз (который по своей сути является неслучайной), я не думаю, что Math.random() * 9 производит значения, во всем диапазоне битовых масок, что один и тот же элемент Float64Array может содержать (хотя мой двоичной с плавающей запятой знаний не достаточно для обслуживания сомневаюсь, что с данными), что означает более битовых масок будет повторяться, уменьшения случайности.

Чтобы быть уверенным, я бы, вероятно, использовал a Uint8Array со значениями в полном диапазоне от 0 до 255, с тех пор я уверен, что использую все битовые шаблоны; что-то вроде этого:

 function download(name) {  const blocks = Array.from(  {length: 30},  () =gt; Uint8Array.from(  {length: 1024 * 1024},  () =gt; Math.floor(Math.random() * 256)  )  );  const blob = new Blob(blocks, {type: "application/octet-stream"});  const a = document.getElementById("a");  a.href = URL.createObjectURL(blob);  a.download = name; }  

Обратите внимание, что я удалил неиспользуемые name и type параметры.

Когда я использую это gzip (инструмент, который у меня есть под рукой), размер результирующего файла не уменьшается (он увеличивается с 31 457 280 байт до 31 462 121 байта).

Это много вызовов Math.random() , но нам в основном гарантировано, что мы полностью изучим доступные битовые шаблоны. Возможно, вы сможете сократить количество звонков с помощью a Uint16Array или a Uint32Array . Например:

 const blockSize = (1024 * 1024) / 4; const blocks = Array.from(  {length: 30},  () =gt; Uint32Array.from(  {length: blockSize},  () =gt; Math.random() * 4294967296  ) );  

Для меня gzip все еще ничего не могло с этим поделать (тот же результат, что и выше), но на создание ушло чуть больше четверти времени.

Использование a Float64Array не сработало (для меня), по-видимому Math.random , не исследует весь спектр битовых шаблонов, возможных в 64-разрядном двоичном числе с плавающей запятой IEEE-754, и/или формат имеет (вероятно, небольшие) неиспользуемые диапазоны. Таким образом, 32-разрядные int могут быть лучшим компромиссом.

Комментарии:

1. это работает, ZIP и ZAR не имеют никакого значения. Потрясающе.

2. Но это требует больших затрат процессора. Занимаю секунду или две в моем i7 MBP. Можем ли мы сделать его немного более эффективным для процессора?. И все равно это Потрясающе!. Большое спасибо.

3. @user3642342 — Ну, это 30 миллионов звонков Math.random , не большой шок, если это займет какое-то время. Похоже, вы можете звонить Math.random меньше, используя a Uint32Array (см. Обновление). Все еще работал на меня, ваш пробег может отличаться.

4. Да, теперь это в 2 раза быстрее.

5. @user3642342 — Ха, я получил не совсем 4 раза с моей стороны, но реализации различаются. 🙂