2015-09-04 09:41:42 +02:00
|
|
|
|
2018-10-04 16:47:06 +02:00
|
|
|
(** {1 Russian peasant multiplication}
|
2016-06-02 17:00:43 +02:00
|
|
|
|
|
|
|
|
Multiply two integers a and b using only addition, multiplication by 2,
|
|
|
|
|
and division by 2.
|
|
|
|
|
|
|
|
|
|
Note: this is exactly the same algorithm as exponentiation by squaring
|
|
|
|
|
with power/*/1 being replaced by */+/0.
|
|
|
|
|
*)
|
|
|
|
|
|
2015-09-04 09:41:42 +02:00
|
|
|
module BinaryMultiplication
|
|
|
|
|
|
2018-06-15 16:45:31 +02:00
|
|
|
use mach.int.Int
|
|
|
|
|
use ref.Ref
|
2015-09-04 09:41:42 +02:00
|
|
|
|
2018-10-04 16:47:06 +02:00
|
|
|
let binary_mult (a b: int) : int
|
2015-09-04 09:41:42 +02:00
|
|
|
requires { b >= 0 }
|
|
|
|
|
ensures { result = a * b }
|
|
|
|
|
= let x = ref a in
|
|
|
|
|
let y = ref b in
|
|
|
|
|
let z = ref 0 in
|
|
|
|
|
while !y <> 0 do
|
|
|
|
|
invariant { 0 <= !y }
|
|
|
|
|
invariant { !z + !x * !y = a * b }
|
|
|
|
|
variant { !y }
|
2016-06-02 17:00:43 +02:00
|
|
|
if !y % 2 = 1 then z := !z + !x;
|
2015-09-04 09:41:42 +02:00
|
|
|
x := 2 * !x;
|
2017-02-03 08:44:38 +01:00
|
|
|
y := !y / 2
|
2015-09-04 09:41:42 +02:00
|
|
|
done;
|
|
|
|
|
!z
|
|
|
|
|
|
|
|
|
|
end
|
2018-10-04 16:47:06 +02:00
|
|
|
|
|
|
|
|
(** Now using machine integers.
|
|
|
|
|
|
|
|
|
|
Assuming that the product fits in machine integers, we can still
|
|
|
|
|
verify the code. The only exception is when `a*b = min_int`.
|
|
|
|
|
|
|
|
|
|
The code below makes no assumption on the sign of `b`.
|
|
|
|
|
Instead, it uses the fact that `!y % 2` has the sign of `!y`
|
|
|
|
|
so that `!x` is either added to or subtracted from the result.
|
|
|
|
|
*)
|
|
|
|
|
|
|
|
|
|
module BinaryMultiplication63
|
|
|
|
|
|
|
|
|
|
use int.Int
|
|
|
|
|
use int.Abs
|
|
|
|
|
use mach.int.Int63
|
|
|
|
|
use ref.Ref
|
|
|
|
|
|
|
|
|
|
let binary_mult (a b: int63) : int63
|
|
|
|
|
requires { min_int < a * b <= max_int }
|
|
|
|
|
ensures { result = a * b }
|
|
|
|
|
= let x = ref a in
|
|
|
|
|
let y = ref b in
|
|
|
|
|
let z = ref 0 in
|
|
|
|
|
while !y <> 0 do
|
|
|
|
|
invariant { if a*b >= 0 then !x * !y >= 0 && !z >= 0
|
|
|
|
|
else !x * !y <= 0 && !z <= 0 }
|
|
|
|
|
invariant { !z + !x * !y = a * b }
|
|
|
|
|
variant { abs !y }
|
|
|
|
|
z := !z + !x * (!y % 2);
|
|
|
|
|
y := !y / 2;
|
|
|
|
|
(* be careful not to make the very last multiplication *)
|
|
|
|
|
if !y <> 0 then x := 2 * !x
|
|
|
|
|
done;
|
|
|
|
|
!z
|
|
|
|
|
|
|
|
|
|
end
|