0% found this document useful (0 votes)
81 views28 pages

Lecture 1 Notes Contracts: 15-122: Principles of Imperative Computation (Summer 1 2015) Frank Pfenning

This document summarizes lecture notes on contracts for an imperative programming class. It discusses using contracts like function preconditions, postconditions, and loop invariants to specify and prove the correctness of programs. As an example, it analyzes a mysterious function to determine what it computes, finds the bug, and adds a precondition contract to specify its domain. Through experimenting with inputs and tracing the loop, it is shown the function computes xy for positive y by using the loop invariants r and xy.

Uploaded by

Sebastien
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
81 views28 pages

Lecture 1 Notes Contracts: 15-122: Principles of Imperative Computation (Summer 1 2015) Frank Pfenning

This document summarizes lecture notes on contracts for an imperative programming class. It discusses using contracts like function preconditions, postconditions, and loop invariants to specify and prove the correctness of programs. As an example, it analyzes a mysterious function to determine what it computes, finds the bug, and adds a precondition contract to specify its domain. Through experimenting with inputs and tracing the loop, it is shown the function computes xy for positive y by using the loop invariants r and xy.

Uploaded by

Sebastien
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 28

Lecture 1 Notes

Contracts
15-122: Principles of Imperative Computation (Summer 1 2015)
Frank Pfenning

Introduction

In these notes we review contracts, which we use to collectively denote


function contracts, loop invariants, and other assertions about the program.
Contracts will play a central role in this class, since they represent the key
to connect algorithmic ideas to imperative programs. We follow the example from lecture, developing annotations to a given program that express
the contracts, thereby making the program understandable (and allowing
us to find the bug).
In term of our learning goals, this lecture addresses:
Computational Thinking: Developing contracts (preconditions, postconditions, assertions, and loop invariants) that establish the safety and
correctness of imperative programs.
Developing proofs of the safety and correctness of code with contracts.
Developing informal termination arguments for programs with loops
and recursion.
Identifying the difference between specification and implementation.
Algorithms and Data Structures: Employing integer algorithms (fast power).
Programming: Identifying, describing, and effectively using while-loops
and contracts (in C0).
If you have not seen this example, we invite you to read this section by
section to see how much of the story you can figure out on your own before
moving on to the next section.

L ECTURE N OTES

Contracts

L1.2

A Mysterious Program

You are a new employee in a company, and a colleague comes to you with
the following program, written by your predecessor who was summarily
fired for being a poor programmer. Your colleague claims he has tracked a
bug in a larger project to this function. It is your job to find and correct this
bug.
int f (int x, int y) {
int r = 1;
while (y > 1) {
if (y % 2 == 1) {
r = x * r;
}
x = x * x;
y = y / 2;
}
return r * x;
}
Before you read on, you might examine this program for a while to try
to determine what it does, or is supposed to do, and see if you can spot the
problem.

L ECTURE N OTES

Contracts

L1.3

Forming a Conjecture

The first step it to execute the program on some input values to see its
results. The code is in a file called mystery.c0 so we invoke the coin interpreter to let us experiment with code.
% coin mystery.c0
C0 interpreter (coin)
Type #help for help or #quit to exit.
-->
At this point we can type in statements and they will be executed. One
form of statement is an expression, in which case coin will show its value.
For example:
--> 3+8;
11 (int)
-->
We can also use the functions in the files that we loaded when we
started coin. In this case, the mystery function is called f, so we can evaluate it on some arguments.
--> f(2,3);
8 (int)
--> f(2,4);
16 (int)
--> f(1,7);
1 (int)
--> f(3,2);
9 (int)
-->
Can you form a conjecture from these values?

L ECTURE N OTES

Contracts

L1.4

From these and similar examples, you might form the conjecture that
f (x, y) = xy , that is, x to the power y. One can confirm that with a few
more values, such as
--> f(-2,3);
-8 (int)
--> f(2,8);
256 (int)
--> f(2,10);
1024 (int)
-->
It seems to work out! Our next task is to see why this function actually
computes the power function. Understanding this is necessary so we can
try to find the error and correct it.

L ECTURE N OTES

Contracts

L1.5

Finding a Loop Invariant

