File: binary_multiplication.mlw

package info (click to toggle)
why3 1.8.2-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 45,028 kB
  • sloc: xml: 185,443; ml: 111,224; ansic: 3,998; sh: 2,578; makefile: 2,568; java: 865; python: 720; javascript: 290; lisp: 205; pascal: 173
file content (69 lines) | stat: -rw-r--r-- 1,704 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

(** {1 Russian peasant multiplication}

   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.
*)

module BinaryMultiplication

  use mach.int.Int
  use ref.Ref

  let binary_mult (a b: int) : int
    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 }
      if !y % 2 = 1 then z := !z + !x;
      x := 2 * !x;
      y := !y / 2
    done;
    !z

end

(** 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