如何优雅地找到一个简单的mod函数的固定点?

时间:2016-05-04 05:59:11

标签: c++ algorithm math fixed-point

这是一个函数,用C表示:

uint32_t f(uint32_t x) {
    return (x * 0x156) ^ 0xfca802c7;
}

然后我遇到了一个挑战:如何找到所有固定点?

我知道我们可以测试每个uint32_t值来解决这个问题,但我仍然想知道是否还有其他方式更优雅 - 特别是当uint32_t成为uint64_t(0x156, 0xfca802c7)是一对任意值。

3 个答案:

答案 0 :(得分:15)

Python代码:

def f(x, n):
    return ((x*0x156)^0xfca802c7) % n


solns = [1]  # The one solution modulo 2, see text for explanation
n = 1
while n < 2**32:
    prev_n = n
    n = n * 2
    lifted_solns = []
    for soln in solns:
        if f(soln, n) == soln:
            lifted_solns.append(soln)
        if f(soln + prev_n, n) == soln + prev_n:
            lifted_solns.append(soln + prev_n)
    solns = lifted_solns

for soln in solns:
    print soln, "evaluates to ", f(soln, 2**32)

输出:150129329评估为150129329

算法背后的理念:我们正在尝试查找x XOR 0xfca802c7 = x*0x156 modulo n,在我们的案例中n=2^32。我这样写是因为右侧是一个简单的模乘,与左侧表现良好。

我们将要使用的主要属性是x XOR 0xfca802c7 = x*0x156 modulo 2^(i+1)的解决方案缩减为x XOR 0xfca802c7 = x*0x156 modulo 2^i的解决方案。另一种说法是,x XOR 0xfca802c7 = x*0x156 modulo 2^i的解决方案转换为一个或两个模2^(i+1)的解:这些可能性是x和/或x+2^i(如果我们想要更确切地说,当我们说“解决方案”时,我们只关注0,...,模数大小-1之间的整数。)

我们可以轻松地为i=1解决此问题:x XOR 0xfca802c7 = x*0x156 modulo 2^1x XOR 1 = x*0 mod 2相同,这意味着x=1是唯一的解决方案。从那里我们知道只有1和3是模2^2 = 4的可能解。所以我们只有两个尝试。事实证明,只有一个有效。这是我们目前的解决模4.我们可以将解决方案提升到模8的可能性。依此类推。最终我们得到了所有这些解决方案。

备注1:此代码找到所有解决方案。在这种情况下,只有一个,但对于更一般的参数,可能有多个。

备注2:运行时间为O(最大值[解决方案数量,模数大小(以位为单位)],假设我没有出错。所以除非有很多很多固定点,否则它很快。在这种情况下,似乎只有一个。

答案 1 :(得分:5)

让我们使用Z3 solver

(declare-const x (_ BitVec 32))
(assert (= x (bvxor (bvmul x #x00000156) #xfca802c7)))
(check-sat)
(get-model)

结果为'#x08f2cab1' = 150129329.

答案 2 :(得分:0)

由于位置n的输入位仅影响位置≥ n的输出位,因此您知道可以通过选择第一位,然后选择第二位等来找到解决方案。

以下是如何使用C ++解决64位整数的问题(当然它也适用于32位整数):

#include <cstdint>
#include <cstdio>

uint64_t f(uint64_t x) {
    return (x * 0x7ef93a76ULL) ^ 0x3550e08f8a9c89c7ULL;
}

static void search(uint64_t x, uint64_t bit)
{
    if (bit == 0)
    {
        printf("Fixed point: 0x%llx\n", (long long unsigned)x);
        return;
    }

    if (f(x + bit) & bit) search(x + bit, bit << 1);
    if ((f(x) & bit) == 0) search(x, bit << 1);
}

int main()
{
    search(0x0, 1);
}

使用此输出:

Fixed point: 0xb9642f1d99863811