Now we start to look inside the function and see how it computes.
int f (int x, int y) {
int r = 1;
while (y > 1) {
if (y % 2 == 1) {
r = x * r;
}
x = x * x;
y = y / 2;
}
return r * x;
}
We notice the conditional
if (y % 2 == 1) {
r = x * r;
}
The condition tests if y modulo 2 is 1. For positive y, this is true if y is odd.
We also observe that in the loop body, y must indeed be positive so this is
a correct test for whether y is odd.
Each time around the loop we divide y by 2, using integer division
(which rounds towards 0). It is exact division if y is even. If y starts as
a power of 2, it will remain even throughout the iteration. In this case r
will remain 1 throughout the execution of the function. Lets tabulate how
the loop works for x = 2 and y = 8. But at which point in the program do
we tabulate the values? It turns out generally the best place for a loop is just
before the exit condition is tested. By iteration 0 we mean when we enter the
loop the first time and test the condition; iteration 1 is after the loop body
has been traversed once and we are looking again at the exit condition, etc.
iteration x
0
2
1
4
2
16
3
256

y
8
4
2
1

r
1
1
1
1

After 3 iterations, x = 256 and y = 1, so the loop condition y > 1 becomes


false and we exit the loop. We return r x = 256.
L ECTURE N OTES

Contracts

L1.6

To understand why this loop works we need to find a so-called loop invariant: a quantity that does not change throughout the loop. In this example, when y is a power of 2 then r is a loop invariant. Can you see a loop
invariant involving just x and y?

L ECTURE N OTES

Contracts

L1.7

Going back to our earlier conjecture, we are trying to show that this
function computes xy . Interestingly, after every iteration of the loop, this
quantity is exactly the same! Before the first iteration it is 28 = 256. After
the first iteration it is 44 = 256. After the second iteration it is 162 = 256.
After the third iteration is it is 2561 = 256. Lets note it down in the table.
iteration x
0
2
1
4
2
16
3
256

y
8
4
2
1

r
1
1
1
1

xy
256
256
256
256

Still concentrating on this special case where y is a power of 2, lets see


if we can use the invariant to show that the function is correct.

L ECTURE N OTES

Contracts

L1.8

Proving the Loop Invariant

To show that the quantity xy is a loop invariant, we have to prove that


if we execute the loop body once, xy before will be equal to xy after. We
cannot write this as xy = xy , because that is of course always true, speaking
mathematically. Mathematics does not understand the idea of assigning a
new value to a variable. The general convention we follow is to add a prime
(0 ) to the name of a variable to denote its value after an iteration.
So assume we have x and y, and y is a power of 2. After one iteration
we have x0 = x x and y 0 = y/2. To show that xy is loop invariant, we have
0
to show that xy = x0 y . So lets calculate:
x0 y

=
=
=
=

(x x)y/2
(x2 )y/2
x2(y/2)
xy

By definition of x0 and y 0
Since a a = a2
Since (ab )c = abc
Since 2 (a/2) = a when a is even

Moreover, if y is a power of 2, then y 0 = y/2 is also a power of 2 (subtracting


1 from the exponent).
We have confirmed that xy is loop invariant if y is a power of 2. Does
this help us to ascertain that the function is correct when y is a power of
two?

L ECTURE N OTES

Contracts

L1.9

Loop Invariant Implies Postcondition

The postcondition of a function is usually a statement about the result it returns. Here, the postcondition is that f (x, y) = xy . Lets recall the function:
int f (int x, int y) {
int r = 1;
while (y > 1) {
if (y % 2 == 1) {
r = x * r;
}
x = x * x;
y = y / 2;
}
return r * x;
}
If y is a power of 2, then the quantity xy never changes in the loop (as we
have just shown). Also, in that case r never changes, remaining equal to 1.
When we exit the loop, y = 1 because y starts out as some (positive) power
of 2 and is divided by 2 every time around loop. So then
r x = 1 x = x = x1 = xy
so we return the correct result, xy !
By using two loop invariant expressions (r and xy ) we were able to
show that the function returns the correct answer if it does return an answer. Does the loop always terminate?

L ECTURE N OTES

Contracts

L1.10

Termination

In this case it is easy to see that the loop always terminates. To show that
a loop always terminates, we need to define some quantity that always gets
strictly smaller during any arbitrary iteration of the loop, and that can never
become negative. This means that the loop can only run a finite number of
times.
The quantity y/2 is always less than y when y > 0, so on any arbitrary
iteration of the loop, y gets strictly smaller and it can never become negative. Therefore, we know the loop has to terminate.
(By the same token, we could identify any lower bound, not just zero,
and a quantity that strictly decreased and never passed that lower bound.
or we could identify an upper bound and a quantity that strictly increased
but never passed that upper bound!)

