Language agnostic 对「;循环不变量;,这些在行业中经常使用吗?

Language agnostic 对「;循环不变量;,这些在行业中经常使用吗?,language-agnostic,Language Agnostic,我回想起我大学一年级(五年前)的时候,我参加了一次计算机科学入门级的考试。有一个关于循环不变量的问题,我想知道在这种情况下循环不变量是否真的是必要的,或者这个问题只是一个糟糕的例子。。。问题是为阶乘函数编写一个迭代定义,然后证明该函数是正确的 我为阶乘函数提供的代码如下: public static int factorial(int x) { if ( x < 0 ){ throw new IllegalArgumentException("Parameter

我回想起我大学一年级(五年前)的时候,我参加了一次计算机科学入门级的考试。有一个关于循环不变量的问题,我想知道在这种情况下循环不变量是否真的是必要的,或者这个问题只是一个糟糕的例子。。。问题是为阶乘函数编写一个迭代定义,然后证明该函数是正确的

我为阶乘函数提供的代码如下:

public static int factorial(int x)
{
     if ( x < 0 ){
         throw new IllegalArgumentException("Parameter must be >= 0");
     }else if ( x == 0 ){
         return 1;
     }else{
         int result = 1;
         for ( int i = 1; i <= x; i++ ){
             result*=i;
         }
         return result;
     }
}
公共静态整数阶乘(intx)
{
if(x<0){
抛出新的IllegalArgumentException(“参数必须大于等于0”);
}else如果(x==0){
返回1;
}否则{
int结果=1;
例如(int i=1;i近年来,以各种名称命名的“测试驱动开发”一直是大多数人最费心对代码进行推理的方式。这相当于非常仔细和可重复的实验,而不是逻辑推理。科学与数学

在像Eiffel这样的语言中使用了一些前置条件、后置条件和循环/类不变量,而.NET4.0中即将提供的“契约”支持可能有助于进一步普及这些思想

就我个人而言,最近我很少使用断言;当我在一个结构中循环时,我通常不再将其作为循环来编写。我将其作为一个查询来编写,例如C#中的Linq或其他类似语言(如JS)中的类似内容。因此,不太需要进行错误的状态操纵(通常没有任何错误)。任何关于结果的断言都是多余的,因为它只会重申查询中的条件:在查询方法中,您描述您想要的结果


这并不是说我从不使用断言;但我倾向于将它们与单元测试结合使用,并且只用于执行集合的某些复杂“就地”变异的非常复杂的算法;在这种情况下,没有“内置”的方式来请求我想要的结果;我必须强制编写算法(可能是因为复制整个数据结构的成本太高了),所以我用断言来覆盖它,以帮助我的单元测试标记出内部问题。

当你在解决困难的问题和编写代码时,你应该(应该)每天都要经历证明你编写的每一个例程的正确性的过程。测试驱动开发是这个想法的形式化,但它的核心是:你需要至少向自己,最好是向其他人(代码审查!)证明你编写的代码将以适当的方式处理所有可能的输入和路径

我们是否会因为代码不变量而争吵?不。我们是否会在你报到之前给论文打分?有点。如果团队对你的代码或你的“证明”不满意,你就回到你的盒子里去修复它,直到它通过审查。

教授想让我用循环不变量来证明这个循环; 你的教授想确保你理解循环不变量,而不仅仅是证明一个非常简单的函数

在这种情况下,真的需要循环不变量作为正确性的证明吗? 从技术上讲,不需要。根据这个推理,您也不需要编写阶乘函数:只需使用库函数!但这不是练习的重点

在循环不变量(以及适当的初始化和终止条件)成为证明正确性的必要条件之前,循环必须有多复杂? 我认识一些聪明的人,他们可能可以证明几乎没有不变量的任何东西,还有一些人甚至需要在上面这样的小事上使用它们。这就像问“在你需要手推车移动石头之前,石头必须有多重?”

此外,我想知道……这种正式证明在行业中使用的频率有多高? 明确写出来?可能很少,除非你在。但我在写任何循环时都会考虑它们,但最简单的循环除外

这有点像我不画句子的图表,但这并不意味着我从不考虑语法,尤其是当我写一些非常重要的文本时。我可以告诉你我的代词的先行词是什么,即使我从来没有把这个事实写在纸上

在多大程度上是正式的证据 需要正确性吗

当然,这要视情况而定,但我认为程序员知道如何编写不容易出错的代码是很重要的,因为通过构造代码往往是正确的

一个例子是“向前看”的概念,例如在解析中,输入的下一个标记不是“读取”,然后是“查看”,如果不是想要的,则可能是“放回”,而是“查看”,然后可能是“接受”例如,当编写循环遍历数据库记录并提取小计时,透视图中的这种简单更改可以生成更简单、更可靠的代码

另一个例子是,我多年前偶然发现的一种技术。它似乎允许以增量方式重新执行任何算法,以便以增量方式更新其结果。我在内容可以动态更改的用户界面中广泛使用它。很长一段时间以来,我觉得它在所有情况下都有效,但直到最后我才确定在那之后,我知道如果我坚持一些简单的约束,我可以依靠它来工作,不管代码有多依赖它


同时,我们可能对某些算法的正确性有极大的信心,但是发现它很难被证明,因为我们的证明技术是很差的。考虑低级冒泡排序。它显然是有效的,但是试图通过将规则应用到源代码来证明它是正确的。我已经做到了,但这并不容易。我没有尝试过更多的ADVA。新的排序算法。

作为旁白:循环不变表达式被大多数人从循环中删除