Самый компактный способ закодировать последовательность двоичных кодов длины случайной переменной?

Скажем, у Вас есть a List> и Вы хотите закодировать это в двоичную форму самым компактным возможным способом.

Я не забочусь о производительности чтения или производительности записи. Я просто хочу использовать минимальную сумму пространства. Кроме того, пример находится в Java, но мы не ограничены системой Java. Длина каждого "Списка" неограниченна. Поэтому любое решение, которое кодирует длину каждого списка, должно сам по себе закодировать тип данных переменной длины.

Связанный с этой проблемой кодирует целых чисел переменной длины. Можно думать о каждом List как переменная длина unsigned integer.

Считайте вопрос тщательно. Мы не ограничены системой Java.

Править

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

Можно думать об этом вопросе по-другому. Позволяет говорят, что у Вас есть список произвольного списка случайных (неограниченных) целых чисел без знака. Как Вы кодируете этот список в двоичном файле?

Исследование

Я сделал некоторое чтение и нашел то, что я действительно ищу, Универсальный код

Результат

Я собираюсь использовать вариант Elias Omega Coding, описанного в газете новый рекурсивный универсальный код положительных целых чисел

Я теперь понимаю, как меньшим представление меньших целых чисел является компромисс с большими целыми числами. Путем простого выбора Универсального кода с "большим" представлением самого первого целого числа Вы оставляете много свободного места в конечном счете, когда необходимо закодировать произвольные большие целые числа.

12
задан 12 revs, 2 users 95% 4 February 2010 в 18:45
поделиться

16 ответов

Я думаю о кодировании битовой последовательности следующим образом:

head  | value
------+------------------
00001 | 0110100111000011

Голова имеет переменную длину. Его конец отмечается первым появлением 1. Подсчитайте количество нулей в заголовке. Длина поля значения будет 2 ^ нулей . Поскольку длина значения известна, это кодирование можно повторить. Поскольку размер заголовка составляет значение журнала , по мере увеличения размера закодированного значения накладные расходы сходятся до 0%.

Добавление

Если вы хотите более точно настроить длину значения, вы можете добавить другое поле, в котором хранится точная длина значения. Длина поля длины может определяться длиной головы. Вот пример с 9 битами.

head  | length | value
------+--------+-----------
00001 | 1001   | 011011001
9
ответ дан 2 December 2019 в 04:43
поделиться

Ну, во-первых, вы захотите собрать эти логики вместе, чтобы вы получили восемь из них в байт. Стандарт C ++ Bitset был разработан для этой цели. Вы, вероятно, должны использовать его, а не на вектор, если можете.

После этого вы могли бы теоретически сжать его, когда вы сохраняете, чтобы получить размер еще меньше. Я бы посоветовал против этого, если ваша спина не на самом деле против стены.

Я говорю в теории, потому что это многое зависит от ваших данных. Не зная о ваших данных, я действительно не могу больше сказать на этом, так как некоторые алгоритмы работают лучше, чем другие на сведениях данных. Фактически, простая теория информации говорит нам, что в некоторых случаях любой алгоритм сжатия будет производить вывод, который занимает больше пространство, чем вы начал.

Если ваш битет довольно редкий (не много 0, или не много из 1-х), или полосатый (длинные пробежки одинакового значения), то возможно, вы можете получить большие выгоды с сжатием. Почти во всех других обстоятельствах не будет нести неприятностей. Даже в этом обстоятельстве это не может быть. Помните, что любой код, который вы добавляете, должны быть отлажены и поддерживаться.

0
ответ дан 2 December 2019 в 04:43
поделиться

Вы можете преобразовать каждый список в Bitset, а затем сериализовать BitSet-S.

0
ответ дан 2 December 2019 в 04:43
поделиться

Я думаю, что «самый компактный путь возможно», вы захотите сжатие, но кодирование Хаффмана может быть не так, как я думаю, он лучше всего работает с алфавитами, которые имеют статические частоты на символ.

Проверьте арифметическое кодирование - он работает на битах и ​​может адаптироваться к динамическим вводным вероятностям. Я также вижу, что есть BSD-лицензионные Java-библиотека , которые сделают это для вас, что, кажется, ожидает, что приятные биты в качестве ввода.

Я полагаю, что для максимального сжатия вы можете объединить каждый внутренний список (префиксирован с его длиной) и снова запустить алгоритм кодирования снова в течение всего.

3
ответ дан 2 December 2019 в 04:43
поделиться

