Floating point 如何用Frama-C中的实数公理证明代码
我已将ACSL示例手册中“内积”代码中的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
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
应该做什么的定义(即玩数学实数游戏,愉快地忽略舍入问题),您最终会遇到一个问题,即在使用有限精度浮点数进行计算时,尝试检查适用于此数学级别的结果是否仍然正确。这通常是一项困难的任务,并且并非所有自动校准仪都能很好地支持浮点数计算(有关更多信息,请参见示例)