Floating point 如何用Frama-C中的实数公理证明代码

Floating point 如何用Frama-C中的实数公理证明代码,floating-point,trigonometry,frama-c,Floating Point,Trigonometry,Frama C,我已将ACSL示例手册中“内积”代码中的int类型更改为float(带有int类型的代码对我有效),现在我无法证明循环不变量Inner。我为inf和NaN添加了一些检查,但没有成功 #include "limits.h" /*@ predicate Unchanged{K,L}(float* a, integer first, integer last) = \forall integer i; first <= i < last ==> \at(a[i

我已将ACSL示例手册中“内积”代码中的
int
类型更改为
float
(带有
int
类型的代码对我有效),现在我无法证明循环不变量
Inner
。我为inf和NaN添加了一些检查,但没有成功

#include "limits.h"

/*@
  predicate  Unchanged{K,L}(float* a, integer first, integer last) =
    \forall integer i; first <= i < last ==>
    \at(a[i],K) == \at(a[i],L);

  predicate  Unchanged{K,L}(float* a, integer n) =
    Unchanged{K,L}(a, 0, n);

  lemma UnchangedStep{K,L}:
    \forall float *a, integer n;
    0 <= n ==>
    Unchanged{K,L}(a, n) ==>
    \at(a[n],K) == \at(a[n],L) ==>
    Unchanged{K,L}(a, n+1);

  lemma UnchangedSection{K,L}:
    \forall float *a, integer m, n;
    0 <= m <= n ==>
    Unchanged{K,L}(a, n) ==>
    Unchanged{K,L}(a, m);
*/


/*@ axiomatic InnerProductAxiomatic
  {
  logic real InnerProduct{L}(float* a, float* b, integer n, float init)
  reads a[0..n-1], b[0..n-1];

  axiom InnerProductEmpty:
    \forall float *a, *b, init, integer n;
    n <= 0 ==> InnerProduct(a, b, n, init) == init;

  axiom InnerProductNext:
    \forall float *a, *b, init, integer n;
    n >= 0 ==>
    InnerProduct(a, b, n + 1, init) ==
    InnerProduct(a, b, n, init) + a[n] * b[n];

  axiom InnerProductRead{L1,L2}:
    \forall float *a, *b, init, integer n;
    Unchanged{L1,L2}(a, n) && Unchanged{L1,L2}(b, n) ==>
    InnerProduct{L1}(a, b, n, init) ==
    InnerProduct{L2}(a, b, n, init);
  }*/

/*@
  predicate ProductBounds(float* a, float* b, integer n) =
    \forall integer i; 0 <= i < n ==>
    (INT_MIN <= a[i] * b[i] <= INT_MAX) ;

  predicate InnerProductBounds(float* a, float* b, integer n, float init) =
    \forall integer i; 0 <= i <= n ==>
    INT_MIN <= InnerProduct(a, b, i, init) <= INT_MAX;
*/

/*@
  requires valid_a: \valid_read(a + (0..n-1));
  requires valid_b: \valid_read(b + (0..n-1));
  requires \is_finite(init);
  requires !\is_NaN(init);
  requires bounds: ProductBounds(a, b, n);
  requires bounds: InnerProductBounds(a, b, n, init);
  requires (n < 100) && (n>=0);
  requires \forall integer i; 0 <= i < n ==>  \is_finite(a[i]);
  requires \forall integer i; 0 <= i < n ==>  \is_finite(b[i]);
  requires \forall integer i; 0 <= i < n ==>  !\is_NaN(b[i]);
  requires \forall integer i; 0 <= i < n ==>  !\is_NaN(a[i]);

  assigns \nothing;
  ensures result: \result == InnerProduct(a, b, n, init);
  ensures unchanged: Unchanged{Here,Pre}(a, n);
  ensures unchanged: Unchanged{Here,Pre}(b, n);
*/

