Proving gcd algorithm with Dafny - greatest-common-divisor

I'm trying to prove the gcd algorithm with Dafny and it's apparently not that simple. What I have so far (not much indeed) is a functional specification, and Dafny manages to prove that compute_gcd behaves like it. However, when I remove the comments [1], [2] and [3] Dafny fails
to prove that the functional specification has the desired properties:
function gcd(a: int, b: int) : (result : int)
requires a > 0
requires b > 0
// [1] ensures (exists q1:int :: (q1 * result == a))
// [2] ensures (exists q2:int :: (q2 * result == b))
// [3] ensures forall d :int, q1:int, q2:int :: ((q1*d==a)&&(q2*d==b)) ==> (exists q3:int :: (q3*d == result))
{
if (a > b) then gcd(a-b,b) else
if (b > a) then gcd(a,b-a) else a
}
method compute_gcd(a: int, b: int) returns (result: int)
requires a > 0
requires b > 0
ensures result == gcd(a,b)
{
var x := a;
var y := b;
while (x != y)
decreases x+y
invariant x > 0
invariant y > 0
invariant gcd(x,y) == gcd(a,b)
{
if (x > y) { x := x - y; }
if (y > x) { y := y - x; }
}
return x;
}
Am I going in the right direction?
any help is very much appreciated, thanks!

I managed to prove a weaker gcd specification (permalink here), but I'm still having a hard time with property [3] above:
function gcd(a: int, b: int) : (result : int)
requires a > 0
requires b > 0
// [1] ensures (exists q1:int :: (q1 * result == a))
// [2] ensures (exists q2:int :: (q2 * result == b))
{
if (a > b) then gcd(a-b,b) else
if (b > a) then gcd(a,b-a) else a
}
lemma gcd_correct(a: int, b: int)
requires a > 0
requires b > 0
ensures (exists q1:int :: (q1 * gcd(a,b) == a))
ensures (exists q2:int :: (q2 * gcd(a,b) == b))
{
if (a > b)
{
gcd_correct(a-b, b);
var q1 :| q1 * gcd(a-b,b) == a-b;
var q2 :| q2 * gcd(a-b,b) == b;
assert (q1+q2) * gcd(a,b) == a;
}
else if (b > a)
{
gcd_correct(a,b-a);
var q1 :| q1 * gcd(a,b-a) == a;
var q2 :| q2 * gcd(a,b-a) == b-a;
assert (q2+q1) * gcd(a,b) == b;
}
else
{
assert 1 * gcd(a,b) == a;
}
}
method compute_gcd(a: int, b: int) returns (result: int)
requires a > 0
requires b > 0
ensures result == gcd(a,b)
ensures (exists q1:int :: (q1 * result == a))
ensures (exists q2:int :: (q2 * result == b))
{
var x := a;
var y := b;
while (x != y)
decreases x+y
invariant x > 0
invariant y > 0
invariant gcd(x,y) == gcd(a,b)
{
if (x > y) { x := x - y; }
if (y > x) { y := y - x; }
}
gcd_correct(a,b);
return x;
}
Any tips?

You might take a look at the GCD algorithm in the Dafny test suite (in Test/VerifyThis2015/Problem2.dfy) and compare it with your approach:

Related

ComputeGCD Dafny

Hi I am trying to prove that the code I write will return the GreatestCommonDivisor (ComputeGCD) with Dafny.
but i get stack . I dont undrstand how to prove it , and i cant change the ComputeGCD
requires and ensures . any Help please .
predicate CommonDivisor(a: nat, b: nat, c: nat)
{
c > 0 && c <=a && c <=b && a%c == b%c == 0 // i add that c<=a && c<=b
}
predicate GreatestCommonDivisor(a: nat, b: nat, c: nat)
{
CommonDivisor(a, b, c) &&
forall d: nat :: CommonDivisor(a, b, d) ==> d <= c
}
lemma {:verify false} GreatestCommonDivisorHeper (a: nat , b:nat , c: nat)
requires a > 0 && b > 0
ensures GreatestCommonDivisor( a, b, c)
{}
method {:verify false} ComputeGCD(a: nat, b: nat) returns (i: nat)
requires a > 0 && b > 0
ensures GreatestCommonDivisor(a, b, i)
{
var x: int;
i := a;
x := b;
assert i == a && x ==b;
while (x != i)
invariant i > 0 && x > 0
decreases x + i
{
if (i > x)
{
assert i > x;
i := i - x;
}
else{
assert i < x ;
x := x - i;
}
}
assert a > 0 && b > 0 ;
assert GreatestCommonDivisor(b - a, a, i);
GreatestCommonDivisorHeper(a,b,i);
// assert GreatestCommonDivisor(a, b, i) == GreatestCommonDivisor(a,b - a, i);
}