L ECTURE N OTES

Contracts

L1.11

A Counterexample

We dont have to look at powers of 2 we already know the function


works correctly there. Some of the earlier examples were not powers of
two, and the function still worked:
--> f(2,3);
8 (int)
--> f(-2,3);
-8 (int)
--> f(2,1);
2 (int)
-->
What about 0, or negative exponents?
--> f(2,0);
2 (int)
--> f(2,-1);
2 (int)
-->
Looks like we have found at least two problems. 20 = 1, so the answer 2
is definitely incorrect. 21 = 1/2 so one might argue it should return 0. Or
one might argue in the absence of fractions (we are working with integers),
a negative exponent does not make sense. In any case, f (2, 1) should
certainly not return 2.

L ECTURE N OTES

Contracts

L1.12

Imposing a Precondition

Lets go back to a mathematical definition of the power function xy on integers x and y. We define:
x0
= 1
xy+1 = x xy for y 0
In this form it remains undefined for negative exponents. In programming,
this is captured as a precondition: we require that the second argument to f
not be negative. Preconditions are written as //@requires and come before
the body of the function.
int f (int x, int y)
//@requires y >= 0;
{
int r = 1;
while (y > 1) {
if (y % 2 == 1) {
r = x * r;
}
x = x * x;
y = y / 2;
}
return r * x;
}
This is the first part of what we call the function contract. It expresses what
the function requires of any client that calls it, namely that the second argument is positive. It is an error to call it with a negative argument; no
promises are made about what the function might return otherwise. It
might even abort the computation due to a contract violation.
But a contract usually has two sides. What does f promise? We know it
promises to compute the exponential function, so this should be formally
expressed.

L ECTURE N OTES

Contracts

10

L1.13

Promising a Postcondition

The C0 language does not have a built-in power function. So we need to


write it explicitly ourselves. But wait! Isnt that what f is supposed to do?
The idea in this and many other examples to capture a specification in the
simplest possible form, even if it may not be computationally efficient, and
then promise in the postcondition to satisfy this simple specification. Here,
we can transcribe the mathematical definition into a recursive function.
int POW (int x, int y)
//@requires y >= 0;
{
if (y == 0)
return 1;
else
return x * POW(x, y-1);
}
In the rest of the lecture we often silently go back and forth between xy
and P OW (x, y). Now we incorporate POW into a formal postcondition for
the function. Postconditions have the form //@ensures e;, where e is a
boolean expression. They are also written before the function body, by convention after the preconditions. Postconditions can use a special variable
\result to refer to the value returned by the function.
int f (int x, int y)
//@requires y >= 0;
//@ensures \result == POW(x,y);
{
int r = 1;
while (y > 1) {
if (y % 2 == 1) {
r = x * r;
}
x = x * x;
y = y / 2;
}
return r * x;
}
Note that as far as the function f is concerned, if we are considering calling it we do not need to look at its body at all. Just looking at the preL ECTURE N OTES

Contracts

L1.14

and post-conditions (the @requires and @ensures clauses), tells us everything we need to know. As long as we adhere to our contract and pass f a
nonnegative y, then f will adhere to its contract and return xy .

L ECTURE N OTES

Contracts

11

L1.15

Dynamically Checking Contracts

During the program development phase, we can instruct the C0 compiler


or interpreter to check adherence to contracts. This is done with the -d flag
on the command line, which stands for dynamic checking. Lets see how the
implementation now reacts to correct and incorrect inputs, assuming we
have added POW as well as pre- and postconditions as shown above.
% coin solution2a.c0 -d
foo.c0:10.5-10.6:error:cannot assign to variable x
used in @ensures annotation
x = x * x;
~
Unable to load files, exiting...
%
The error is that we are changing the value of x in the body of the loop,
while the postcondition refers to x. If it were allowed, it would violate the
principle that we need to look only at the contract when calling the function, because assignments to x change the meaning of the postcondition.
We want \result == POW(x,y) for the original x and y we passed as arguments to f and not the values x and y might hold at the end of the function.
We therefore change the function body, creating auxiliary variables b
(for base) and e (for exponent) to replace x and y which we leave unchanged.
int f (int x, int y)
//@requires y >= 0;
//@ensures \result == POW(x,y);
{
int r = 1;
int b = x; /* base */
int e = y; /* exponent */
while (e > 1) {
if (e % 2 == 1) {
r = b * r;
}
b = b * b;
e = e / 2;
}
return r * b;
}
L ECTURE N OTES