Этот вопрос имеет определенное индукционное ощущение. Вам нужна функция: (bool list) -> (bool list) так, чтобы обратная функция (bool list) -> (bool list) создавала ту же самую исходную структуру, а длина закодированного bool list была минимальной, без ограничений на входную структуру. Так как этот вопрос настолько абстрактен, то я думаю, что эти списки могут быть невообразимо большими - 10^50 может быть, или 10^2000, или они могут быть очень маленькими, как 10^0. Также может быть большое количество списков, опять же 10^50 или просто 1. Так что алгоритм должен подстраиваться под эти сильно различающиеся входы.

Я думаю, что мы можем кодировать длину каждого списка как (bool list), и добавлять один дополнительный bool, чтобы указать, является ли следующая последовательность другой (теперь большей) длиной или реальным битовым потоком.

let encode2d(list1d::Bs) = encode1d(length(list1d), true) @ list1d @ encode2d(Bs)
    encode2d(nil)       = nil

let encode1d(1, nextIsValue) = true :: nextIsValue :: []
    encode1d(len, nextIsValue) = 
               let bitList = toBoolList(len) @ [nextIsValue] in
               encode1d(length(bitList), false) @ bitList

let decode2d(bits) = 
               let (list1d, rest) = decode1d(bits, 1) in
               list1d :: decode2d(rest)

let decode1d(bits, n) = 
               let length = fromBoolList(take(n, bits)) in
               let nextIsValue :: bits' = skip(n, bits) in
               if nextIsValue then bits' else decode1d(bits', length)
assumed library functions
-------------------------

toBoolList : int -> bool list
   this function takes an integer and produces the boolean list representation
   of the bits.  All leading zeroes are removed, except for input '0' 

fromBoolList : bool list -> int
   the inverse of toBoolList

take : int * a' list -> a' list
   returns the first count elements of the list

skip : int * a' list -> a' list
   returns the remainder of the list after removing the first count elements

Накладные расходы по каждому списку штук. Для пустого списка накладные расходы - это 2 дополнительных элемента списка. Для 10^2000 штук накладные расходы составляют 6645 + 14 + 5 + 4 + 3 + 2 = 6673 дополнительных элементов списка.

0
ответ дан 2 December 2019 в 04:43
поделиться

Кроме того, вместо связывания user32.lib вы можете сделать это только с помощью glut:

glutGet(GLUT_SCREEN_WIDTH) // returns Screen width

и

glutGet(GLUT_SCREEN_HEIGHT) // returns Screen height

Зачем зависеть от Windows, когда вы можете быть кроссплатформенным?

Следовательно, ваш код будет выглядеть:

glutInitWindowPosition((glutGet(GLUT_SCREEN_WIDTH)-640)/2,
                       (glutGet(GLUT_SCREEN_HEIGHT)-480)/2);
-121--2938645-

... но как узнать, какой языковой стандарт использует база данных? Могу я проверить это программно...

Для этого не существует портативного (независимого от базы данных) способа, но для получения набора символов, используемого базой данных Orable, можно использовать следующий запрос:

select value from nls_database_parameters where parameter = 'NLS_CHARACTERSET';

На этой странице приведены более подробные сведения.

Что касается сравнения, лучше всего (*) позволить базе данных позаботиться о нижнем корпусе, как предлагает @ Gary. Драйвер JDBC выполняет преобразование последовательностей Java (UTF-16) в все используемые базы данных.

(* На самом деле, я не думаю, что у вас есть большой выбор, если вы не готовы носить стоимость хранения копий со смешанным и более низким регистром всех запрашиваемых последовательностей в базе данных.)

-121--5086207-

Если я правильно понимаю, наша структура данных (1 2 (33483 7) 373404 9 (337652222 37333788))

byte 255 - escape code
byte 254 - begin block
byte 253 - list separator
byte 252 - end block