Why is head-tail pattern matching so much faster than indexing?

I was working on a HackerRank problem today and initially wrote it with indexing and it was incredibly slow for most of the test cases because they were huge. I then decided to switch it to head:tail pattern matching and it just zoomed. The difference was absolutely night and day, but I can't figure out how it was such a change in efficiency. Here is the code for reference if it is at all useful
Most efficient attempt with indexing
count :: Eq a => Integral b => a -> [a] -> b
count e [] = 0
count e (a:xs) = (count e xs +) $ if a == e then 1 else 0
fullCheck :: String -> Bool
fullCheck a = prefixCheck 0 (0,0,0,0) a (length a) && (count 'R' a == count 'G' a) && (count 'Y' a == count 'B' a)
prefixCheck :: Int -> (Int, Int, Int, Int) -> String -> Int -> Bool
prefixCheck n (r',g',y',b') s l
| n == l = True
| otherwise =
((<= 1) $ abs $ r - g) && ((<= 1) $ abs $ y - b)
&& prefixCheck (n+1) (r,g,y,b) s l
where c = s !! n
r = if c == 'R' then r' + 1 else r'
g = if c == 'G' then g' + 1 else g'
y = if c == 'Y' then y' + 1 else y'
b = if c == 'B' then b' + 1 else b'
run :: Int -> IO ()
run 0 = putStr ""
run n = do
a <- getLine
print $ fullCheck a
run $ n - 1
main :: IO ()
main = do
b <- getLine
run $ read b
head:tail pattern matching attempt
count :: Eq a => Integral b => a -> [a] -> b
count e [] = 0
count e (a:xs) = (count e xs +) $ if a == e then 1 else 0
fullCheck :: String -> Bool
fullCheck a = prefixCheck (0,0,0,0) a && (count 'R' a == count 'G' a) && (count 'Y' a == count 'B' a)
prefixCheck :: (Int, Int, Int, Int) -> String -> Bool
prefixCheck (r,g,y,b) [] = r == g && y == b
prefixCheck (r',g',y',b') (h:s) = ((<= 1) $ abs $ r - g) && ((<= 1) $ abs $ y - b)
&& prefixCheck (r,g,y,b) s
where r = if h == 'R' then r' + 1 else r'
g = if h == 'G' then g' + 1 else g'
y = if h == 'Y' then y' + 1 else y'
b = if h == 'B' then b' + 1 else b'
run :: Int -> IO ()
run 0 = putStr ""
run n = do
a <- getLine
print $ fullCheck a
run $ n - 1
main :: IO ()
main = do
b <- getLine
run $ read b
For reference as well, the question was
You are given a sequence of N balls in 4 colors: red, green, yellow and blue. The sequence is full of colors if and only if all of the following conditions are true:
There are as many red balls as green balls.
There are as many yellow balls as blue balls.
Difference between the number of red balls and green balls in every prefix of the sequence is at most 1.
Difference between the number of yellow balls and blue balls in every prefix of the sequence is at most 1.
Where a prefix of a string is any substring from the beginning to m where m is less than the size of the string
You have already got the answer in the comments why lists indexing performs linearly. But, if you are interested in a more Haskell style solution to the Hackerrank problem your referring to, even head-tail pattern matching is unnecessary. A more performant solution can be done with right folds:
import Control.Applicative ((<$>))
import Control.Monad (replicateM_)
solve :: String -> Bool
solve s = foldr go (\r g y b -> r == g && y == b) s 0 0 0 0
where
go x run r g y b
| 1 < abs (r - g) || 1 < abs (y - b) = False
| x == 'R' = run (r + 1) g y b
| x == 'G' = run r (g + 1) y b
| x == 'Y' = run r g (y + 1) b
| x == 'B' = run r g y (b + 1)
main :: IO ()
main = do
n <- read <$> getLine
replicateM_ n $ getLine >>= print . solve

