-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathexamples_arithmetic.mbt
More file actions
103 lines (97 loc) · 3.24 KB
/
Copy pathexamples_arithmetic.mbt
File metadata and controls
103 lines (97 loc) · 3.24 KB
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// ============================================================================
// Example C: Division with Remainder (repeated subtraction)
// ============================================================================
///|
/// Compute (q, r) for non-negative n and positive d.
#warnings("+missing_invariant+missing_reasoning")
fn div_mod_nonneg(n : Int, d : Int) -> (Int, Int) {
guard n >= 0 && d > 0 else { return (0, 0) }
for q = 0, r = n {
if r < d {
break (q, r)
} else {
continue q + 1, r - d
}
} where {
proof_invariant: n == q * d + r,
proof_reasoning: (
#|INVARIANT (division identity):
#|n == q * d + r holds with r as the remaining remainder.
#|MAINTENANCE:
#|Increment q and subtract d from r, preserving the identity.
#|TERMINATION:
#|When r < d, (q, r) is the quotient-remainder pair.
),
proof_invariant: r >= 0,
proof_reasoning: (
#|INVARIANT (non-negative remainder):
#|r starts at n and decreases by d; we stop before r would go negative.
#|MAINTENANCE:
#|The loop condition ensures r >= d before subtracting.
#|TERMINATION:
#|At exit, r is the non-negative remainder.
),
}
}
///|
test "div_mod_nonneg" {
@debug.assert_eq(div_mod_nonneg(10, 3), (3, 1))
@debug.assert_eq(div_mod_nonneg(25, 5), (5, 0))
@debug.assert_eq(div_mod_nonneg(0, 7), (0, 0))
}
// ============================================================================
// Example D: Horner's Method for Polynomial Evaluation
// ============================================================================
///|
/// Evaluate polynomial prefix of length end with Horner's scheme.
fn poly_prefix(coeffs : ArrayView[Int], end : Int, x : Int) -> Int {
if end <= 0 {
0
} else if end == 1 {
coeffs[0]
} else {
let prev = poly_prefix(coeffs, end - 1, x)
prev * x + coeffs[end - 1]
}
}
///|
/// Evaluate polynomial with coefficients in descending powers.
#warnings("+missing_invariant+missing_reasoning")
fn horner_eval(coeffs : ArrayView[Int], x : Int) -> Int {
guard coeffs.length() > 0 else { return 0 }
for i = 1, acc = coeffs[0] {
if i >= coeffs.length() {
break acc
} else {
let next = acc * x + coeffs[i]
continue i + 1, next
}
} where {
proof_invariant: 1 <= i && i <= coeffs.length(),
proof_reasoning: (
#|INVARIANT (progress):
#|i is the number of coefficients folded into acc, within [1..len].
#|MAINTENANCE:
#|Each step consumes coeffs[i] and increments i by 1.
#|TERMINATION:
#|At i = coeffs.length(), all coefficients are processed.
),
proof_invariant: acc == poly_prefix(coeffs, i, x),
proof_reasoning: (
#|INVARIANT (Horner):
#|acc equals the value of the polynomial prefix of length i at x.
#|MAINTENANCE:
#|If acc = P_prefix(i), then acc * x + coeffs[i] = P_prefix(i + 1).
#|TERMINATION:
#|At i == coeffs.length(), acc equals the full polynomial value.
),
}
}
///|
test "horner_eval" {
// 2x^2 - 3x + 5 at x=4 -> 25
@debug.assert_eq(horner_eval([2, -3, 5], 4), 25)
@debug.assert_eq(horner_eval([1], 10), 1)
@debug.assert_eq(horner_eval([3, 0, 0], 2), 12) // 3x^2
@debug.assert_eq(poly_prefix([2, -3, 5], 3, 4), 25)
}