Log(n)中的Tetranacci数

时间:2015-11-18 11:46:39

标签: algorithm runtime matrix-multiplication

我偶然发现了一个问题,这需要我计算O(log n)中的第n Tetranacci Number个。

我已经看到了为Fibonacci Numbers

执行此操作的几种解决方案

我希望按照类似的程序(矩阵乘法/快速加倍)来实现这一目标,但我不确定如何做到这一点(以类似的方式采用4乘4矩阵和1乘4并且#39 ;似乎工作)。使用动态编程/通用循环/任何其他基本思想,我无法实现子线性运行时。任何帮助表示赞赏!

3 个答案:

答案 0 :(得分:5)

矩阵乘法当然有效。以下是如何推导矩阵。

我们想要的是找到制作等式的条目

[a b c d] [T(n-1)]   [T(n)  ]
[e f g h] [T(n-2)]   [T(n-1)]
[i j k l] [T(n-3)] = [T(n-2)]
[m n o p] [T(n-4)]   [T(n-3)]

对所有n都是如此。展开。

a T(n-1) + b T(n-2) + c T(n-3) + d T(n-4) = T(n)
e T(n-1) + f T(n-2) + g T(n-3) + h T(n-4) = T(n-1)
i T(n-1) + j T(n-2) + k T(n-3) + l T(n-4) = T(n-2)
m T(n-1) + n T(n-2) + o T(n-3) + p T(n-4) = T(n-3)

这里显而易见的设置是a = b = c = d = 1(使用重复)和e = j = o = 1以及f = g = h = i = k = l = m = n = p = 0(基本代数)。

初始向量是

[T(3)]   [1]
[T(2)]   [0]
[T(1)] = [0]
[T(0)]   [0]

按照定义。

答案 1 :(得分:3)

OEIS开始,这是

的第n次幂的(1,4)条目
QJsonObject myJsonObj;
myJsonObj["MyValue"] = 10;
QJsonDocument doc(myJsonObj);

QFile file("MyFile.json");
file.open(QIODevice::WriteOnly | QIODevice::Text);
file.write(doc.toJson(QJsonDocument::Indented));

要在O(log n)操作中计算该矩阵的n次幂,可以使用exponentiation by squaring。可能会有一个稍微简单的重复,但您应该能够实现一般技术。

答案 2 :(得分:2)

我从其他答案中描述的相应矩阵推导出Tetranacci加倍公式。公式是:

$('.ui.modal')
   .modal('setting', 'transition', 'horizontal flip')
   .modal('show');

通过这些,我们可以实现快速加倍"方法。这是Python中的一个这样的实现,它对任意大小的整数的原生支持非常方便:

T(2n)   = T(n+1)*(2*T(n+2) - T(n+1)) + T(n)*(2*T(n+3) - 2*T(n+2) - 2*T(n+1) - T(n))
T(2n+1) = T(n)^2 + T(n+2)^2 + T(n+1)*(2*T(n+3) - 2*T(n+2) - T(n+1))
T(2n+2) = T(n+1)*(2*T(n) + T(n+1)) + T(n+2)*(2*T(n+3) - T(n+2))
T(2n+3) = T(n+1)^2 + T(n+3)^2 + T(n+2)*(2*T(n) + 2*T(n+1) + T(n+2))

我希望根据def tetranacci_by_doubling(n): if n >= 0: a, b, c, d = 0, 0, 0, 1 # T(0), T(1), T(2), T(3) else: # n < 0 a, b, c, d = 1, 0, 0, 0 # T(-1), T(0), T(1), T(2) # unroll the last iteration to avoid computing unnecessary values. for i in reversed(range(1, abs(n).bit_length())): w = b*(2*c - b) + a*(2*(d - c - b) - a) x = a*a + c*c + b*(2*(d - c) - b) y = b*(2*a + b) + c*(2*d - c) z = b*b + d*d + c*(2*(a + b) + c) a, b, c, d = w, x, y, z if (n >> i) & 1 == 1: a, b, c, d = b, c, d, a + b + c + d if n & 1 == 0: return b*(2*c - b) + a*(2*(d - c - b) - a) # w else: # n & 1 == 1 return a*a + c*c + b*(2*(d - c) - b) # x def tetranacci(n): a, b, c, d = 0, 0, 0, 1 # T(0), T(1), T(2), T(3) # offset by 3 to reduce excess computation for large positive `n` n -= 3 if n >= 0: for _ in range(+n): a, b, c, d = b, c, d, a + b + c + d else: # n < 0 for _ in range(-n): a, b, c, d = d - c - b - a, a, b, c return d # sanity check print(all(tetranacci_by_doubling(n) == tetranacci(n) for n in range(-1000, 1001))) 将倍增公式调整为T(2n-3),T(2n-2),T(2n-1),T(2n),以略微减少大T(n-3),T(n-2),T(n-1),T(n)的过量计算,但会简化转移公式很繁琐。

更新

  • 交换到迭代版本,因为我弄清楚如何使其干净地处理负n并且复制最少。最初,这是递归版本的唯一优势。
  • 采用了一种技术,该技术在几篇关于计算Fibonacci&amp; amp;卢卡斯数 - 在循环之后手动执行最后的倍增步骤,以避免计算额外的不需要的值。这导致大nn加速约40%-50%!此优化也可以应用于递归版本。

由于展开最后一次迭代而加速非常有趣。它表明,近一半的计算工作是在最后一步完成的。这是有道理的,因为当>= 10^6)加倍时,T(n)中的数字位数(以及算术成本)大约加倍,我们知道n。将优化应用于类似的Fibonacci / Lucas倍增算法可以产生约40%的类似加速 - 但是,如果您正在计算Fibonacci /等。以64位2^n ~= 2^0 + 2^1 + ... + 2^(n-1)为模,我怀疑这种优化并不具有价值。