如何将一系列数字转换为单个数字?

时间:2012-09-01 16:17:14

标签: algorithm math numbers

我想将一系列数字转换为单个数字,这将保留单个值以及它们的位置。例如提供以下顺序 -

  

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

这里,例如,如果我应用简单的加法,即1 + 6 + 7 + 8 + 9 + 45 + 67,那么将生成一个数字。但是从那个没有。我们不能用它们的顺序提取个别数字[即。 1,6,7,8,9,...]。

有没有办法在没有任何模糊推论的情况下实现这个功能[即只从一个数字中提取一组唯一的数字。]?是否有任何数学函数可以帮助从该数字中找回各个元素?

8 个答案:

答案 0 :(得分:9)

您可以将其转换为基数为N的数字,其中N大于输入序列中显示的最大值。

<强>更新

基于各种评论,我想提供一种可能更容易实施的替代解决方案。您可以将序列视为UTF-8编码的字符串,并使用Huffman coding和自定义字典来实现紧凑的表示。

自定义词典允许您存储极少数位的非常常见的字符(例如,序列分隔符','和单个字符'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

也很容易

Compressing small piece of data

答案 1 :(得分:4)

在数学上可以为有限序列做到这一点,但不是很实用,因为所需的数字非常快很快:有67 7 (约2 42 )从1 ... 67开始的不同长度-7个整数序列,更不用说更长的序列和更大的整数。

对于这样一个函数的一个简单例子,将序列[1,6,7,8,9,45,67]映射到值2 1 * 3 6 * 5 7 * 7 8 * 11 9 * 13 45 * 17 67 。基数是素数,幂是序列中的元素。

反向映射是通过除法计算的 - 你可以将值除以2的次数是序列中的第一个元素,等等。值的最大素数因子告诉你序列有多长是

如果你想在序列中允许0以及正数,那么当你将素数提升到幂时,为所有元素加1。或者使用2的幂来给出序列的长度,然后开始编码以3开头的元素。

Goedel在他的不完全性定理的证明中使用了这样的编码。

正如Kendall Frey所说,无法定义将每个无限整数序列映射到不同整数的函数。这是康托尔证明自然数的幂集不可数的结果:你甚至无法将{true, false}中所有无限元素序列映射到整数,更不用说整数中所有无限元素序列了。

对于更实用的方法,请考虑将整数序列编码为字节序列,而不是数字。有限的字节序列可以很容易地被认为是二进制值,因此它是一个数字,你实际上并没有真正使用它。示例序列的常见表示是字节序列:[1,6,7,8,9,45,67],例如在JSON中使用。这是一个136位的数字。反转这种映射的数学函数包括算术模数为256,减去数字48,乘以10,等等: - )

答案 2 :(得分:2)

假设您的序列被称为s 我将len(n)定义为n中的位数。

然后结果的第一个数字是len(s[0]), 以下len(s[0])数字是数字s[0]; 然后添加len(s[1])s[1],依此类推。

适用于最多9位的数字。

答案 3 :(得分:1)

如果您的数字范围无限,则不能。

自然数的幂集不可数。这意味着您无法在数字和数字组之间提供映射。

如果您的数字被限制为32位,您可以做的是将数字连接成一个长二进制数,并将它们存储为一个字节序列,可能是一个BigNum。

答案 4 :(得分:1)

这是Steve Jessop在上面描述的Godel numbering的基本PHP实现:

<?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] - &gt; 1051517。

答案 5 :(得分:0)

更新以检查0,1案例。

将不同的数字分开001。

为避免与数字中的00混淆,每次数字出现0时,请将其替换为01.

解码,拆分为001.将所有01替换为0。

答案 6 :(得分:0)

这使用universal code,例如Elias omega coding(或任何前缀代码 - 但通用代码是具有某些所需属性的前缀代码)。 前缀代码将比特序列(即数字)编码为前缀,基本上提供必要的信息以确定有多少比特构成数字的其余部分。

1)使用代码表示序列中的元素数量。 2)然后使用代码表示每个元素。

答案 7 :(得分:0)

我发现了另一个答案。将每个数字编码为balanced ternary,每个trit有两位(例如,0 = 00; + 1 = 01; -1 = 10)。剩余的比特对(例如,11)是元素标记的结束,对序列的结束重复。 Con:当预期值较大时,比前缀代码的空间效率更低;优点:1)空间效率更高,大多数值很小; 2)编码/解码更简单; 3)直接表示负值。