CS52 - Spring 2016 - Class 6
Example code in this lecture
subtraction.sml
Lecture notes
admin
- assignment 2 due tomorrow at 5pm
- assignment 3 out soon
- you can start on some of the problems now, so start early
- one of the more challenging assignments
- due Monday 2/15 at 11:59pm
revisit subtraction in
subtraction.sml code
- key idea is a helper function that processes a digit at a time
- three parameters
- top list/number (l)
- bottom list/number (r)
- and a borrow bit, i.e. whether the column next to it had to borrow
- to calculate the answer
- take the top digit minus the bottom minus the borrow (which will either be 0 or 1)
- if that number is greater than or equal to 0, that's the digit
- recurse to the next digit WITHOUT borrowing
- if that number is less than or equals to 0, then we need to borrow
- add 10 to this column (because we borrowed)
- recurse to the next digit WITH a borrow
- what are the base cases?
- if one of the numbers is shorter than the other, just add zeros
- the 2nd and third base cases do this
- eventually we run out of numbers on both sides
- if we didn't have a borrow (i.e. b = 0) we're done
- what about if there is a borrow when we're out of digits?
- the answer is negative!
- what does adding ~b do?
- adds a [~1] to the end of the list
- what effect does that have?
a step back: number representation
- we're representing a number like 5,427 as the list [7,2,4,5]
- it's just another representation for the idea of the number "5,427"
decimal numbers
- most commonly used number systems have a "base"
- each digit in the number can range from 0...base-1
- each digit in the number has an index, starting at the right-most digit with 0 and working up to the left
- the contribution of the digit is:
base^index * value
- by summing up the contribution of all of the digits, we get the value of the number
- what is the base for our numbering system?
- 10
- for example
- 245 = 5*10^0 + 4*10^1 + 2*10^2
- 80498 = 8*10^0 + 9*10^1 + 4*10^2 + 0*10^3 + 8*10^4
other bases
- we can represent values by any base we'd like!
- A common one is CS, base 2, binary numbers:
- digits can only be a 0 or a 1
- for example, the following binary numbers:
- 101 = 1*2^0 + 0*2^2 + 1*2^2 = 5
- 11 = 1*2^0 + 1*2^1 = 3
- 10111 = 1*2^0 + 1*2^1 + 1*2^2 + 0*2^3 + 1*2^4 = 23
- 100001 = 1*2^0 + 1*2^5 = 33
- we can use any base we'd like, though
- base 9
- digits are numbers from 0 through 8
- 267 = 7*9^0 + 6*9^1 + 2*9^2 = 7 + 54 + 162 = 223
- base 200
- digits are numbers from 0 through 199
- 267 = 7*200^0 + 6*200^1 + 2*200^2 = 81,207
- not that even numbers written the same way can be interpreted differently!
- 2 55 167 = 167*200^0 + 55*200^2 + 2*200^2 = 91,167
back to our representation
- what does [7, 2, 4, 5] represent?
- depends on the base! :)
- in base 10?
- remember the least significant bits are lower
- 7*10^0 + 2*10^1 + 4*10^2 + 5*10^3 = 5,427
- in base 8?
- 7*8^0 + 2*8^1 + 4*8^2 + 5*8^3 = 2,839
back to the base case of subtraction
- what is 25-36?
- -11
- what will our algorithm do?
- [5,2] - [6,3]
- 1st digit: 9 with a borrow
- 2nd digit: 2-1-3 = 8 with a borrow
- 3rd digit: base case, -1
- answer: [9, 8, -1]
- what number is that?
- [9, 8, -1] = 9*10^0 + 8*10^1 + -1*10^2 = -11
- it still works!
- for now, we'll mostly be worrying about positive numbers, but we'll come back to this idea in a bit
swb
- how do we call swb if we want to subtract two numbers?
- specify a 0 for the borrow and then the two lists
- this isn't very satisfying, we really just want to subtract one list from the other
- fix?
- look at the subDigitList function in
subtraction.sml code
- just write another function that only takes two and calls swb
- since swb really is a helper function, we should "hide" it
- we could use let
- but there is another option
local
- used for information hiding (similar to let)
- key difference:
let
<definitions>
in
<expression>
end;
local
<definitions>
in
<definitions>
end;
- one implication of this is that you can have multiple functions in a "local" block that leverage a hidden function or value
- you're welcome to use either in your code, though in some situations it will be more natural to use one or the other.
- look at the second definition of subDigitList in
subtraction.sml code
addition
- very, very similar to subtraction
- for example:
7539
+672
----
- notice the recursion again here:
- to calculate an answer digit we need three things, the two digits and whether there was a carry from the previous iteration
- In our representation, the problem looks like
[9, 3, 5, 7]
+[2, 7, 9]
-------------
- and we're working from the front of the list down, but the idea is the same
multiplication
- take the example:
7539
*672
----
- proceeds in steps
- first, multiply 2 * 7539
7539
*672
----
15078
- second, multiply 7 * 7539 and shift a zero over (in essence, multiplying by 10)
7539
*672
----
15078
527730
------
- add these together
7539
*672
----
15078
527730
------
542808
- third, multiply 6 * 7539 and shift it over
7539
*672
----
15078
527730
------
542808
4523400
- add this to the previous total and we're done!
7539
*672
----
15078
527730
------
542808
4523400
-------
5066208
- how can we break this problem down? where is the recursion?
- multiply a digit from the lower number times the top number
- add the answer to this to the results of multiplying the rest of the digits shifted over (or multiplied by 10)
- in this example:
[9, 3, 5, 7]
*[2, 7, 6]
-------------
2 * [9, 3, 5, 7] + ...
- notice that as a subroutine, we need something that will multiply a digit times a number
math in other bases
- the algorithms for doing mathematical operations work the same in any base
- if adding digits and you exceed the *base*, then you carry
- when subtracting digits, if you need to borrow you borrow the value of the base NOT 10
- addition base 8
4351
+ 672
-----
- first digit
4351
+ 672
-----
3
- second digit
- 5+7 = 12, which results in a carry and 4 remaining because the base is 8!
- put another way, 14 base 8 = 1*8^1 + 4*8^0 = 12
4351
+ 672
-----
43
with a carry
- third digit
- 3+6+1 (for the carry) = 10, which results in a carry and 2 remaining
4351
+ 672
-----
243
with a carry
- fourth digit we just have to add the carry
4351
+ 672
-----
5243
- we can double-check our answer:
- 4351_8 = 4*8^3 + 6*8^2 + 5*8^1 + 1*8^0 = 2281
- 672_8 = 442
- 5243_8 = 2723 (which is 2281+442)
- subtraction base 6
421
minus 234
---------
- first digit
- 1-4 = -3 need to borrow
- because it's base 6 borrowing 1 from the one larger position results in 6 being added to the current position (instead of 10 in base 10)
- 1-4+6 = 3 with a borrow
421
minus 234
---------
3
with a borrow
- second digit
- 2-3-1(for the borrow) = -2, need to borrow
- 2-3-1+6 = 4 with a borrow
421
minus 234
---------
43
with a borrow
- third digit
- 4-2-1(for the borrow)
421
minus 234
---------
143
- we can double-check our answer:
- 421_7 = 157
- 234_7 = 94
- 143_7 = 63 (which is 157-94)
- multiplication
- same idea, but again, adjusted for the base (play with some examples!
Our own map
- What does this function do:
fun mystery f [] = []
| mystery f (x::xs) = (f x) :: (mystery f xs);
- It's the map function!
- Notice a few things:
- even though map is very powerful, it's very easy to write in SML
- functions are first order values so we can make them parameters (f above) and use them