努力找到正确的循环不变式

时间:2018-10-30 05:32:52

标签: java loops assert

我有以下代码:

public static void main(String[] args) {
    int a = 3;
    int b = 7;

    int x = b; // x=b
    int res = a; // res = a
    int y = 1;

    int invariant = 0;

    System.out.println("a|b|x|y|res|invariant");
    while (x > 0) { 
        if (x % 2 == 0) {
            y = 2 * y;
            x = x / 2;  
        } else {
            res = res + y;
            y = 2 * y;
            x = (x - 1) / 2;
        }
        invariant = y + 2;
        String output = String.format("%d|%d|%d|%d|%d|%d", a,b,x,y,res,invariant);
        System.out.println(output);
    }
    // < res = a + b >
}

哪个给出以下输出:

a|b|x|y|res|invariant
3|7|3|2|4|4
3|7|1|4|6|6
3|7|0|8|10|10

但是,如果我更改数字,则不变性不再等于res。因此,我对此问题的循环不变性是不正确的。

我一直在努力寻找正确的循环不变性,如果有人可以给我提示,我将非常高兴。

查看代码和结果后,我的第一印象是循环不变性基于a和b进行更改。假设a和b都是奇数,就像我的例子一样,那么我的Loop不变量是正确的(至少看起来像这样)

假设像下面这样的循环变量是正确的吗?

< res = y - 2 && a % 2 != 0 && b % 2 != 0 >

我确实使用了不同的数字,并且似乎在每次更改它们时,都会有不同的循环不变性,我很难找到任何模式。

如果有人能给我提示或解决方法的一般想法,我将不胜感激。

谢谢

1 个答案:

答案 0 :(得分:1)

此循环计算总和a+bres初始化为a。 然后,在循环的每次迭代中,将b的二进制表示形式的下一位(从最低有效位开始)添加到res,直到循环结束且res保持不变a+b

工作方式:

x初始化为b。在每次迭代中,您将消除最低有效位。如果该位是0,则只需将x除以2。如果是1,则减去1并除以2(实际上,除以{ {1}},因为当x为奇数2(x-1)/2==x/2。仅当遇到int位时,才需要将其添加(乘以1的正确幂)。 2拥有y的正确能力。

在您的a = 3,b = 7的示例中,b的二进制表示为111

  • 在第一次迭代中,res的值为a + 1(二进制)== a + 1 = 4
  • 在第二次迭代中,res的值为a + 11(二进制)== a + 3 = 6
  • 在最后一次迭代中,res的值为a + 111(二进制)== a + 7 == 10

您可以将不变式写为:

2

这利用了这样一个事实,即在第invariant = a + (b & (y - 1)); 次迭代结束时(ii开始,1持有y,因此2^i是一个数字,其二进制表示形式是y - 1 == 2^i - 1 1位(即i11...11位)。当您用i &来编号时,将得到b的{​​{1}}个最低有效位。