Как последовательность чисел может быть преобразована в одно число?
Я хочу преобразовать последовательность чисел в одно число, которое сохранит отдельные значения, а также их положение. например, предоставляется следующая последовательность-
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) отражает отрицательные значения.