Итак, мы имеем:

 struct {
    int nmem; /* Won't overflow -- out of memory first */
    int kind; /* 0 = number, 1 = recurse */
    void *data; /* points to array of bytes for kind 0, array of bigdat for kind 1 */
 } bigdat;

 int serialize(FILE *f, struct bigdat *op) {
   int i;
   if (op->kind) {
      unsigned char *num = (char *)op->data;
      for (i = 0; i < op->nmem; i++) {
         if (num[i] >= 252)
            fputs(255, f);
         fputs(num[i], f);
      }
   } else {
      struct bigdat *blocks = (struct bigdat *)op->data
      fputs(254, f);
      for (i = 0; i < op->nmem; i++) {
          if (i) fputs(253, f);
          serialize(f, blocks[i]);
      }
      fputs(252, f);
 }

Существует закон о числовом распределении цифр, который говорит для наборов наборов произвольных беззнаковых целых чисел, что чем выше значение байта, тем меньше это происходит, так что положить специальные коды в конце.

Не кодирование длины перед каждым занимает гораздо меньше места, но делает десериализацию трудным упражнением.

0
ответ дан 2 December 2019 в 04:43
поделиться

Список списка-of-int-binary:

Start traversing the input list
For each sublist:
    Output 0xFF 0xFE
    For each item in the sublist:
        Output the item as a stream of bits, LSB first.
          If the pattern 0xFF appears anywhere in the stream,
          replace it with 0xFF 0xFD in the output.
        Output 0xFF 0xFC

Декодирование:

If the stream has ended then end any previous list and end reading.
Read bits from input stream. If pattern 0xFF is encountered, read the next 8 bits.
   If they are 0xFE, end any previous list and begin a new one.
   If they are 0xFD, assume that the value 0xFF has been read (discard the 0xFD)
   If they are 0xFC, end any current integer at the bit before the pattern, and begin reading a new one at the bit after the 0xFC.
   Otherwise indicate error. 
0
ответ дан 2 December 2019 в 04:43
поделиться

Если я правильно понял вопрос, биты являются случайными, и у нас есть список случайных длинных списков независимо. Поскольку с байтами нет ничего нечего, я буду обсуждать это как немного поток. Поскольку файлы фактически содержат байты, вам нужно будет поставить пакет восемь битов для каждого байта и оставить 0..7 биты последнего байта неиспользованного.

Самый эффективный способ хранения логических ценностей как есть. Просто сбросьте их в битматри как простой массив.

В начале битового потока вам нужно кодировать длину массива. Есть много способов сделать это, и вы можете сэкономить несколько битов, выбрав наиболее оптимальный для ваших массивов. Для этого вы, вероятно, захотите использовать кодирование Хаффмана с фиксированной кодовой книгой, так что обычно используемые и небольшие значения получают кратчайшие последовательности. Если список очень длинный, вы, вероятно, наверное не все равно о размере его кодировки в более длительной форме.

Точный ответ относительно какой кодовой книги (и, следовательно, код Huffman) будет не может быть предоставлен без дополнительной информации об ожидаемом списке.

Если все внутренние списки имеют одинаковый размер (то есть у вас есть 2D-массив), вам нужны только два размера.

Дезерниризация: декодируйте длину и выделяют структуры, затем прочитайте биты один за другим, назначая их структуре в порядке.

0
ответ дан 2 December 2019 в 04:43
поделиться

Как вы указываете, нет причин хранить ваши логические значения, используя больше места, чем один бит. Если вы объедините это с какой-то базовой конструкцией, например, каждая строка начинается с целочисленного кодирования количества битов в этой строке, вы сможете сохранить 2D таблицу любого размера, где каждая запись в строке является одним битом.

Однако этого недостаточно. Строка произвольных 1 и 0 будет выглядеть довольно случайным, и любой алгоритм сжатия ломается, поскольку случайность ваших данных увеличивается - поэтому я бы порекомендовал, как сортировка процесса Burrows-Wheeler, чтобы значительно увеличивать количество повторяющихся «слов» или « блокировки "в ваших данных. После завершения простого кода Хаффмана или алгоритм Lempel-ZIV должен иметь возможность довольно хорошо сжиматься.

Чтобы позволить вышеуказанному методу работать для целых чисел без знака, вы будете сжать целые числа, используя Delta Code, затем выполните сортировку блоков и сжатие (стандартная практика в списках поиска информации).

0
ответ дан 2 December 2019 в 04:43
поделиться

@ Zneak's ответ (победил меня к нему), но используйте Huffman encoded целых чисел, особенно если некоторые длины более вероятны.

Просто должен быть автономным: кодировать количество списков в качестве целочисленного integer Huffman, затем для каждого списка кодируйте свою длину бита как Huffman Conded Integer. Биты для каждого списка следуют без промежутка впустую биты.

Если порядок списков не имеет значения, сортировка их по длине будет уменьшить необходимое пространство, только повышение дополнительной длины каждого последующего списка необходимо кодировать.

0
ответ дан 2 December 2019 в 04:43
поделиться

Я не вижу, как кодирование произвольного набора битов отличается от сжатия/кодирования любой другой формы данных. Обратите внимание, что вы накладываете только свободное ограничение на кодируемые биты: а именно, это списки битов. С этим небольшим ограничением этот список битов становится просто данными, произвольными данными, и это то, что «нормальные» алгоритмы сжатия сжимаются.

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

Учитывая ваши предпосылки и то, как работают алгоритмы сжатия, я бы посоветовал сделать следующее:

  1. Упакуйте биты каждого списка, используя меньшее возможное количество байтов, используя байты в качестве битовых полей, кодируя длину и т.д.
  2. Попробуйте хаффман, арифметику, LZxx и т.д. на результирующем потоке байтов.

Можно утверждать, что это довольно очевидный и простой способ сделать это, и что это не будет работать, так как ваша последовательность битов не имеют известных образцов. Но дело в том, что это лучшее, что можно сделать при любом сценарии.

ЕСЛИ ТОЛЬКО вы не знаете что-то из ваших данных или какое-то преобразование в тех списках, которые заставляют их поднимать какой-то образец. Возьмем, например, кодирование DCT коэффициентов в кодировании JPEG. Способ перечисления этих коэффициентов (диагональных и зигзагообразных) сделан в пользу образца на выходе различных коэффициентов для преобразования. Таким образом, к полученным данным могут применяться традиционные сжатия. Если вы знаете что-то из тех списков битов, которые позволяют перегруппировать их более сжимаемым способом (способ, который показывает некоторые более структуры), то вы получите сжатие.

-121--2771399-

См. Параллельная библиотека задач по сравнению с асинхронными рабочими процессами .

Я бы резюмировал основы:

Task Parallel Library : Позволяет нескольким блокам работы эффективно работать на нескольких ядрах, включая относительно простые сценарии, такие как создание нескольких потоков для выполнения аналогичных вычислений параллельно, а также более сложные операции, где сами вычисления также приводят к созданию дополнительных задач. Использует улучшенный threadpool .NET 4.0 и рабочие очереди кражи для обеспечения занятости всех ядер.

Асинхронные рабочие процессы : позволяет выполнять асинхронные вычисления, не занимая ненужные потоки, инициируя обратные вызовы при наличии результатов.

PLINQ : Код, написанный с помощью PLINQ, работает через TPL, но это более удобный интерфейс для кода, который легко выражается с помощью запросов LINQ (например, выполнение одной операции над каждым предметом в массиве данных параллельно).

Обратить внимание, что async технологические процессы могут быть преобразованы в Задачи, используя метод StartAsTask , и Задачи могут быть преобразованы в Async с, используя Async. Метод AwaitTask , таким образом, возможно соединить технологии,хотя они и нацелены на несколько иные целевые сценарии.

По моему мнению, главное правило состоит в том, что если вы активно выполняете много вычислений на разных потоках, вы захотите использовать TPL (возможно, через PLINQ или эквивалент F #, такой как модуль PSeq), тогда как если вы пытаетесь выполнять много операций ввода-вывода (параллельных или нет), вы должны использовать асинхронные рабочие процессы. Так что raytracer будет использовать TPL для запуска задач, чтобы визуализировать каждый пиксель (или scanline) параллельно, максимизируя доступную вычислительную мощность на компьютере. Но загрузка множества веб-страниц будет выполнена с асинхронными рабочими процессами, так как нет большого количества вычислений для распространения среди ядер; вы просто должны быть уведомлены ОС, когда результаты поступят.

-121--3632147-

Теоретические пределы

На этот вопрос трудно ответить, не зная больше о данных, которые предполагается сжать; ответ на ваш вопрос может быть разным с различными доменами.

Например, из раздела Ограничения статьи Википедии о сжатии без потерь :

Алгоритмы сжатия данных без потерь не могут гарантировать сжатие для всех наборов входных данных. Другими словами, для любого алгоритма сжатия данных без потерь будет существовать набор входных данных, который не уменьшается при обработке алгоритмом. Это легко доказано с элементарной математикой, используя аргумент подсчета....

В основном, поскольку теоретически невозможно сжать все возможные входные данные без потерь, невозможно даже эффективно ответить на ваш вопрос.

Практический компромисс

Просто используйте Huffman, DEFLATE, 7Z или какой-нибудь ZIP-подобный готовый алгоритм сжатия и преобразуйте биты в массивы байтов переменной длины (или списки, или векторы, или что бы они ни назывались на Java или любом языке, который вам нравится). Конечно, для обратного считывания битов может потребоваться немного декомпрессии, но это может быть сделано за кадром. Можно создать класс, который скрывает внутренние методы реализации для возврата списка или массива логических значений в некотором диапазоне индексов, несмотря на то, что данные хранятся внутри массива байтов пакета. Обновление логического значения в заданном индексе или индексах может быть проблемой, но ни в коем случае невозможно.

2
ответ дан 2 December 2019 в 04:43
поделиться

List-of-Lists-of-Ints-Encoding:

  • Когда вы приходите к началу списка, записывайте биты для ASCII '['. Затем переходите к списку.

  • Когда вы приходите к любому произвольному двоичному числу, запишите биты, соответствующие десятичному представлению числа в ASCII. Например, число 100, запишите 0x31 0x30 0x30. Затем запишите биты, соответствующие ASCII ','.

  • Когда вы подойдете к концу списка, запишите биты для ']'. Затем напишите ASCII ',''.

Эта кодировка закодирует любую арбитражную вложенность произвольной длины списков неограниченных целых чисел. Если эта кодировка недостаточно компактна, следуйте за ней с помощью gzip для устранения избыточности в ASCII-битной кодировке.

1
ответ дан 2 December 2019 в 04:43
поделиться

JDBC API является отличным примером для этого. В этом пути драйвер JDBC можно настроить извне, например, в файле свойств

driver = com.dbvendor.jdbc.Driver
url = jdbc:dbvendor://localhost/dbname
username = stackoverflow
password = youneverguess

.. который можно использовать как

Properties properties = new Properties();
properties.load(Thread.currentThread().getResourceAsStream("jdbc.properties"));

String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String username = properties.getProperty("username");
String password = properties.getProperty("password");

Class.forName(driver);
Connection connection = DriverManager.getConnection(url, username, password);

Каждая реализация драйвера JDBC в основном регистрируется в DriverManager внутри статического блока инициализатора. Это именно тот, который выполняется во время Class # forName () .

package com.dbvendor.jdbc;

public class Driver implements java.sql.Driver {

    static {
         java.sql.DriverManager.registerDriver(new Driver());
    }

    private Driver() {
        // ...
    }

    public boolean acceptsURL(String url) {
        return url.startsWith("jdbc:dbvendor");
    }

}

Поскольку DriverManager примерно выглядит так (он фактически использует старомодный Vector )

private static final Set<Driver> drivers = new HashSet<Driver>();

public static void registerDriver(Driver driver) {
    drivers.add(driver);
}

public static Connection getConnection(String url, String username, String password) throws SQLException {
    for (Driver driver : drivers) {
        if (driver.acceptsURL(url)) {
            return driver.connect(url, username, password);
        }
    }
    throw new SQLException("No suitable driver");
}

... вы можете получить от него подключение без необходимости создания экземпляра самого драйвера!

В этом пути код JDBC является очень портативным. Можно изменить БД или распределить код между пользователями с различными БД без необходимости изменения/взлома/перестроения самого кода.

Этот подход используют не только JDBC, но и другие API, такие как Servlet API, ORM, такие как Hibernate/JPA, рамки ввода зависимостей и т.д. использует отражение для загрузки классов на основе настраиваемых извне файлов свойств, файлов конфигурации XML и/или аннотаций. Все это делает код более портативным и съемным.

-121--1732675-

из моего опыта поведение статики, определенной в области действия файла, отличается от статики, определенной в функции

Область действия файла инициализируется безопасно до того, как все потоки переходят, область действия функции отсутствует.

Обратите внимание, что это, по-видимому, зависит от версий компилятора (которые вы ожидаете, учитывая, что мы идем в «неопределенных» областях поведения)

-121--3113862-

У меня есть подозрение, что вы просто не можете кодировать действительно случайный набор битов в более компактную форму в худшем случае. Любой вид RLE собирается раздуть набор только на неправильном входе, хотя это будет хорошо в среднем и лучших случаях. Любой вид периодической или специфической аппроксимации будет терять данные.

Как заявил один из других плакатов, вы должны знать НЕЧТО о наборе данных, чтобы представить его в более компактной форме и/или вы должны принять некоторые потери, чтобы получить его в предсказуемую форму, которая может быть более компактно выражена.

На мой взгляд, это информационно-теоретическая проблема с ограничением бесконечной информации и нулевыми потерями. Вы не можете представить информацию в другом пути, и вы не можете приблизить ее как что-то более легко представить. Эрго, тебе нужно как минимум столько места, сколько у тебя есть информации и не меньше.

http://en.wikipedia.org/wiki/Information_theory

Вы всегда можете обмануть, я полагаю, и манипулировать аппаратными средствами, чтобы закодировать дискретный диапазон значений на носителе, чтобы выдумать еще несколько «битов на бит» (мысленное мультиплексирование). Вы бы потратили больше времени на его кодирование и чтение.

Практически, вы всегда можете попробовать эффект «jiggle», где вы кодируете данные несколько раз несколькими способами (попробуйте интерпретировать как аудио, видео, 3d,периодические, последовательные, основанные на ключах, diffs и т.д.) и в нескольких размерах страниц и выбрать лучшие. Вам будет гарантировано лучшее РАЗУМНОЕ сжатие, и ваш худший случай будет не хуже, чем ваш исходный набор данных.

Не знаю, если это даст вам теоретическое лучшее.

3
ответ дан 2 December 2019 в 04:43
поделиться

Я бы использовал целые числа переменной длины для кодирования того, сколько там бит для чтения. MSB будет указывать, является ли следующий байт частью целого числа. Например:

11000101 10010110 00100000

фактически означало бы:

   10001 01001011 00100000

поскольку целое число продолжается 2 раза.

Эти целые числа переменной длины будут рассказать, сколько битов следует читать. И там был бы еще одна длина переменной длины в начале всех, чтобы рассказать, сколько там битов есть.

Оттуда на, предположим, что вы не хотите использовать сжатие, единственный способ, которым я могу видеть, чтобы оптимизировать его размер - это адаптировать его к вашей ситуации. Если у вас часто есть большие наборы битов, вы можете, например, чтобы использовать короткие целые числа вместо байтов для целочисленного кодирования переменной длины, что позволяет вам потенциально тратить меньшие биты в самой кодировке.


Редактировать Я не думаю, что существует идеальный способ достижения всех, как вы хотите, все сразу. Вы не можете создавать информацию из ничего, и если вам нужна целые числа переменной длины, вы, очевидно, приходится кодировать длину целой группы тоже. Существует обязательно компромисс между пространством и информацией, но есть также минимальная информация, которую вы не можете сократить, чтобы использовать меньше места. Нет системы, где факторы растут по разным ставкам, когда-либо будут масштабироваться идеально. Это как пытаться установить прямую линию по логарифмической кривой. Вы не можете это сделать. (И, кроме того, это в значительной степени, что именно вы пытаетесь сделать здесь.)

Вы не можете кодировать длину целого числа переменной длины за пределами целого числа и получить неограниченное количество вариабельных чисел размера одновременно, потому что потребует в самой длине, которая должна быть переменной длиной, и любой любой алгоритм вы выберете, мне кажется здравым смыслом, что вам будет лучше с одним целым числом переменной длины вместо двух или более из них.

Итак, вот моя другая идея: в целочисленном «заголовке», напишите один 1 для каждого байта целое число переменной, требует оттуда. Первый 0 обозначает конец «заголовка» и начало самого целого числа.

Я пытаюсь постичь точное уравнение, чтобы определить, сколько бит требуется для хранения данного целого числа для двух способов, которыми я дал, но мои логарифмы ржавые, поэтому я поговорку и редактирую это сообщение включить результаты.


Редактировать 2 Вот уравнения:

  • раствор один, 7 бит в кодировке (один полный байт за раз):
    y = 8 * Ceil (log (x) / (7 * log (2)))
  • Решение One, 3 бита на кодирующий бит (один zamble за раз):
    y = 4 * Ceil (log (x) / (3 * log (2)))
  • Решение два, 1 байт на кодирование Бит плюс сепаратор:
    y = 9 * Ceil (log (x) / (8 * log (2))) + 1
  • Решение два, 1 Zibble на кодирующий бит плюс сепаратор:
    y = 5 * CEIL (log (x) / (4 * log (2))) + 1

Я предлагаю вам потратить время на сюжету (лучше всего смотреть с системой логарифмических координат), чтобы получить идеал Решение для вашего случая, потому что нет идеального решения . На мой взгляд, первое решение имеет самые стабильные результаты.

4
ответ дан 2 December 2019 в 04:43
поделиться

Вместо статических многомерных массивов, вероятно, следует использовать одномерный массив и вычислять индекс путем умножения. Например,

class Array3D {
    size_t m_width, m_height;
    std::vector<int> m_data;
  public:
    Array3D(size_t x, size_t y, size_t z, int init = 0):
      m_width(x), m_height(y), m_data(x*y*z, init)
    {}
    int& operator()(size_t x, size_t y, size_t z) {
        return m_data.at(x + y * m_width + z * m_width * m_height);
    }
};

// Usage:
Array3D arr(10, 15, 20, 100); // 10x15x20 array initialized with value 100
arr(8, 12, 17) = 3;

std:: vector распределяет место хранения динамически, что хорошо, потому что пространство стека часто очень ограничено, и 3D массивы легко используют много пространства. Перенос его в такой класс также делает передачу массива (путем копирования или ссылки) другим функциям тривиальной, в то время как выполнение любой передачи многомерных статических массивов очень проблематично.

Приведенный выше код является просто примером и может быть оптимизирован и сделан более полным. Также, конечно, существуют реализации этого в различных библиотеках, но я не знаю ни одной.

-121--1314546-

Решение, попробуйте вызвать новый ActiveXObject:


function testForActiveX(){
    tester = null;
    try {
        tester = new ActiveXObject('htmlfile');
    }
     catch (e) {
        // catch the exception
    }
    if (tester) {
        // ActiveX is installed
        return true;
    }
    return false;
}
-121--1742766-

Я не вижу, как кодирование произвольного набора битов отличается от сжатия/кодирования любой другой формы данных. Обратите внимание, что вы накладываете только свободное ограничение на кодируемые биты: а именно, это списки битов. С этим небольшим ограничением этот список битов становится просто данными, произвольными данными, и это то, что «нормальные» алгоритмы сжатия сжимаются.

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

Учитывая ваши предпосылки и то, как работают алгоритмы сжатия, я бы посоветовал сделать следующее:

  1. Пакетом биты каждого списка, используя меньшее возможное количество байтов, используя байты в качестве битовых полей, кодируя длину и т. д.
  2. Попробуйте хаффман, арифметику, LZxx и т. д. на результирующем потоке байтов.

Можно утверждать, что это довольно очевидный и простой способ сделать это, и что это не будет работать, так как ваша последовательность битов не имеют известных образцов. Но дело в том, что это лучшее, что можно сделать при любом сценарии.

ЕСЛИ ТОЛЬКО вы не знаете что-то из ваших данных или какое-то преобразование в тех списках, которые заставляют их поднимать какой-то образец. Возьмем, например, кодирование DCT коэффициентов в кодировании JPEG. Способ перечисления этих коэффициентов (диагональных и зигзагообразных) сделан в пользу образца на выходе различных коэффициентов для преобразования. Таким образом, к полученным данным могут применяться традиционные сжатия. Если вы знаете что-то из тех списков битов, которые позволяют перегруппировать их более сжимаемым способом (способ, который показывает некоторые более структуры), то вы получите сжатие.

3
ответ дан 2 December 2019 в 04:43
поделиться

Я мало что знаю о Java, поэтому полагаю, что мое решение ДОЛЖНО быть общим:)

1. Сжатие списков

Поскольку логические значения неэффективны, каждый List должен быть сжат в List , это легко, просто возьмите их 8 за раз.

Последний «байт» может быть неполным, поэтому вам, конечно же, нужно сохранить, сколько бит было закодировано.

2. Сериализация списка элементов

У вас есть 2 способа продолжить: либо вы кодируете количество элементов в списке, либо используете шаблон, чтобы отметить конец. Я бы порекомендовал кодировать количество элементов, шаблонный подход требует экранирования, и это жутко, плюс сложнее с упакованными битами.

Для кодирования длины вы можете использовать переменную схему: то есть количество байтов, необходимое для кодирования длины, должно быть пропорционально длине, которую я уже использовал. Вы можете указать, сколько байтов используется для кодирования самой длины, используя префикс в первом байте:

0... .... > this byte encodes the number of items (7 bits of effective)
10.. .... / .... .... > 2 bytes
110. .... / .... .... / .... .... > 3 bytes

Это довольно эффективно по пространству, и декодирование происходит по целым байтам, так что это не слишком сложно. Можно заметить, что это очень похоже на схему UTF8 :)