float inner_product(const float* a, const float* b, int n, float init)
{
  int i = 0;
  /*@
    loop invariant index: 0 <= i <= n;
    loop invariant inner: init == InnerProduct(a, b, i, \at(init,Pre));
    loop assigns i, init;
    loop variant n-i;
  */
  while (i < n) {
    init = init + a[i] * b[i];
    i++;
  }
  return init;
}
#包括“limits.h”
/*@
谓词未更改{K,L}(浮点*a,先整数,后整数)=
\对于所有整数i;第一
\at(a[i],K)=\at(a[i],L);
谓词未更改{K,L}(浮点*a,整数n)=
不变的{K,L}(a,0,n);
引理不变阶{K,L}:
\对于所有浮点*a,整数n;
0
不变的{K,L}(a,n)=>
\at(a[n],K)==\at(a[n],L)=>
不变的{K,L}(a,n+1);
引理不变截面{K,L}:
\对于所有浮点*a,整数m,n;
0
不变的{K,L}(a,m);
*/
/*@公理的
{
逻辑实数内积{L}(浮点*a,浮点*b,整数n,浮点init)
读取a[0..n-1],b[0..n-1];
axiom InnerProductEmpty:
\对于所有浮点*a,*b,init,整数n;
n内积(a,b,n,init)=init;
axiom InnerProductNext:
\对于所有浮点*a,*b,init,整数n;
n>=0==>
内积(a,b,n+1,初始)==
内积(a,b,n,init)+a[n]*b[n];
axiom InnerProductRead{L1,L2}:
\对于所有浮点*a,*b,init,整数n;
不变的{L1,L2}(a,n)&&不变的{L1,L2}(b,n)=>
内积{L1}(a,b,n,init)==
内积{L2}(a,b,n,init);
}*/
/*@
谓词ProductBounds(浮点*a,浮点*b,整数n)=
\对于所有整数i;0

(INT_MIN我将回答你问题的第一部分。问题在于公理
InnerProductNext
,更准确地说,这里
InnerProduct(a,b,n+1,init)==InnerProduct(a,b,n,init)+a[n]*b[n]
.ACSL规范使用实数算术,而您的函数使用32位浮点计算。由于C函数中出现舍入,无法实现证明。解决方法非常简单:在引理中适当舍入所有操作

  axiom InnerProductNext:
    \forall float *a, *b, init, integer n;
    n >= 0 ==>
    InnerProduct(a, b, n + 1, init) ==
    (float)(InnerProduct(a, b, n, init) + (float)(a[n] * b[n]));

这足以证明成功。

我将回答你问题的第一部分。问题在于公理
InnerProductNext
,更准确地说,这里
InnerProduct(a,b,n+1,init)==InnerProduct(a,b,n,init)+a[n]*b[n]
.ACSL规范使用实数算术,而您的函数使用32位浮点计算。由于C函数中出现舍入,无法实现证明。解决方法非常简单:在引理中适当舍入所有操作

  axiom InnerProductNext:
    \forall float *a, *b, init, integer n;
    n >= 0 ==>
    InnerProduct(a, b, n + 1, init) ==
    (float)(InnerProduct(a, b, n, init) + (float)(a[n] * b[n]));

这就足以证明成功。

关于问题的第二部分,似乎对ACSL公理学的语义有一些深刻的误解。特别是:

  • 你的
    SinnnEmpty
    公理基本上是说,对于任何
    x
    sum
    ,我们都有
    Sinnn(x,sum,0,0,0)==sum
    (基本上,我刚刚用
    0
    实例化了
    current
    I
    I_max
    ,这使得含义的左边部分为真)1.你不太可能是想在那里这么说的
  • SinnnMemCmp
    是一种重言式。事实上,在全局注释中,
    \at()
    构造和逻辑标签旨在说明C变量和内存位置。这里,您只有受通用量化约束的纯逻辑变量:它们是不可变的,不与C内存状态绑定,也就是说,它们的值不依赖于逻辑标签

最后,一旦您从ACSL的角度整理了关于
Sinnn
应该做什么的定义(即玩数学实数游戏,愉快地忽略舍入问题),您最终会遇到一个问题,即在使用有限精度浮点数进行计算时,尝试检查适用于此数学级别的结果是否仍然正确。这通常是一项困难的任务,并且并非所有自动校准仪都能很好地支持浮点数计算(有关更多信息,请参见示例).

关于问题的第二部分,似乎对ACSL公理学的语义有一些深刻的误解。特别是:

  • 你的
    SinnnEmpty
    公理基本上是说,对于任何
    x
    sum
    ,我们都有
    Sinnn(x,sum,0,0,0)==sum
    (基本上,我刚刚用
    0
    实例化了
    current
    I
    I_max
    ,这使得含义的左边部分为真)1.你不太可能是想在那里这么说的
  • SinnnMemCmp
    是一种重言式。事实上,在全局注释中,
    \at()
    构造和逻辑标签旨在说明C变量和内存位置。这里,您只有受通用量化约束的纯逻辑变量:它们是不可变的,不与C内存状态绑定,也就是说,它们的值不依赖于逻辑标签
最后,一旦您从ACSL的角度整理了关于
Sinnn
应该做什么的定义(即玩数学实数游戏,愉快地忽略舍入问题),您最终会遇到一个问题,即在使用有限精度浮点数进行计算时,尝试检查适用于此数学级别的结果是否仍然正确。这通常是一项困难的任务,并且并非所有自动校准仪都能很好地支持浮点数计算(有关更多信息,请参见示例)