给定一个整数以及它在某个任意进制下的表示,目标是找到这个进制的基数。例如,如果数字是10,表示为000010,则进制应该是10。另一个例子:数字21的表示为0010101,那么进制就是2。再举一个例子:如果数字是6,表示为10100,则进制为sqrt(2)。有没有人知道如何解决这样的问题?
___
\
number = /__ ( digit[i] * base ^ i )
你知道 number
,你知道所有的数字 digit[i]
,你只需要找出 base
。I
,都有 base^I > ∑(i = 0; i < I; ++i)(digit[i] * base^i)
。 - Matthieu M.a_6 a_5 a_4 a_3 a_2 a_1
,找到该基数意味着解决:a_6 b^5 + a_5 b^4 + a_4 b^3 + a_3 b^2 + a_2 b^1 + a_1 = x.
如Abel和Ruffini所示,这通常是不可能完成的。如果数字很短,你可能会更幸运,但如果涉及超过四位数,则公式变得越来越丑陋。
然而,有相当多的良好的近似算法。请参见此处。
仅限整数,这并不难(我们可以列举出来)。
让我们看看 21
及其表示为 10101
。
1 * base^4 <= 21 < (1+1) * base^4
让我们为一些进制生成数字:
base low high
2 16 32
3 81 162
更普遍地,我们将 N
表示为 ∑ ai * basei。考虑 I
是最大的幂次,使得 aI 非零,则有:
a[I] * base^I <= N < (a[I] + 1) * base^I # does not matter if not representable
# Isolate base term
N / (a[I] + 1) < base^I <= N / a[I]
# Ith root
Ithroot( N / (a[I] + 1) ) < base <= Ithroot( N / a[I] )
# Or as a range
base in ] Ithroot(N / (a[I] + 1)), Ithroot( N / a[I] ) ]
N / (a[I] + 1)
的 Ithroot
并从这里开始迭代可能更快,而不是计算第二个(这应该足够接近)...... 但是我需要对这种感觉进行数学审查。N
为您的整数,R
为其在神秘基数下的表示。
- 找到 R
中最大的数字并将其称为 r
。r+1
。base == (r+1, r+2, ...)
,让 I
表示在基数 base
下解释的 R
- 如果 I
等于 N
,那么 base
就是您要找的神秘基数。
- 如果 I
小于 N
,尝试下一个基数。
- 如果 I
大于 N
,那么您的基数就在 base-1
和 base
之间。I
明显小于 N
时将 base
增加超过一来加快速度。x = a[n]*base^n + a[n-1]*base^(n-1) + ... + a[2]*base^2 + a[1]*base + a[0]
a[n]*base^n
。如果这比x
还要大,则您已经知道您的基数太大了。否则,逐个添加一个项(从最高有效位到最低有效位)。这样,您就不会在知道基数错误后浪费时间计算术语。(x - a[0]) = a[n]*base^n + a[n-1]*base^(n-1) + ... + a[2]*base^2 + a[1]*base
或者
(x - a[0]) = (a[n]*base^(n-1) + a[n-1]*base^(n-2) + ... + a[2]*base + a[1])*base
x
和a[0]
的值(即“个位数”,无论进制如何,你都可以解释它)。这使你得到了额外的条件,即(x - a[0])
必须能够被base
整除(因为所有的a[]
值都是整数)。如果你计算(x - a[0]) % base
并得到一个非零结果,则base
不能是正确的进制。base
是一个整数(在这种情况下问题是微不足道的)...我也犯了同样的错误,但是 @evil.coder
给出了一个例子,其中 base
是 sqrt(2)
。 - Matthieu M.我不确定这个问题能否有效地解决。我会尝试选择一个随机的基数,看看给定该基数时结果是小于、大于还是等于该数字。如果结果比该数字小,那就选择一个更大的基数,如果结果比该数字大,则选择一个更小的基数,否则你就得到了正确的基数。
1 * base ^ 4 + 2 * base ^ 2 + 3 = 42
现在你可以解方程来获取base
的值。
我认为你需要尝试并检查不同的进制。为了高效,你的起始进制可以是max(digit) + 1,因为你知道它不会小于这个值。如果这个值太小,就加倍直到超过,然后使用二分搜索来缩小范围。这样,你的算法在正常情况下应该以O(log n)的速度运行。
其他一些帖子建议通过找到表示数字的多项式的根来找到解决方案。当然,这通常是有效的,尽管它们往往会产生负数和复数基数以及正整数。
另一种方法是将其作为整数规划问题进行转换,并使用分支定界法进行求解。
但我怀疑猜测和测试的建议比任何聪明的提议都要快。
I
,base^I > ∑(i in [0, I[)(digit[i] * base^i)
。这个属性使得问题变得更容易,我在答案中进行了说明,因为我没有足够的空间来放置方程,但它确实大大简化了手头的问题。 - Matthieu M.