chriswarbo-net: bb77dbdc762b98fa59bf7d9cbebc397467637280
1: ---
2: title: Problems with Subtraction
3: packages: [ 'mathml' ]
4: ---
5:
6: <small>Part of [my units pages](/projects/units)</small>
7:
8: Subtraction is the operation of "taking away", and acts like the "opposite" of
9: addition. For example, we can use a subtraction to "undo" an addition:
10:
11: ```{.unwrap pipe="sh | math block minus"}
12: {
13: {
14: { var 'x'; var 'y'; } | add
15: var 'y'
16: } | mapply 'minus'
17: var 'x'
18: } | mapply 'eq'
19: ```
20:
21: This is a fine idea, but unfortunately subtraction is not as well-behaved as
22: addition, and I personally think it causes more problems than it solves.
23:
24: ## Subtraction is *redundant* ##
25:
26: We can define subtraction using addition and negation (using
27: [overbar notation for negatives](negative_bar_notation.html)):
28:
29: ```{.unwrap pipe="sh | math block"}
30: {
31: { var 'x'; var 'y'; } | mapply 'minus'
32: { var 'x'; var 'y' | neg; } | add
33: } | mapply 'equivalent'
34: ```
35:
36: ```{pipe="sh > neg_answer.mml"}
37: {
38: { num '5'; num '7'; } | mapply 'minus'
39: num '2' | neg
40: } | mapply 'eq'
41: ```
42:
43: Hence situations involving negatives don't need subtraction: we can stick to
44: additions, and sprinkle in some negatives as needed. Furthermore, if a situation
45: *doesn't* allow negatives, then it doesn't allow subtraction either, since
46: subtraction gives negative answers when the second value is larger than the
47: first (e.g. `cat neg_answer.mml`{.unwrap pipe="sh | math"}).
48:
49: So any time we might want subtraction, we could add negatives instead; and any
50: time we can't use negatives, we also can't use subtraction. Thus subtraction
51: isn't *needed*. We might find it *useful*, but it's ultimately just an
52: abbreviation for adding negatives.
53:
54: ### Adding negatives using negative digits ###
55:
56: We can use the familiar "long addition" algorithm to add negatives, if we think
57: of them as having [negative digits](negative_digits.html)!
58:
59: ## Subtraction is *hard* ##
60:
61: We've seen that subtraction is the same as adding negatives, but that doesn't
62: tell us whether one is "better" than the other. Now I'll show that adding is
63: preferable, since it follows many nice rules/patterns that subtraction doesn't;
64: hence making it easier to add negatives (both mentally, and on a computer)!
65:
66: ### Subtraction doesn't commute ###
67:
68: ```{pipe="sh > add_comm.mml"}
69: {
70: { var 'x'; var 'y'; } | add
71: { var 'y'; var 'x'; } | add
72: } | mapply 'eq'
73: ```
74:
75: ```{pipe="sh > not_comm.mml"}
76: {
77: { var 'x'; var 'y'; } | mapply 'minus'
78: { var 'y'; var 'x'; } | mapply 'minus'
79: } | mapply 'neq'
80: ```
81:
82: ```{pipe="sh > anti_comm.mml"}
83: {
84: { var 'x'; var 'y'; } | mapply 'minus'
85: { var 'y'; var 'x'; } | mapply 'minus' | neg
86: } | mapply 'eq'
87: ```
88:
89: We can swap around the values of an addition without changing the result: we say
90: addition *commutes*, i.e. that `cat add_comm.mml`{.unwrap pipe="sh | math"}.
91:
92: In contrast, we *can't* swap around the values of a subtraction, since
93: `cat not_comm.mml`{.unwrap pipe="sh | math"}. In fact, doing so will negate the
94: result: `cat anti_comm.mml`{.unwrap pipe="sh | math"} (we say that subtraction
95: "anti-commutes").
96:
97: ### Subtraction doesn't associate ###
98:
99: ```{pipe="cat > add_left.mml"}
100: <mrow>
101: <mrow>
102: <mo>(</mo>
103: <mi>x</mi>
104: <mo>+</mo>
105: <mi>y</mi>
106: <mo>)</mo>
107: </mrow>
108: <mo>+</mo>
109: <mi>z</mi>
110: </mrow>
111: ```
112:
113: ```{pipe="cat > add_right.mml"}
114: <mrow>
115: <mi>x</mi>
116: <mo>+</mo>
117: <mrow>
118: <mo>(</mo>
119: <mi>y</mi>
120: <mo>+</mo>
121: <mi>z</mi>
122: <mo>)</mo>
123: </mrow>
124: </mrow>
125: ```
126:
127: ```{pipe="sh > add_flat.mml"}
128: { var 'x'; var 'y'; var 'z'; } | add
129: ```
130:
131: Addition extends to arbitrarily-many inputs, which we call being "associative".
132: In particular, `cat add_left.mml`{.unwrap pipe="sh | math nosem"} is the same as
133: `cat add_right.mml`{.unwrap pipe="sh | math nosem"}, so we can just avoid
134: nesting altogether and write `cat add_flat.mml`{.unwrap pipe="sh | math"} (the
135: same goes when dealing with more than three inputs, nested in any way).
136:
137: ```{pipe="sh > sub_neq.mml"}
138: {
139: {
140: { var 'x'; var 'y'; } | mapply 'minus'
141: var 'z'
142: } | mapply 'minus'
143: {
144: var 'x'
145: { var 'y'; var 'z'; } | mapply 'minus'
146: } | mapply 'minus'
147: } | mapply 'neq'
148: ```
149:
150: ```{pipe="sh > sub_left_example.mml"}
151: {
152: {
153: { num '1'; num '2'; } | mapply 'minus'
154: num '3'
155: } | mapply 'minus'
156: {
157: num '1' | neg
158: num '3'
159: } | mapply 'minus'
160: num '4' | neg
161: } | mapply 'eq'
162: ```
163:
164: ```{pipe="sh > sub_right_example.mml"}
165: {
166: {
167: num '1'
168: { num '2'; num '3'; } | mapply 'minus'
169: } | mapply 'minus'
170: {
171: num '1'
172: num '1' | neg
173: } | mapply 'minus'
174: num '2'
175: } | mapply 'eq'
176: ```
177:
178: ```{pipe="cat > sub_flat_example.mml"}
179: <mrow>
180: <mn>1</mn>
181: <mo>-</mo>
182: <mn>2</mn>
183: <mo>-</mo>
184: <mn>3</mn>
185: </mrow>
186: ```
187:
188: In contrast, using subtraction with more than two values is ambiguous. For
189: example `cat sub_flat_example.mml`{.unwrap pipe="sh | math nosem"}
190: could mean `cat sub_left_example.mml`{.unwrap pipe="sh | math"} *or* it could
191: mean `cat sub_right_example.mml`{.unwrap pipe="sh | math"}, which give different
192: results. In general `cat sub_neq.mml`{.unwrap pipe="sh | math"}, so we're forced
193: to keep careful track of nesting when using subtraction.
194:
195: ```{pipe="sh > add_example_flat.mml"}
196: { var 'a'; var 'b'; var 'c'; var 'd'; var 'e'; var 'f'; } | add
197: ```
198:
199: ```{pipe="cat > add_example_nest.mml"}
200: <mrow>
201: <mrow>
202: <mo>(</mo><mi>a</mi><mo>+</mo><mi>b</mi><mo>)</mo>
203: </mrow>
204: <mo>+</mo>
205: <mrow>
206: <mo>(</mo><mi>c</mi><mo>+</mo><mi>d</mi><mo>)</mo>
207: </mrow>
208: <mo>+</mo>
209: <mrow>
210: <mo>(</mo><mi>e</mi><mo>+</mo><mi>f</mi><mo>)</mo>
211: </mrow>
212: </mrow>
213: ```
214:
215: Associative operations are also better for computers, since they're trivial to
216: calculate in parallel. For example, if we have three processors, we can
217: calculate `cat add_example_flat.mml`{.unwrap pipe="sh | math"} in parallel by
218: transforming it into `cat add_example_nest.mml`{.unwrap pipe="sh | math nosem"};
219: the result will always be identical, but the nested parts can be calculated
220: independently, and hence on separate processors at the same time. We cannot
221: perform such transformations for operations that *aren't* associative; hence
222: subtraction can't easily be done in parallel.
Generated by git2html.