Integer in an interval with maximized number of trailing zero bits

Sought is an efficient algorithm that finds the unique integer in an interval [a, b] which has the maximum number of trailing zeros in its binary representation (a and b are integers > 0):
def bruteForce(a: Int, b: Int): Int =
(a to b).maxBy(Integer.numberOfTrailingZeros(_))
def binSplit(a: Int, b: Int): Int = {
require(a > 0 && a <= b)
val res = ???
assert(res == bruteForce(a, b))
res
}
here are some examples
bruteForce( 5, 7) == 6 // binary 110 (1 trailing zero)
bruteForce( 1, 255) == 128 // binary 10000000
bruteForce(129, 255) == 192 // binary 11000000
etc.
This one finds the number of zeros:
// Requires a>0
def mtz(a: Int, b: Int, mask: Int = 0xFFFFFFFE, n: Int = 0): Int = {
if (a > (b & mask)) n
else mtz(a, b, mask<<1, n+1)
}
This one returns the number with those zeros:
// Requires a > 0
def nmtz(a: Int, b: Int, mask: Int = 0xFFFFFFFE): Int = {
if (a > (b & mask)) b & (mask>>1)
else nmtz(a, b, mask<<1)
}
I doubt the log(log(n)) solution has a small enough constant term to beat this. (But you could do binary search on the number of zeros to get log(log(n)).)
I decided to take Rex's challenge and produce something faster. :-)
// requires a > 0
def mtz2(a: Int, b: Int, mask: Int = 0xffff0000, shift: Int = 8, n: Int = 16): Int = {
if (shift == 0) if (a > (b & mask)) n - 1 else n
else if (a > (b & mask)) mtz2(a, b, mask >> shift, shift / 2, n - shift)
else mtz2(a, b, mask << shift, shift / 2, n + shift)
}
Benchmarked with
import System.{currentTimeMillis => now}
def time[T](f: => T): T = {
val start = now
try { f } finally { println("Elapsed: " + (now - start)/1000.0 + " s") }
}
val range = 1 to 200
time(f((a, b) => mtz(a, b)))
time(f((a, b) => mtz2(a, b)))
First see if there is a power of two that lies within your interval. If there is at least one, the largest one wins.
Otherwise, choose the largest power of two that is less than your minimum bound.
Does 1100000...0 lie in your bound? If yes, you've won. If it's still less than your minimum bound, try 1110000...0; otherwise, if it's greater than your maximum bound, try 1010000...0.
And so forth, until you win.
as a conclusion, here is my variant of Rex' answer which gives both the center value and also an 'extent' which is the minimum power of two distance from the center which covers both a in the one direction and b in the other.
#tailrec def binSplit(a: Int, b: Int, mask: Int = 0xFFFFFFFF): (Int, Int) = {
val mask2 = mask << 1
if (a > (b & mask2)) (b & mask, -mask)
else binSplit(a, b, mask2)
}
def test(): Unit = {
val Seq(r1, r2) = Seq.fill(2)(util.Random.nextInt(0x3FFFFFFF) + 1)
val (a, b) = if (r1 <= r2) (r1, r2) else (r2, r1)
val (center, extent) = binSplit(a, b)
assert((center >= a) && (center <= b) && (center - extent) <= a &&
(center - extent) >= 0 && (center + extent) > b, (a, b, center, extent))
}
for (i <- 0 to 100000) { test() }

Missing if/else statements detection by static analysis