3. Применить рекурсивно

List > становится [Length Item ... Item] , где каждый Item сам по себе является представлением List < Логическое значение>

4. Zip

Я полагаю, что для Java доступна библиотека zlib или что-то еще, например deflate или lcw . Передайте ему свой буфер и убедитесь, что вы хотите максимально возможное сжатие, независимо от времени, которое на это потребуется.

Если в вашем представлении есть повторяющийся узор (даже тот, который вы не видели), он должен иметь возможность его сжать. Не верьте этому тупо и ОБЯЗАТЕЛЬНО проверяйте, что «сжатая» форма легче, чем «несжатая», это не всегда так.

5. Примеры

Где можно заметить, что отслеживание края списков занимает много места:)

// Tricky here, we indicate how many bits are used, but they are packed into bytes ;)
List<Boolean> list = [false,false,true,true,false,false,true,true]
encode(list) == [0x08, 0x33] // [00001000, 00110011]  (2 bytes)

// Easier: the length actually indicates the number of elements
List<List<Boolean>> super = [list,list]
encode(super) == [0x02, 0x08, 0x33, 0x08, 0x33] // [00000010, ...] (5 bytes)

6. Потребление места

Предположим, у нас есть List из n логических значений, пространство, используемое для его кодирования, составляет:

booleans = ceil( n / 8 )

