基本2本机int的指数

时间:2017-09-28 21:54:53

标签: native dafny

某些算法(分配二叉树......)需要计算基数2指数。如何为这种原生类型计算它?

function pow2(n: u32): (r: u32)
  requires n < 10
{
  if n == 0 then 1 else 2 * pow2(n - 1)
}

这是一个明显的尝试:

u32

它失败了,因为Dafny怀疑产品保持低于{{1}}的最大值。如何证明它的价值低于2 ** 10?

2 个答案:

答案 0 :(得分:1)

在这种情况下,首先定义函数的无界版本更方便,然后证明一个引理,表明当n < 10(或n < 32,偶数)它在边界内时。

function pow2(n: nat): int
{
  if n == 0 then 1 else 2 * pow2(n - 1)
}

lemma pow2Bounds(n: nat)
    requires n < 32
    ensures 0 <= pow2(n) < 0x100000000
{ /* omitted here; two proofs given below */ }

function pow2u32(n: u32): u32
    requires n < 32
{
    pow2Bounds(n as nat);
    pow2(n as nat) as u32
}

直观地说,我们可能会期望引理自动完成,因为只有少数案例需要考虑:n = 0n = 1,... n = 31。但是Dafny不会自动执行此类案例分析。相反,我们有几个选择。

第一次证明

首先,我们可以证明一个更普遍的属性,通过归纳推理的魔力,可以更容易来证明,尽管它比我们需要的更强。

lemma pow2Monotone(a: nat, b: nat)
    requires a < b
    ensures pow2(a) < pow2(b)
{}  // Dafny is able to prove this automatically by induction.

然后是引理。

lemma pow2Bounds(n: nat)
    requires n < 32
    ensures 0 <= pow2(n) < 0x100000000
{
    pow2Monotone(n, 32);
}

第二次证明

证明这一点的另一种方法是告诉Dafny它应该使用pow2属性将:fuel展开最多32次。这32次展开与要求Dafny对每个可能值进行案例分析基本相同。然后Dafny可以在没有额外帮助的情况下完成证明。

lemma {:fuel pow2,31,32} pow2Bounds(n: nat)
    requires n < 32
    ensures 0 <= pow2(n) < 0x100000000
{}

:fuel属性(轻微)记录在第24节的Dafny Reference Manual中。

答案 1 :(得分:1)

有点作弊,但由于域名非常狭窄,这种方法很有效。

const pow2: seq<u32> :=
  [0x1, 0x2, 0x4, 0x8, 0x10, 0x20];

lemma pow2_exponential(n: u32)
  ensures n == 0    ==> pow2[n] == 1
  ensures 0 < n < 6 ==> pow2[n] == 2 * pow2[n - 1]  
{}