I'm trying to catch missing unhandled conditions of expressiong inside if statements.
First Example
if (a < 5) {
// Do something
} else {
// handled else condition
}
Second Example
if (a < 5) {
// Do something
} else if (a >= 5){
// handled else if condition
}
this two examples are correct and all possibilities are handled.
But I'm trying to cathc the conditions like
if ((a < 5) && b > 10) {
// Do something
} else if ((a >= 5) && (b > 10)){
// handled else condition
} else if((a < 5) && (b <= 10)) {
// handled else condition
}
But this condition does not handle all possibilities and there is a missing condition of
} else if ((a >= 5) && (b <= 10)) {
// missing condition which is not handled
}
I'm trying to find these kind of vulnerability by static analysis and using Abstract Syntax Tree of source codes. Is there any algorithm, approach or any paper which is studied on problem like that?
If you have code like
if(A) { ... }
else if (B) { ... }
else if (C) { ... }
and you want to make sure that all possibilities are handled, then you have to prove that the formula A or B or C always evaluates to true. If all you do is check for ranges, then I would transform this formula to a conjunctive normal form.
After this transformation you have a formula of the form
(F1 or F2 or ...) and (G1 or G2 or G3) and (H1 or H2 or H3) ...
where each atomic proposition is of the form (x < c), (x ≤ c), (x > c) or (x ≥ c), where x is a variable and c is a constant. These propositions can be combined by using the following transformations:
(x < c1) together with (x > c2) transforms to true if (c1 > c2)
(x < c1) together with (x ≥ c2) transforms to true if (c1 ≥ c2)
(x ≤ c1) together with (x > c2) transforms to true if (c1 ≥ c2)
(x ≤ c1) together with (x ≥ c2) transforms to true if (c1 ≥ c2)
Now look at the clause (F1 or F2 or ...). As soon as you are able to perform one of these transformations, then the entire clause is valid, and you can begin checking the next clause.
If all clauses are valid, then all possibilities are handled.
A generic solution (where the conditions in the if statements can be anything) is not as trivial. For instance, if you want to check if(f(x) || g(x)), it is possible that f() or g() have side effects, or perform very complex calculations.
If you wish to reduce your problem to a more general problem, you can transform the code
if ((a < 5) && b > 10) {
// Do something
} else if ((a >= 5) && (b > 10)){
// handled else condition
} else if((a < 5) && (b <= 10)) {
// handled else condition
}
into:
if ((a < 5) && b > 10) {
// Do something
} else if ((a >= 5) && (b > 10)){
// handled else condition
} else if((a < 5) && (b <= 10)) {
// handled else condition
} else {
/*# assert false ; */
}
A reasonable compiler would emit the same code for the transformed version as for the original version, and now you can use static analysis or test generation to verify that the assert holds, which is the same as verifying that the last else is never taken, which is exactly the property you are interested in.
Tools exist if the above code is Java (the assert can be a JML annotation), C (the assert can be an ACSL annotation), or C# (the assert can be a Spec# annotation). Elian Ebbing's algorithm is fine, but the alternative I suggest it to let the automated theorem provers used as back-end for these tools do the job without re-implementing the wheel that determines if a given logical proposition is a tautology. Chances are that the existing wheels are doing a better job than you'll ever be able to get.
Example in C, using Frama-C and Jessie:
int a, b;
main(){
if ((a < 5) && b > 10) {
// Do something
} else if ((a >= 5) && (b > 10)){
// handled else condition
} else if((a < 5) && (b <= 10)) {
// handled else condition
} else {
/*# assert \false ; */
}
}
The assertion is not verified, indicating that Jessie wasn't able to verify that the last case was unreachable. Adding } else if ((a >= 5) && (b <= 10)) {, the assertion is verified.

Can you simplify this expression?