Для кодирования количества бит ( n ) нам нужно:

length = 1   for 0    <= n < 2^7   ~ 128
length = 2   for 2^7  <= n < 2^14  ~ 16384
length = 3   for 2^14 <= n < 2^21  ~ 2097152
...
length = ceil( log(n) / 7 )  # for n != 0 ;)

Таким образом, чтобы полностью закодировать список:

bytes =
 if n == 0: 1
 else     : ceil( log(n) / 7 ) + ceil( n / 8 )

7. Небольшие списки

Однако есть один угловой случай: нижний предел диапазона (то есть почти пустой список).

Для n == 1 , байта оцениваются как 2 , что действительно может показаться расточительным. Я бы, однако, не пытался угадывать, что произойдет, когда начнется сжатие.

Вы можете упаковать еще больше. Это возможно, если мы откажемся от идеи сохранения целых байтов ...

  1. Сохраните кодировку длины как есть (в целых байтах), но не «дополняйте» List .Список из одного элемента становится 0000 0001 x (9 бит)
  2. Попробуйте также «упаковать» кодировку длины

Второй пункт более сложен, мы фактически дошли до кодирования двойной длины. :

  1. Указывает, сколько битов кодирует длину
  2. Фактически кодирует длину этих битов

Например:

0  -> 0 0
1  -> 0 1
2  -> 10 10
3  -> 10 11
4  -> 110 100
5  -> 110 101
8  -> 1110 1000
16 -> 11110 10000 (=> 1 byte and 2 bits)