Contracts

L1.16

Now invoking the interpreter with -d works correctly when we return


the right answer, but raises an exception if we give it arguments where we
know the function to be incorrect, or arguments that violate the precondition to the function.
% coin solution2b.c0 -d
C0 interpreter (coin) 0.3.2 Nickel (r256, Thu Jan
Type #help for help or #quit to exit.
--> f(3,2);
9 (int)
--> f(3,-1);
foo.c0:12.4-12.20: @requires annotation failed

3 14:18:03 EST 2013)

Last position: foo.c0:12.4-12.20


f from <stdio>:1.1-1.8
--> f(2,0);
foo.c0:13.4-13.32: @ensures annotation failed
Last position: foo.c0:13.4-13.32
f from <stdio>:1.1-1.7
-->
The fact that @requires annotation fails in the second example call means
that our call is to blame, not f . The fact that the @ensures annotation fails
in the third example call means the function f does not satisfy its contract
and is therefore to blame.

L ECTURE N OTES

Contracts

12

L1.17

Generalizing the Loop Invariant

Before fixing the bug with an exponent of 0, lets figure out why the function apparently works when the exponent is odd. Our loop invariant so far
only works when y is a power of 2. It uses the basic law that b2c = (b2 )c =
(b b)c in the case where the exponent e = 2 c is even.
What about the case where the exponent is odd? Then we are trying
to compute b2c+1 . With analogous reasoning to above we obtain b2c+1 =
b b2c = b (b b)c . This means there is an additional factor of b in the
answer. We see that we exactly multiply r by b in the case that e is odd!
int f (int x, int y)
//@requires y >= 0;
//@ensures \result == POW(x,y);
{
int r = 1;
int b = x; /* base */
int e = y; /* exponent */
while (e > 1) {
if (e % 2 == 1) {
r = b * r;
}
b = b * b;
e = e / 2;
}
return r * b;
}
What quantity remains invariant now, throughout the loop? Try to form a
conjecture for a more general loop invariant before reading on.

L ECTURE N OTES

Contracts

L1.18

Lets make a table again, this time to trace a call when the exponent is
not a power of two, say, while computing 27 by calling f (2, 7).
iteration b
0
2
1
4
2
16

e
7
3
1

r be
1 128
2 64
8 16

As we can see, be is not invariant, but r be = 128 is! The extra factor from
the equation on the previous page is absorbed into r.
We now express this proposed invariant formally in C0. This requires
the @loop_invariant annotation. It must come immediately before the
loop body, but it is checked just before the loop exit condition. We would
like to say that the expression r * POW(b,e) is invariant, but this is not
possible directly.
Loop invariants in C0 are boolean expressions which must be either true
or false. We can achieve this by stating that r * POW(b,e) == POW(x,y).
Observe that x and y do not change in the loop, so this guarantees that
r * POW(b,e) never changes either. But it says a little more, stating what
the invariant quantity is in term of the original function parameters.
int f (int x, int y)
//@requires y >= 0;
//@ensures \result == POW(x,y);
{
int r = 1;
int b = x; /* base */
int e = y; /* exponent */
while (e > 1)
//@loop_invariant r * POW(b,e) == POW(x,y);
{
if (e % 2 == 1) {
r = b * r;
}
b = b * b;
e = e / 2;
}
return r * b;
}

L ECTURE N OTES

Contracts

13

L1.19

Fixing the Function

The bug we have discovered so far was for y = 0. In that case, e = 0


so we never go through the loop. If we exit the loop and e = 1, then the
loop invariant implies the function postcondition. To see this, note that we
return r b and r b = r b1 = r be = xy , where the last equation is the
loop invariant. When y (and therefore e) is 0, however, this reasoning does
not apply because we exit the loop and e = 0, not 1.
Think about how you might fix the function and its annotations before
reading on.

L ECTURE N OTES

Contracts

L1.20

