GNATprove : "overflow check might fail" in exponentiation function - overflow

I can't solve this problem with SPARK 2018, I think I need some invariant to solve the problem of overflow, but I have already tried everything and can not find it. If someone could shed some light on my problem.
I'll try Exponentiation by simple mode and by binary mode by successive squaring.
Thank you very much in advance.
THIS IS THE ERRORS:
practica.adb:20:17: medium: overflow check might fail (e.g. when A = 0 and r = 1)
practica.adb:40:33: medium: loop invariant might fail after first iteration, cannot prove r * (x ** y) = (M ** N (e.g. when M = 0 and N = 0 and r = 0 and x = 0 and y = 0)
practica.adb:44:20: medium: overflow check might fail (e.g. when x = 0)
practica.adb:47:20: medium: overflow check might fail (e.g. when r = 0 and x = 0)
practica.ads:8:19: medium: postcondition might fail, cannot prove power_simple'Result = (A ** B (e.g. when A = 0 and B = 2 and power_simple'Result = 0)
practica.ads:16:22: medium: postcondition might fail, cannot prove power_binary'Result = (M ** N (e.g. when M = 0 and N = 2 and power_binary'Result = 0)
This is my code .ads
package Practica with SPARK_Mode => On is
-- Funcion que calcula la potenciacion de A elevado a B
function power_simple (A : Natural; B : Natural) return Integer
with Depends => (power_simple'Result => (A,B)),
Pre => B >= 0,
Post => power_simple'Result = (A ** B)
and (if B = 0 then power_simple'Result = 1);
-- Funcion que calcula mediante exponenciacion binaria, potencias de un numero dado
function power_binary (M : Integer; N : Integer) return Integer
with Depends => (power_binary'Result => (M,N)),
Pre => (M >= 0) and (N >= 0),
Post => power_binary'Result = (M ** N)
and (if N = 0 then power_binary'Result = 1);
end Practica;
and this is my code .adb
-- Funcion que calcula la potenciacion de A elevado a B
function power_simple (A : Natural; B : Natural) return Integer is
x : Integer := 0;
r : Integer := 1;
begin
while x /= B loop
pragma Loop_Invariant (0 <= x);
pragma Loop_Invariant (x <= B);
pragma Loop_Invariant (r = (A ** x));
pragma Loop_Invariant (r >= 0);
pragma Loop_Invariant ((if x = 0 then r /= 0));
pragma Loop_Variant (Decreases => B - x);
r := r * A;
x := x + 1;
end loop;
if (B = 0) then r := 1; end if;
if (B = 1) then r := A; end if;
return r;
end power_simple;
--Funcion que calcula mediante exponenciacion binaria, potencias de un numero
function power_binary(M : Integer; N : Integer) return Integer is
x : Integer := M;
y : Integer := N;
r : Integer := 1;
begin
while y /= 0 loop
pragma Loop_Invariant ((x >= 0) and (y >= 0));
pragma Loop_Invariant (r * (x ** y) = (M ** N));
pragma Loop_Variant (Decreases => y);
if (y mod 2) = 0 then
x := x * x;
y := y / 2;
else
r := r * x;
y := y - 1;
end if;
end loop;
if (N = 0) then r := 1; end if;
if (N = 1) then r := M; end if;
return r;
end power_binary;

Related

Reverse the isometric projection algorithm

I've got this code:
const a = 2; // always > 0 and known in advance
const b = 3; // always > 0 and known in advance
const c = 4; // always > 0 and known in advance
for (let x = 0; x <= a; x++) {
for (let y = 0; y <= b; y++) {
for (let z = 0; z <= c; z++) {
for (let p = 0; p <= 1; p++) {
for (let q = 0; q <= 2; q++) {
let u = b + x - y + p;
let v = a + b + 2 * c - x - y - 2 * z + q;
let w = c + x + y - z;
}
}
}
}
}
The code generates (a+1)*(b+1)*(c+1)*2*3 triplets of (u,v,w), each of them is unique. And because of that fact, I think it should be possible to write reversed version of this algorithm that will calculate x,y,z,p,q based on u,v,w. I understand that there are only 3 equations and 5 variables to get, but known boundaries for x,y,z,p,q and the fact that all variables are integers should probably help.
for (let u = ?; u <= ?; u++) {
for (let v = ?; v <= ?; v++) {
for (let w = ?; w <= ?; w++) {
x = ?;
y = ?;
z = ?;
p = ?;
q = ?;
}
}
}
I even managed to produce the first line: for (let u = 0; u <= a + b + 1; u++) by taking the equation for u and finding min and max but I'm struggling with moving forward. I understand that min and max values for v are depending on u, but can't figure out the formulas.
Examples are in JS, but I will be thankful for any help in any programming language or even plain math formulas.
If anyone is interested in what this code is actually about - it projects voxel 3d model to triangles on a plain. u,v are resulting 2d coordinates and w is distance from the camera. Reversed algorithm will be actually a kind of raytracing.
UPDATE: Using line equations from 2 points I managed to create minmax conditions for v and code now looks like this:
for (let u = 0; u <= a + b + 1; u++) {
let minv = u <= a ? a - u : -a + u - 1;
let maxv = u <= b ? a + 2 * c + u + 2 : a + 2 * b + 2 * c - u + 3;
for (let v = minv; v <= maxv; v++) {
...
}
}
I think I know what to do with x, y, z, p, q on the last step so the problem left is minw and maxw. As far as I understand those values should depend both on u and v and I must use plane equations?
If the triplets are really unique (didn't check that) and if p and q always go up to 1 and 2 (respectively), then you can "group" triplets together and go up the loop chain.
We'll first find the 3 triplets that where made in the same "q loop" : the triplets make with the same x,y,z,p. As only q change, the only difference will be v, and it will be 3 consecutive numbers.
For that, let's group triplets such that, in a group, all triplets have the same u and same w. Then we sort triplets in groups by their v parameters, and we group them 3 by 3. Inside each group it's easy to assign the correct q variable to each triplet.
Then reduce the groups of 3 into the first triplet (the one with q == 0). We start over to assign the p variable : Group all triplets such that they have same v and w inside a group. Then sort them by the u value, and group them 2 by 2. This let's us find their p value. Remember that each triplet in the group of 3 (before reducing) has that same p value.
Then, for each triplet, we have found p and q. We solve the 3 equation for x,y,z :
z = -1 * ((v + w) - a - b - 3c -q)/3
y = (w - u + z + b - c - p)/2
x = u + y - b - p
After spending some time with articles on geometry and with the huge help from Wolfram Alpha, I managed to write needed equations myself. And yes, I had to use plane equations.
const a = 2; // always > 0 and known in advance
const b = 3; // always > 0 and known in advance
const c = 4; // always > 0 and known in advance
const minu = 0;
const maxu = a + b + 1;
let minv, maxv, minw, maxw;
let x, y, z, p, q;
for (let u = minu; u <= maxu; u++) {
if (u <= a) {
minv = a - u;
} else {
minv = -a + u - 1;
}
if (u <= b) {
maxv = a + 2 * c + u + 2;
} else {
maxv = a + 2 * b + 2 * c - u + 3;
}
for (let v = minv; v <= maxv; v++) {
if (u <= b && v >= a + u + 1) {
minw = (-a + 2 * b - 3 * u + v - 2) / 2;
} else if (u > b && v >= a + 2 * b - u + 2) {
minw = (-a - 4 * b + 3 * u + v - 5) / 2;
} else {
minw = a + b - v;
}
if (u <= a && v <= a + 2 * c - u + 1) {
maxw = (-a + 2 * b + 3 * u + v - 1) / 2;
} else if (u > a && v <= -a + 2 * c + u) {
maxw = (5 * a + 2 * b - 3 * u + v + 2) / 2;
} else {
maxw = a + b + 3 * c - v + 2;
}
minw = Math.round(minw);
maxw = Math.round(maxw);
for (let w = minw; w <= maxw; w++) {
z = (a + b + 3 * c - v - w + 2) / 3;
q = Math.round(2 - (z % 1) * 3);
z = Math.floor(z);
y = (a + 4 * b + q - 3 * u - v + 2 * w + 3) / 6;
p = 1 - (y % 1) * 2;
y = Math.floor(y);
x = (a - 2 * b - 3 * p + q + 3 * u - v + 2 * w) / 6;
x = Math.round(x);
}
}
}
This code passes my tests, but if someone can create better solution, I would be very interested.

The '+' operation is not applicable to the types function(x: real): real and real. Check the operation of the program for a = 0.1; b = 1.0; h = 0.1;

Check the operation of the program for a = 0.1; b = 1.0; h = 0.1; select the value of parameter n depending on the task.
Why am I getting an error? What is the best way to solve this problem? How to simplify?
var i, n: integer;
x, k, h, sx: real;
function Y(x: real): real;
begin
Y := x * arctan(x) - 0.5 * ln(1.0 + x * x)
end;
function S(x: real): real;
var sum, xx, p, znak, e: real;
begin
S := 0.5 * x * x;
p := x * x;
xx := - x * x;
k := 2;
e := 1e303;
while abs(e) > 1e-14 do
begin
k := k + 2;
p := p * xx;
e := p / (k * (k - 1));
S := S + e
end
end;
begin
h := 0.1;
writeln('x': 2, 'S(x)': 14,
'Y(x)': 18, 'n': 15);
for i := 1 to 10 do
begin
x := i * h;
sx := S(x);
n := round(k / 2);
writeln(x: 3: 1, sx: 18: 14,
Y(x): 18: 14, n: 10)
end
end.
-->The '+' operation is not applicable to the types function(x: real): real and real
I tried to solve the problem based on the fact that x is the range a to b with a step h:
program test;
var y, a, b, h, x, Sx, Yx, n:real;
begin
a:=0.1;
b:=1.0;
h:=0.1;
x:=a;
n:=0;
while x<=b do
begin
Yx:= x*arctan(x)-ln(sqrt(1+exp(x)));
x:=x+h;
writeln(Yx);
writeln('---------------------', n); n:=n+1;
end;
end.
But I do not know how to get S(x)
The error message means that the first argument of + is a function. I'll bet this is the S := S + e line. While you can assign to S to set the return value of S, you can't read it back like that.
You can refer to a function inside that function; this is used with recursion. But then you'll need to actually call yourself. E.g. Fibonacci := Fibonacci(i-1) * i. Now the left side of * is not a function, but the result of a function call.
Solution: just use a temporary variable, and assign that to S at the very end; of S

Pascal duplicate identifier

program Noname4;
function minutes (Amin, Bmin :integer) : integer;
function time (Aval, Bval :integer) : integer;
begin
if (0 <= Aval) and (Bval < 24) then
time :=Bval - Aval;
if (0 <= Amin) and (Bmin < 60) then
minutes :=Bmin - Amin;
end;
var Aval, Amin, Bval, Bmin, n , x , i , y :integer;
duom, rez : text;
begin
readln(Aval, Amin, Bval, Bmin );
writeln(time(Aval, Bval));
writeln(minutes(Amin, Bmin));
readln;
assign(duom, 'Duomenys2.txt');
Reset(duom);
Readln(duom, n );
assign(rez, 'rezultatai2.txt');
rewrite(rez);
for i := 1 to n do
begin
Readln(duom, Aval, Amin, Bval, Bmin);
x := time(Aval, Bval);
y := minutes (Amin, Bmin);
writeln(rez, x);
writeln(rez, y);
end;
close(duom);
close(rez);
end.
Hello, I am getting a error (duplicate identifier, identifier already defined in line 2). It shows red in the ( duom, rez : text; ) line. Can't find out why
program Noname4;
function minutes (Amin, Bmin :integer) : integer;
function time (Aval, Bval :integer) : integer;
begin
if (0 <= Aval) and (Bval < 24) then
time :=Bval - Aval;
if (0 <= Amin) and (Bmin < 60) then
minutes :=Bmin - Amin;
end;
var Aval, Bval, n , x , i , y :integer;
duom, rez : text;
begin
assign(duom, 'Duomenys2.txt');
Reset(duom);
Readln(duom, n );
assign(rez, 'Rezultatai2.txt');
rewrite(rez);
for i := 1 to n do
begin
Readln(duom, Aval, Bval, Amin, Bmin);
x := time(Aval, Bval);
y := minutes(Amin, Bmin);
writeln(rez, x);
writeln(rez, y);
end;
close(duom);
close(rez);
end;
begin
end.
I did what you said, the program now works fine except it doesn't write the the answer in 'Rezultatai2.txt' file.
change:
var Aval, Amin, Bval, Bmin, n , x , i , y :integer;
duom, rez : text;
to:
var Aval, Bval, n , x , i , y :integer;
duom, rez : text;
they are already defined as variables passed into your minute function

`if a = 0 mod p then` in Maple only works when a = 0.

I need it to show the message every time a = 0 (mod p). But it only does it when a is actually 0. For example, if I plug Legendre(11,11), I get "-1".
Legendre := proc (a, p)
local L; if a = `mod`(0, p) then
"Coose a different integer";
else if a = -1 then
L := (-1)^((1/2)*p-1/2);
else
L := `mod`(a^((1/2)*p-1/2), p);
end if;
if L = 1 then
L else L := -1;
L end if end if;
end proc;
a = 'mod'(0, p) should be 0 = 'mod'(a, p)
See the docs.

algorithm to simulate multiplication by addition

How to design an algorithm to simulate multiplication by addition. input two integers. they may be zero, positive or negative..
def multiply(a, b):
if (a == 1):
return b
elif (a == 0):
return 0
elif (a < 0):
return -multiply(-a, b)
else:
return b + multiply(a - 1, b)
some pseudocode:
function multiply(x, y)
if abs(x) = x and abs(y) = y or abs(x) <> x and abs(y) <> y then sign = 'plus'
if abs(x) = x and abs(y) <> y or abs(x) <> x and abs(y) = y then sign = 'minus'
res = 0
for i = 0 to abs(y)
res = res + abs(x)
end
if sign = 'plus' return res
else return -1 * res
end function
val:= 0
bothNegative:=false
if(input1 < 0) && if(input2 < 0)
bothNegative=true
if(bothNegative)
smaller_number:=absolute_value_of(smaller_number)
for [i:=absolute_value_of(bigger_number);i!=0;i--]
do val+=smaller_number
return val;
mul(a,b)
{
sign1=sign2=1;
if(a==0 || b==0)
return 0;
if(a<0){
sign1=-1;
a=-a;
}
if(b<0){
sign2=-1;
b=-b;
}
s=a;
for(i=1;i<b;i++)
s+=a;
if(sign1==sign2)
return s;
else
return -s;
}
How about this for integers:
int multiply(int a, int b)
{
int product = 0;
int i;
if ( b > 0 )
{
for(i = 0; i < b ; i++)
{
product += a;
}
}
else
{
for(i = 0; i > b ; i--)
{
product -= a;
}
}
return product;
}
I got here because I was looking for multiplication algorithm without using * operation. All I see here is just adding or subtracting number n-times. It's O(n) and it's ok, but...
If you have bitwise shift operations you can get O(log n) algorithm for multiplication.
Here is my pseudocode:
function mul(n, x)
if n < 0 then # 'n' cannot be negative
n := -n
x := -x
endif
y := 0
while n != 0 do
if n % 2 == 0 then
x := x << 1 # x := x + x
n := n >> 1 # n := n / 2
else
y := y + x
x := x << 1 # x := x + x
n := n - 1 # n := (n-1)/2
n := n >> 1
endif
endwhile
return y # y = n * x
end
Remember that function above for mul(1000000, 2) is O(log 1000000) and for mul(2, 1000000) is only O(log 2).
Of course, you will get the same results, but keep in mind that the order of the parameters in function call does matter.
Edit: sidenote for using n % 2
Implementation of n % 2 using bitwise shift
It's pretty straightforward. First divide n by 2, then multiply n by 2 and check if n has changed. Pseudocode:
function is_even(n)
n_original := n
n := n >> 1 # n := n / 2
n := n << 1 # n := n * 2
if n = n_original then
return true # n is even
else
return false # n is not even
endif
end
Implementation of n % 2 using bitwise and
function is_even(n)
if n and 1 = 0 then
return true
else
return false
endif
end

Resources