Это работает довольно хорошо для очень маленьких списков, но быстро вырождается:

# Original scheme
length = ceil( ( log(n) / 7)

# New scheme
length = 2 * ceil( log(n) )

Точка разрыва? 8

Да, вы все правильно прочитали, это лучше только для списка с менее чем 8 элементами ... и лучше только по «битам».

n         -> bits spared
[0,1]     ->  6
[2,3]     ->  4
[4,7]     ->  2
[8,15]    ->  0    # Turn point
[16,31]   -> -2
[32,63]   -> -4
[64,127]  -> -6
[128,255] ->  0    # Interesting eh ? That's the whole byte effect!

И, конечно же, как только сжатие сработает, скорее всего, это не будет иметь никакого значения.

Я понимаю, что вам может понравиться рекурсивный алгоритм, но я все же посоветовал бы вычислить цифры фактического потребления места или, еще лучше, проверить его с архивированием, применяемым на реальных тестовых наборах.

8. Рекурсивное / переменное кодирование

Я с интересом прочитал ответ TheDon и ссылку, которую он отправил на Elias Omega Coding .

Это разумные ответы в теоретической области. К сожалению, они совершенно непрактичны. Основная проблема в том, что у них чрезвычайно интересное асимптотическое поведение, но когда нам действительно нужно кодировать данные размером в гигабайт? Редко, если вообще.

Недавнее исследование использования памяти на работе показало, что большинство контейнеров использовалось для дюжины элементов (или нескольких десятков). Только в очень редких случаях мы достигаем тысячи.Конечно, для вашей конкретной проблемы лучшим способом было бы фактически изучить ваши собственные данные и увидеть распределение значений, но по опыту я бы сказал, что вы не можете просто сосредоточиться на верхней части спектра, потому что ваши данные лежат в нижней части .

Пример алгоритма TheDon . Скажем, у меня есть список [0,1,0,1,0,1,0,1]

len('01010101') = 8 -> 1000
len('1000')     = 4 -> 100
len('100')      = 3 -> 11
len('11')       = 2 -> 10

encode('01010101') = '10' '0' '11' '0' '100' '0' '1000' '1' '01010101'

len(encode('01010101')) = 2 + 1 + 2 + 1 + 3 + 1 + 4 + 1 + 8 = 23

Давайте создадим небольшую таблицу с различными «порогами», чтобы остановить рекурсию. Он представляет количество служебных битов для различных диапазонов n .

threshold     2    3    4    5      My proposal
-----------------------------------------------
[0,3]    ->   3    4    5    6           8
[4,7]    ->   10   4    5    6           8
[8,15]   ->   15   9    5    6           8
[16,31]  ->   16   10   5    6           8
[32,63]  ->   17   11   12   6           8
[64,127] ->   18   12   13   14          8
[128,255]->   19   13   14   15         16

Честно говоря, я сосредоточился на низком уровне, и мое предложение подходит для этой задачи. Я хотел подчеркнуть, что все не так однозначно. Особенно потому, что около 1 функция log почти линейна, и, таким образом, рекурсия теряет свое очарование.Порог очень помогает, и 3 кажется хорошим кандидатом ...

Что касается кодирования Elias omega , оно еще хуже. Из статьи в Википедии:

17 -> '10 100 10001 0'

Вот и все, кричащие 11 бит.

Мораль: нельзя выбрать схему кодирования без учета имеющихся данных.

Итак, если ваш List не имеет длины в сотни, не беспокойтесь и придерживайтесь моего небольшого предложения.

7
ответ дан 2 December 2019 в 04:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: