Skip to content

Commit 58f2947

Browse files
committed
Use fewer multiplications
1 parent 48ad8b8 commit 58f2947

File tree

1 file changed

+112
-0
lines changed

1 file changed

+112
-0
lines changed

exercise_2.11.exs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
defmodule Interval do
2+
def make(lower, upper), do: [lower | upper]
3+
def lower(interval), do: hd interval
4+
def upper(interval), do: tl interval
5+
6+
def add(x, y), do: make(lower(x) + lower(y), upper(x) + upper(y))
7+
8+
def sub(x, y), do: make(lower(x) - upper(y), upper(x) - lower(y))
9+
10+
# L1 -, U1 -, L2 -, U2 - -> [U1 * U2, L1 * L2]
11+
# L1 -, U1 -, L2 -, U2 + -> [L1 * U2, U1 * L2]
12+
# L1 -, U1 -, L2 +, U2 + -> [L1 * U2, U1 * L2]
13+
14+
# L1 -, U1 +, L2 -, U2 - -> [U1 * L2, L1 * U2]
15+
# L1 -, U1 +, L2 -, U2 + -> [min(L1 * U2, U1 * L2), U1 * U2]
16+
# L1 -, U1 +, L2 +, U2 + -> [L1 * U2, U1 * U2]
17+
18+
# L1 +, U1 +, L2 -, U2 - -> [U1 * U2, L1 * U2]
19+
# L1 +, U1 +, L2 -, U2 + -> [U1 * L2, U1 * U2]
20+
# L1 +, U1 +, L2 +, U2 + -> [L1 * L2, U1 * U2]
21+
def mul(x, y) do
22+
lower = case { lower(x), upper(x), lower(y), upper(y) } do
23+
{a, b, c, d} when a < 0 and b < 0 and c < 0 and d < 0 -> b * d
24+
{a, b, c, d} when a >= 0 and b >= 0 and c >= 0 and d >= 0 -> a * c
25+
{a, b, c, d} when a < 0 and b >= 0 and c < 0 and d >= 0 -> Enum.min([a * d, b * c])
26+
{a, _, _, d} when a < 0 and d >= 0 -> a * d
27+
{_, b, c, _} when b >= 0 and c < 0 -> b * c
28+
end
29+
upper = case { lower(x), upper(x), lower(y), upper(y) } do
30+
{_, b, _, d} when b >= 0 and d >= 0 -> b * d
31+
{a, _, c, _} when a < 0 and c < 0 -> a * c
32+
{a, _, _, d} when a >= 0 and d < 0 -> a * d
33+
{_, b, c, _} when b < 0 and c >= 0 -> b * c
34+
end
35+
make(lower, upper)
36+
end
37+
38+
def alyssa_mul(x, y) do
39+
p1 = lower(x) * lower(y)
40+
p2 = lower(x) * upper(y)
41+
p3 = upper(x) * lower(y)
42+
p4 = upper(x) * upper(y)
43+
44+
make Enum.min([p1, p2, p3, p4]), Enum.max([p1, p2, p3, p4])
45+
end
46+
47+
def div(x, y) do
48+
if span_zero?(y) do
49+
raise ArithmeticError, message: "cannot divide by interval spanning zero"
50+
end
51+
mul(x, make(1 / upper(y), 1 / lower(y)))
52+
end
53+
54+
def span_zero?(interval), do: lower(interval) <= 0 && upper(interval) >= 0
55+
end
56+
57+
ExUnit.start
58+
59+
defmodule IntervalTests do
60+
use ExUnit.Case, async: true
61+
62+
test "it multiplies [-, -] * [-, -]" do
63+
neg_neg = Interval.make -10, -5
64+
assert Interval.mul(neg_neg, neg_neg) == Interval.alyssa_mul(neg_neg, neg_neg)
65+
end
66+
67+
test "it multiplies [-, -] * [-, +]" do
68+
neg_neg = Interval.make -10, -5
69+
neg_pos = Interval.make -5, 5
70+
assert Interval.mul(neg_neg, neg_pos) == Interval.alyssa_mul(neg_neg, neg_pos)
71+
end
72+
73+
test "it multiplies [-, -] * [+, +]" do
74+
neg_neg = Interval.make -10, -5
75+
pos_pos = Interval.make 5, 10
76+
assert Interval.mul(neg_neg, pos_pos) == Interval.alyssa_mul(neg_neg, pos_pos)
77+
end
78+
79+
test "it multiplies [-, +] * [-, -]" do
80+
neg_neg = Interval.make -10, -5
81+
neg_pos = Interval.make -5, 5
82+
assert Interval.mul(neg_pos, neg_neg) == Interval.alyssa_mul(neg_pos, neg_neg)
83+
end
84+
85+
test "it multiplies [-, +] * [-, +]" do
86+
neg_pos = Interval.make -5, 5
87+
assert Interval.mul(neg_pos, neg_pos) == Interval.alyssa_mul(neg_pos, neg_pos)
88+
end
89+
90+
test "it multiplies [-, +] * [+, +]" do
91+
neg_pos = Interval.make -5, 5
92+
pos_pos = Interval.make 5, 10
93+
assert Interval.mul(neg_pos, pos_pos) == Interval.alyssa_mul(neg_pos, pos_pos)
94+
end
95+
96+
test "it multiplies [+, +] * [-, -]" do
97+
neg_neg = Interval.make -10, -5
98+
pos_pos = Interval.make 5, 10
99+
assert Interval.mul(pos_pos, neg_neg) == Interval.alyssa_mul(pos_pos, neg_neg)
100+
end
101+
102+
test "it multiplies [+, +] * [-, +]" do
103+
neg_pos = Interval.make -5, 5
104+
pos_pos = Interval.make 5, 10
105+
assert Interval.mul(pos_pos, neg_pos) == Interval.alyssa_mul(pos_pos, neg_pos)
106+
end
107+
108+
test "it multiplies [+, +] * [+, +]" do
109+
pos_pos = Interval.make 5, 10
110+
assert Interval.mul(pos_pos, pos_pos) == Interval.alyssa_mul(pos_pos, pos_pos)
111+
end
112+
end

0 commit comments

Comments
 (0)