Как последовательность чисел может быть преобразована в одно число?

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

1,6,7,8,9,45,67

вот, например, если я применяю простое добавление, т. е. 1+6+7+8+9+45+67 затем будет сгенерировано число. Но от этого нет. мы не можем извлечь отдельные числа с их упорядочением[т. е. 1,6,7,8,9,...].

есть ли способ достичь этого особенность без какого-либо двусмысленного вывода [i.e из числа будет извлечен только 1 уникальный набор чисел.]? Есть ли математическая функция, которая поможет вернуть отдельные элементы из этого числа?

8 ответов


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

обновление

основываясь на различных комментариях, я хотел бы предложить альтернативное решение, которое может быть проще реализовать. Вы можете считать последовательность кодированной строкой UTF-8 и использовать кодирование Хаффмана с пользовательским словарем для достижения компактного представления.

пользовательские словарь позволяет хранить очень распространенные символы с очень небольшим количеством битов (например, разделитель последовательности", "и отдельные символы "0"..'9' может храниться всего с 3 битами, но и другие числа, которые вы найдете статистически вероятными, могут быть сохранены в короткой битовой последовательности. Например, если вы обнаружите, что "42" происходит часто, вы можете сохранить "42" всего за несколько бит.

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

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

Я сделал что-то вроде этого, используя SharpZipLib

http://www.icsharpcode.net/opensource/sharpziplib/

http://community.sharpdevelop.net/forums/p/8255/23219.aspx

Это также легко сделать с помощью zlib

сжатие небольшой части данных


это математически возможно сделать для конечных последовательностей, но не очень практично, потому что требуемые числа становятся очень большими очень быстро: есть 677 (около 242) разная длина-7 последовательностей целых чисел от 1 ... 67, не говоря уже о более длинных последовательностях и больших целых числах.

для простого примера такой функции сопоставьте последовательность [1,6,7,8,9,45,67] со значением 21 * 36 * 57 * 78 * 119 * 1345 * 1767. Основания-это простые числа, степени-это элементы в последовательности.

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

если вы хотите разрешить 0 в последовательности, а также положительных чисел, затем добавить 1 ко всем элементам, когда вы поднимаете простых полномочий. Или альтернативно использовать силу 2 чтобы дать длину последовательности, а затем начать кодирование элементы, начиная с 3.

Гедель использовал такие кодировки в доказательстве своих теорем неполноты.

как говорит Кендалл Фрей, невозможно определить функцию, которая отображает каждый бесконечный последовательность целых чисел в другое целое число. Это следствие Доказательство Кантора, что набор степеней натуральных чисел неисчислим: вы даже не можете инъективно отобразить все бесконечные последовательности элементов из {true, false} к целым числам, не говоря уже о всех бесконечных последовательностях элементов из целых чисел.

для более практических подходов подумайте о кодировании последовательности целых чисел как последовательности байтов, а не как числа. Конечную последовательность байтов можно легко считать двоичным значением, следовательно, это число, вы просто не действительно используйте его как таковой. Общим представлением вашей последовательности примеров является последовательность байтов:[1,6,7,8,9,45,67], используется, например, в JSON. Это 136-битное число. Математическая функция обратного отображения включает в себя арифметические степени по модулю 256, вычитание числа 48, умножение на 10 и т. д.: -)


Допустим, ваша последовательность называется s и я определю len(n) быть числом цифр в n.

тогда первая цифра вашего результата -len(s[0]), и следующее len(s[0]) цифры-это число s[0]; затем вы добавляете len(s[1]) и s[1] и так далее.

это работает для чисел не более 9 цифр.


вы не можете, если диапазон чисел бесконечно.

набор мощности натуральных чисел в uncountable. Это означает, что вы не можете обеспечить связь между наборами цифр и чисел.

Что вы можете сделать, если ваши числа ограничены, скажем, 32 битами, это объединить числа в длинное двоичное число и сохранить их как последовательность байтов, возможно, как Бигнум.


вот базовая реализация PHP Godel нумерация описано Стивом Джессопом выше:

<?php

$sec = array(5,9,8,4);

$n = count($sec);
$max = max($sec);

$enc = encode($sec);
$dec = decode($enc, $n, $max);

echo "Input sequence:  " . implode(",", $sec) . "\n";
echo "Output sequence: " . implode(",", $dec) . "\n";
echo "Godel number:    " . $enc;
echo (PHP_INT_MAX/$enc < 20 ? " - too big to decode.\n" : "\n");

function encode($sec) {
    $primes = array(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53);
    $enc = 1;
    $i = 0;
    foreach ($sec as $v) {
        $enc = $enc * pow($primes[$i], $v+1);
        $i++;
    }
    return $enc;
}

function decode($enc, $n, $max) {
    $primes = array(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53);
    $sec = array();
    for ($i = 0; $i < $n; $i++) {
        for ($v = 2; $v <= $max+1; $v++) {
            if ($enc/pow($primes[$i], $v) != round($enc/pow($primes[$i], $v))) {
                break;
            }
        }
        $sec[] = $v-2;
    }
    return $sec;
}

?>

этот скрипт работает только для небольших чисел в малых последовательностей. Он не может обрабатывать очень большие числа, я думаю, так же, как и любая другая реализация. Еще проще и эффективнее хранить цифры, объединяющие их так, как они есть: [01,05,15,17] - > 1051517.


обновлено, чтобы проверить случай 0,1.

отделить разные номера по 001.

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

для декодирования, разделить на 001. Заменить все 01 на 0.


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

1) используйте код для представления количества элементов в последовательности. 2) затем используйте код для представления каждого элемент.


еще один ответ, который пришел мне в голову. Кодируйте каждое число в сбалансированной троичной, С двумя битами на Трит (напр., 0=00; +1=01; -1=10). Оставшаяся битовая пара (например, 11) - это конец маркера элемента, повторяемый для конца последовательности. Минусы: меньше места эффективным, чем код префикса, когда большие значения; Плюсы: 1) более эффективное пространство, в основном малых значений; 2) кодирования/декодирования проще; 3) отражает отрицательные значения.