We can fix it by carrying on with the while loop until e = 0. On the


last iteration e is 1, which is odd, so we set r0 = b r. This means we now
should return r0 (the new r) after the one additional iteration of the loop,
and not r b.
int f (int x, int y)
//@requires y >= 0;
//@ensures \result == POW(x,y);
{
int r = 1;
int b = x; /* base */
int e = y; /* exponent */
while (e > 0)
//@loop_invariant r * POW(b,e) == POW(x,y);
{
if (e % 2 == 1) r = b * r;
b = b * b;
e = e / 2;
}
return r;
}
Now when the exponent y = 0 we skip the loop body and return r = 1,
which is the right answer for x0 ! Indeed:
% coin solution2d.c0 -d
Coin 0.2.3 "Penny" (r1478, Thu Jan 20 16:14:15 EST 2011)
Type #help for help or #quit to exit.
--> f(2,0);
1 (int)
-->

L ECTURE N OTES

Contracts

14

L1.21

Strengthening the Loop Invariant Again

We would now like to show that the improved function is correct. That
requires two steps: one is that the loop invariant implies the postcondition;
another is that the proposed loop invariant is indeed a loop invariant. The
loop invariant, r be = xy implies that the result r = xy if we know that
e = 0 (since b0 = 1).
But how do we know that e = 0 when we exit the loop? Actually,
we dont: the loop invariant is too weak to prove that. The negation of
the exit condition only tells us that e 0. However, if we add another
loop invariant, namely that e 0, then we know e = 0 when the loop is
exited and the postcondition follows. For clarity, we also add a (redundant)
assertion to this effect after the loop and before the return statement.
int f (int x, int y)
//@requires y >= 0;
//@ensures \result == POW(x,y);
{
int r = 1;
int b = x; /* base */
int e = y; /* exponent */
while (e > 0)
//@loop_invariant e >= 0;
//@loop_invariant r * POW(b,e) == POW(x,y);
{
if (e % 2 == 1) {
r = b * r;
}
b = b * b;
e = e / 2;
}
//@assert e == 0;
return r;
}
The @assert annotation can be used to verify an expression that should
be true. If it is not, our reasoning must have been faulty somewhere else.
@assert is a useful debugging tool and sometimes helps the reader understand better what the code author intended.

L ECTURE N OTES

Contracts

15

L1.22

Verifying the Loop Invariants

It seems like we have beaten this example to death: we have added pre- and
post-conditions, stated loop invariants, fixed the original bug and shown
that the loop invariants imply the postcondition. But we have not yet verified that the loop invariant actually holds! Ouch! Lets do it.
We begin with the invariant e 0. We have to demonstrate two properties.
Init: The invariant holds initially. When we enter the loop, e = y and y 0
by the precondition of the function. Done.
Preservation: Assume the invariant holds just before the exit condition is
checked. We have to show that it is true again when we reach the exit
condition after one iteration of the loop
Assumption: e 0.
To show: e0 0 where e0 = e/2, with integer division. This clearly
holds.
Next, we look at the invariant r P OW (b, e) = P OW (x, y).
Init: The invariant holds initially, because when entering the loop we have
r = 1, b = x and e = y.
Preservation: We show that the invariant is perserved on every iteration.
For this, we distinguish two cases: e is even and e is odd.
Assumption: r P OW (b, e) = P OW (x, y).
To show: r0 P OW (b0 , e0 ) = P OW (x, y), where r0 , b0 , and e0 are the
values of r, b, and e after one iteration.
Case: e is even. Then r0 = r, b0 = b b and e0 = e/2 and we reason:
r0 P OW (b0 , e0 ) = r P OW (b b, e/2)
= r P OW (b, 2 (e/2)) Since (a2 )c = a2c
= r P OW (b, e)
Since e is even
= P OW (x, y)
By assumption
Case: e is odd. Then r0 = b r, b0 = b b and e0 = (e 1)/2 (because
e is odd, integer division rounds towards 0, and e 0) and we

L ECTURE N OTES

Contracts

L1.23

reason:
r0 P OW (b0 , e0 ) =
=
=
=
=

(b r) P OW (b b, (e 1)/2)
(b r) P OW (b, 2 (e 1)/2)
(b r) P OW (b, e 1)
r P OW (b, e)
P OW (x, y)

This shows that both loop invariants hold on every iteration.

