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