One for the mathematicians. This has gone around the office and we want to see who can come up with a better optimised version.
(((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) &&
((b - (a + p) == 0) || (b - (a + p) > 1))
Edit: all data is positive int's
Edit: Better == simpler
(a + p <= b) && (a != 1) && (b - a - p != 1);
If the formula works and come from your business rules there is no real need to simplify it. The compiler probably knows better than us how to optimizing the formula.
The only thing you should do is use better variables names which reflect the business logic.
Beware of applying any of the proposed solution before unit testing them.
Refactor for simplicity by introducing more local variables which indicate the meaning of each expression. This is hard for us to do with no idea of what a, b and p mean.
b >= p && b != p+1
EDIT: Ok, that didn't work, but this one does:
a != 1 && b >= a+p && b-a-p != 1
(a!=1) && ((b==a+p) || (b>1+a+p))
It may not the simplest, but should be the one of most readable.
I wouldnt do all math in that expression. Such as b - ( a + p ) is evaluated twice. If possible, split them into variables instead.
Also, writing a polish notiation tree might help you optimize it, everything that you see twice, can be re-used.
Since they are all positive ints a lot of the repetition can be removed:
So as a first step,
(((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1))
becomes
((a+p) <= b) && (a != 1) && (b >= p)) && ((b - (a + p) != 1)
For clarity, this is just replacing the (foo == 0 || foo > 1) pattern with foo != 1
That pattern appears twice above, once with foo = a, and once with foo = (b - (a+p))
Since the ints are unsigned, (a==0 || a>1) can be substituted for (a !=1).
With a first pass, you can reduce it to this:
uint sum = a + p;
return ((sum <= b) && (a != 1) && (b >= p)) && (b - sum != 1);
Also, it would be much more readable if you were able to give more meaningful names to the variables. For instance, if a and p were pressures, then a+p could be substitued as PressureSum.
s = a + p
b >= s && a != 1 && b - s - 1 > 0
Checked, returns the same boolean value as the question.
Program that I have used to check: (had fun writing it)
#include <iostream>
using namespace std;
typedef unsigned int uint;
bool condition(uint a, uint b, uint p)
{
uint s = a + p;
return uint( b >= s && a != 1 && b - s - 1 > 0 )
== uint( (((a+p) <= b) && (a == 0 || a > 1) && (b >= p))
&& ((b - (a + p) == 0) || (b - (a + p) > 1)) );
}
void main()
{
uint i = 0;
uint j = 0;
uint k = 0;
const uint max = 50;
for (uint i = 0; i <= max; ++i)
for (uint j = 0; j <= max; ++j)
for (uint k = 0; k <= max; ++k)
if (condition(i, j, k) == false)
{
cout << "Fails on a = " << i << ", b = " << j;
cout << ", p = " << k << endl;
int wait = 0;
cin >> wait;
}
}
bap = b - (a + p)
bap >= 0 && bap != 1 && a != 1
EDIT: Now I've got -2 for an honest attempt at helping out and also for what seems to me to be a valid answer. For you who can use Python, here are two functions, one with the question and one with my answer:
def question(a, b, p):
return (((a+p) <= b) and (a == 0 or a > 1) and (b >= p)) or ((b - (a + p) == 0) or (b - (a + p) > 1))
def answer(a, b, p):
bap = b - (a + p)
return bap >= 0 and bap != 1 and a != 1
Tested with a,b,p from 0 to 10000:
a != 1 && a != (b-p-1) && a <= (b-p);
I think it can be simplified even more.
This is as simple as I could get it.
def calc(a, b, p):
if (a != 1):
temp = a - b + p
if temp == 0 or temp < -1:
return True
return False
It could also be written as:
def calc(a, b, p):
temp = a - b + p
return a != 1 and (temp == 0 or temp < -1)
Or as:
def calc(a, b, p):
temp = a - b + p
return a != 1 and temp <= 0 and temp != -1
// In one line:
return (a != 1) && ((b-a-p == 0) || (b-a-p > 1))
// Expanded for the compiler:
if(a == 1)
return false;
int bap = b - a - p;
return (bap == 0) || (bap > 1);
If you post the processor you are using, I can optimize for assembly. =]
jjngy up here has it right. Here's a proof that his simplified formula is equivalent to the original using the Coq Proof Assistant.
Require Import Arith.
Require Import Omega.
Lemma eq : forall (a b p:nat),
(((a+p) <= b) /\ ((a = 0) \/ (a > 1)) /\ (b >= p)) /\
((b - (a + p) = 0) \/ (b - (a + p) > 1)) <->
((a + p <= b) /\ ~ (a= 1) /\ ~ (b - a - p = 1)).
Proof. intros; omega. Qed.
my apologies for the mistake in the original derivation. This is what happens when you don't bother to unit test after refactoring!
the corrected derivation follows, in the form of a test program.
The short answer is:
((a > 1) && (skeet == 0)) || ((a > 1) && (jon > 0) && (skeet < -1));
where
jon = (b - p)
skeet = (a - jon);
class Program
{
static void Main(string[] args)
{
bool ok = true;
for (int a = 1; a < 100; a++)
{
Console.Write(a.ToString());
Console.Write("...");
for (int b = 1; b < 100; b++)
{
for (int p = 1; p < 100; p++)
{
bool[] results = testFunctions(a, b, p);
if (!allSame(results))
{
Console.WriteLine(string.Format(
"Fails for {0},{1},{2}", a, b, p));
for (int i = 1; i <= results.Length; i++)
{
Console.WriteLine(i.ToString() + ": " +
results[i-1].ToString());
}
ok = false;
break;
}
}
if (!ok) { break; }
}
if (!ok) { break; }
}
if (ok) { Console.WriteLine("Success"); }
else { Console.WriteLine("Failed!"); }
Console.ReadKey();
}
public static bool allSame(bool[] vals)
{
bool firstValue = vals[0];
for (int i = 1; i < vals.Length; i++)
{
if (vals[i] != firstValue)
{
return false;
}
}
return true;
}
public static bool[] testFunctions(int a, int b, int p)
{
bool [] results = new bool[16];
//given: all values are positive integers
if (a<=0 || b<=0 || p<=0)
{
throw new Exception("All inputs must be positive integers!");
}
//[1] original expression
results[0] = (((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) &&
((b - (a + p) == 0) || (b - (a + p) > 1));
//[2] a==0 cannot be true since a is a positive integer
results[1] = (((a+p) <= b) && (a > 1) && (b >= p)) &&
((b - (a + p) == 0) || (b - (a + p) > 1));
//[3] rewrite (b >= p) && ((a+p) <= b)
results[2] = (b >= p) && (b >= (a+p)) && (a > 1) &&
((b - (a + p) == 0) || (b - (a + p) > 1));
//[4] since a is positive, (b>=p) guarantees (b>=(p+a)) so we
//can drop the latter term
results[3] = (b >= p) && (a > 1) &&
((b - (a + p) == 0) || (b - (a + p) > 1));
//[5] separate the two cases b>=p and b=p
results[4] = ((b==p) && (a > 1) && ((b - (a + p) == 0) ||
(b - (a + p) > 1))) || ((b > p) && (a > 1) &&
((b - (a + p) == 0) || (b - (a + p) > 1)));
//[6] rewrite the first case to eliminate p (since b=p
//in that case)
results[5] = ((b==p) && (a > 1) && ((-a == 0) ||
(-a > 1))) || ((b > p) && (a > 1) &&
(((b - a - p) == 0) || ((b - a - p) > 1)));
//[7] since a>0, neither (-a=0) nor (-a>1) can be true,
//so the case when b=p is always false
results[6] = (b > p) && (a > 1) && (((b - a - p) == 0) ||
((b - a - p) > 1));
//[8] rewrite (b>p) as ((b-p)>0) and reorder the subtractions
results[7] = ((b - p) > 0) && (a > 1) && (((b - p - a) == 0) ||
((b - p - a) > 1));
//[9] define (b - p) as N temporarily
int N = (b - p);
results[8] = (N > 0) && (a > 1) && (((N - a) == 0) || ((N - a) > 1));
//[10] rewrite the disjunction to isolate a
results[9] = (N > 0) && (a > 1) && ((a == N) || (a < (N - 1)));
//[11] expand the disjunction
results[10] = ((N > 0) && (a > 1) && (a == N)) ||
((N > 0) && (a > 1) && (a < (N - 1)));
//[12] since (a = N) in the first subexpression we can simplify to
results[11] = ((a == N) && (a > 1)) ||
((N > 0) && (a > 1) && (a < (N - 1)));
//[13] extract common term (a > 1) and replace N with (b - p)
results[12] = (a > 1) && ((a == (b - p)) ||
(((b - p) > 0) && (a < (b - p - 1))));
//[14] extract common term (a > 1) and replace N with (b - p)
results[13] = (a > 1) && (((a - b + p) == 0) ||
(((b - p) > 0) && ((a - b + p) < -1)));
//[15] replace redundant subterms with intermediate
//variables (to make Jon Skeet happy)
int jon = (b - p);
int skeet = (a - jon); //(a - b + p) = (a - (b - p))
results[14] = (a > 1) && ((skeet == 0) ||
((jon > 0) && (skeet < -1)));
//[16] rewrite in disjunctive normal form
results[15] = ((a > 1) && (skeet == 0)) ||
((a > 1) && (jon > 0) && (skeet < -1));
return results;
}
}
Well
((b - (a + p) == 0) || (b - (a + p) > 1))
Would be better writen as:
(b - (a + p) >= 0)
Applying this to the whole string you get:
((a+p) <= b) && (a > 1) && (b >= p)) && (b - (a + p) >= 0)
(a + p) <= b is the same thing as b - (a + p) >= 0
So you can get rid of that leaving:
((a+p) <= b) && (a > 1) && (b >= p))
I added this as a comment to nickf's answer but thought I'd offer it up as an answer on it's own. The good answers all seem to be a variation of his, including mine. But since we're not depending on the compiler for optimization (if the OP were, we wouldn't even be doing this) then boiling this down from 3 ANDs to the following means that there will be values where only 2 of the 3 portions will need to be evaluated. And if this is being done in a script, it would make a difference as opposed to compiled code.
(a != 1) && ((b > (a + p + 1)) || (b == (a + p))))
Based on a comment, I'm going to add this wrt this being better than the AND version:
I guess it depends on whether your true results data set is larger than 50 percent of the input sets. The more often the input is true, the better my variation will be. So, with this equation, it looks like the AND style will be better (at least for my input data set of 0-500).
If a, b and p are positive integers (assuming that the positive range include the 0 value) then the expression (((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1))
can be reduced to ((a+p)<=b) && (a!=1) && ((b-(a+p))!=1)
Let me demonstrate it:
In the first part of the expression there is a condition, ((a+p)<=b),
that if valuated true render true the second part:
((b - (a + p) == 0) || (b - (a + p) > 1)). If it is true that (b >=(a+p)) then (b - (a+p)) have to be greater or equal to 0, we need to assure that (b-(a+p))!=1.
Put this term aside for awhile and go on.
Now we can concentrate our efforts on the the first part
(((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b-(a+p))!=1)
If a is positive then it is always >=0 and so we can drop the test (a == 0 || a > 1) if favor of (a!=1) and reduce first part of the expression to (((a+p) <= b) && (b >= p) && (a!=1)).
For the next step of the reduction you can consider that if b >= (a+p) then, obviously b>=p (a is positive) and the expression can be reduced to
((a+p)<=b) && (a!=1) && ((b-(a+p))!=1)
how is about the following logic, please comment it:
((a == 0 || a > 1) && ((b-p) > 1) )
(((a+p) <= b) && (a == 0 || a > 1) &&
(b >= p)) && ((b - (a + p) == 0)
|| (b - (a + p) > 1))
1) (a == 0 || a > 1) is (a != 1)
2) (b >= p) is (b - p >= 0)
(a + p <= b) is (b - p >= a), which is stronger than (b - p >= 0).
First condition reduced to (a != 1) && (b - p >= a).
3) (b - (a + p) == 0) is (b - a - p == 0) is (b - p == a).
(b - (a + p) > 1) is (b - a - p > 1) is (b - p > 1 + a).
Since we had (b - p >= a) and we're using && operation, we may say that (b - p >= a) covers (b - p == a && b - p > 1 + a).
Hence, the whole condition will be reduced to
(a != 1 && (b - p >= a))
There's a tempation to reduce it further to (b >= p), but this reduction won't cover prohibition of b = p + 1, therefore (a != 1 && (b - p >= a)) is the condition.
This question has been pretty comfortably answered already in practice, but there is one point I mention below which I have not seen anyone else raise yet.
Since we were told to assume a >= 0, and the first condition assures that b - (a + p) >= 0, the bracketed || tests can be turned into tests against inequality with 1:
(a + p <= b) && (a != 1) && (b >= p) && (b - a - p != 1)
It is tempting to remove the check (b >= p), which would give nickf's expression. And this is almost certainly the correct practical solution. Unfortunately, we need to know more about the problem domain before being able to say if it is safe to do that.
For instance, if using C and 32-bit unsigned ints for the types of a, b, and p, consider the case where a = 2^31 + 7, p = 2^31 + 5, b = 13. We have a > 0, (a + p) = 12 < b, but b < p. (I'm using '^' to indicate exponentiation, not C bitwise xor.)
Probably your values will not approach the kind of ranges where this sort of overflow is an issue, but you should check this assumption. And if it turns out to be a possibility, add a comment with that expression explaining this so that some zealous future optimiser does not carelessly remove the (b >= p) test.
I feel (a != 1) && (a + p <= b) && (a + p != b - 1) is slightly more clear.
Another option is:
int t = b-p;
(a != 1 && a <= t && a != t-1)
Basically a is either 0, t, or lies between 2 and t-2 inclusive.
First iteration:
bool bool1 = ((a+p) <= b) && (a == 0 || a > 1) && (b >= p);
bool bool2 = (b - (a + p) == 0) || (b - (a + p) > 1);
return bool1 && bool2;
Second iteration:
int value1 = b - (a + p);
bool bool1 = (value1 >= 0) && (a == 0 || a > 1) && (b >= p);
bool bool2 = (value1 == 0) || (value1 > 1);
return bool1 && bool2;
Third iteration (all positives)
int value1 = b - (a + p);
bool bool1 = (value1 >= 0) && (a != 1) && (b >= p);
bool bool2 = (value1 == 0) || (value1 > 1);
return bool1 && bool2;
4th iteration (all positives)
int value2 = b - p;
int value1 = value2 - a;
bool bool1 = (value1 >= 0) && (a != 1) && (b - p >= 0);
bool bool2 = (value1 == 0) || (value1 > 1);
return bool1 && bool2;
5th iteration:
int value2 = b - p;
int value1 = value2 - a;
bool bool1 = (value1 >= 0) && (a != 1) && (value2 >= 0);
bool bool2 = (value1 == 0) || (value1 > 1);
return bool1 && bool2;
b >= (a+p) && a>=1
even b >= p is redundant as this will always be the case for a >= 1
Alright, I'm hoping that I did my math right here, but if I'm right, then this simplifies quite a bit. Granted it doesn't look the same in the end, but the core logic should be the same.
// Initial equation
(((a + p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1))
// ((a + p) <= b) iif a = 0 && p = b; therefore, b = p and a = 0 for this to work
(b == p) && ((b - (a + p) == 0) || (b - (a + p) > 1))
// Simplification, assuming that b = p and a = 0
(b == p) && (a == 0)
However, if we are operating under the assumption that zero is neither positive or negative then that implies that any value for a provided to the equation is going to be greater than or equal to one. This in turn means that the equation will always evaluate to false due to the fact that the following:
(a == 0 || a > 1)
Would only evaluate to true when a >= 2; however, if the following is also true:
(b >= p)
Then that means that p is at least equal to b, thus:
((a + p) <= b)
By substitution becomes:
((2 + b) <= b)
Which can clearly never evaluate to true.
a!=1 && ((b == a + p) || (b - p > a + 1))
(((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1))
since a >=0 (positive integers), the term (a == 0 || a > 1) is always true
if ((a+p) <= b) then (b >= p) is true when a,b,p are >=0
therefore ((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) reduces to
b>=(a+p)
(b - (a + p) == 0) || (b - (a + p) > 1) is equivalent to b>=(a+p)
therefore the whole equation reduces to
**b>= (a+p)**

Resources