L ECTURE N OTES

Since (a2 )c = a2c


Since e 1 is even
Since a (ac ) = ac+1
By assumption

Contracts

16

L1.24

Termination

The previous argument for termination still holds. By loop invariant, we


know that e 0. When we enter the body of the loop, the condition must
be true so e > 0. Now we just use that e/2 < e for e > 0, so the value
of e is strictly decreasing and positive, which, as an integer, means it must
eventually become 0, upon which we exit the loop and return from the
function after one additional step.

L ECTURE N OTES

Contracts

17

L1.25

A Surprise

Now, lets try our function on some larger numbers, computing some powers of 2.
% coin -d solution2e.c0
Coin 0.2.3 "Penny" (r1478, Thu Jan 20 16:14:15 EST 2011)
Type #help for help or #quit to exit.
--> f(2,30);
1073741824 (int)
--> f(2,31);
-2147483648 (int)
--> f(2,32);
0 (int)
-->
230 looks plausible, but how could 231 be negative or 232 be zero? We
claimed we just proved it correct!
The reason is that the values of type int in C0 or C and many other
languages actually do not represent arbitrarily large integers, but have a
fixed-size representation. In mathematical terms, this means we that we are
dealing with modular arithmetic. The fact that 232 = 0 provides a clue that
integers in C0 have 32 bits, and arithmetic operations implement arithmetic
modulo 232 .
In this light, the results above are actually correct. We examine modular
arithmetic in detail in the next lecture.

L ECTURE N OTES

Contracts

18

L1.26

Summary: Contracts, and Why They are Important

We have introduced contracts, using the example of an algorithm for integer


exponentiation.
Contracts are expressed in form of annotations, started with //@. These
annotations are checked when the program is executed if it is compiled or
interpreted with the -d flag. Otherwise, they are ignored.
The forms of contracts, and how they are checked, are:
@requires: A precondition to a function. This is checked just before the
function body executes.
@ensures: A postcondition for a function. This is checked just after the
function body has been executed. We use \result to refer to the value
returned by the function to impose a condition on it.
@loop invariant: A loop invariant. This is checked every time just before
the loop exit condition is tested.
@assert: An assertion. This is like a statement and is checked every time
it is encountered during execution.
Contracts are important for two purposes.
Testing: Contracts represent a kind of generic test of a function. Rather
than stating specific inputs (like f(2,8) and testing the answer 256),
contracts talk about expected properties for arbitrary values. On the
other hand, contracts are only useful in this regard if we have a good
set of test cases, because contracts that are not executed with values
that cause them to fail cannot cause execution to abort.
Reasoning: Contracts express important properties of programs so we can
prove them. Ultimately, this can mathematically verify program correctness. Since correctness is the most important concern about programs, this is a crucial aspect of program development. Different
forms of contracts have different roles, reviewed below.
The proof obligations for contracts are as follows:
@requires: At the call sites we have to prove that the precondition for the
function is satisfied for the given arguments. We can then assume it
when reasoning in the body of the function.

L ECTURE N OTES

Contracts

L1.27

@ensures: At the return sites inside a function we have to prove that the
postcondition is satisfied for the given return value. We can then assume it at the call site.
@loop invariant: We have to show:
Init: The loop invariant is satisfied initially, when the loop is first
encountered.
Preservation: Assuming the loop invariant is satisfied at the beginning of the loop (just before the exit test), we have to show it still
holds when the beginning of the loop is reached again, after one
iteration of the loop.
We are then allowed to assume that the loop invariant holds after the
loop exits, together with the exit condition.
@assert: We have to show that an assertion is satisfied when it is reached
during program execution. We can then assume it for subsequent
statements.
Contracts are crucial for reasoning since (a) they express what needs to
be proved in the first place (give the programs specification), and (b) they
localize reasoning: from a big program to the conditions on the individual
functions, from the inside of a big function to each loop invariant or assertion.

L ECTURE N OTES

Contracts

L1.28

Exercises
Exercise 1 Rewrite first POW and then f so that it signals an error in case of an
overflow rather than silently working in modular arithmetic. You can use the
statement error("Overflow"); to signal an overflow.
Exercise 2 Find an input for f that fails the first guess of a loop invariant:
//@loop_invariant r * POW(b,e) == POW(x,y);

L ECTURE N OTES

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy