Comp210 Exam3 Solution
01.fall (v.4)

Name & Lab:

Honor pledge:
1.     /20
2.     /20
3.     /20
4.     /20
5.     /20
tot     /100

 

 

 

 

Directions and tips:

Jam 2000 Reference Sheet

Arithmetic Instructions

Encoding Assembly Meaning
? ? ? x y z 1 0 (add Rx Ry Rz) Rx <-- Ry + Rz
? ? ? x y z 2 0 (sub Rx Ry Rz) Rx <-- Ry - Rz
? ? ? x y z 3 0 (mul Rx Ry Rz) Rx <-- Ry * Rz
? ? ? x y z 4 0 (div Rx Ry Rz) Rx <-- Ry / Rz
? ? ? x y z 5 0 (mod Rx Ry Rz) Rx <-- Ry % Rz

Memory Load and Store Instructions

Encoding Assembly Meaning
±d7...d2 x 9 (ldi Rx ±d7...d2) Rx <-- ±d7...d2
? ? 1 ? y x 6 0 (ld Rx Ry) Rx <-- mem[Ry]
? ? 0 z y x 6 0 (ldx Rx Ry Rz) Rx <-- mem[Ry + Rz]
? ? 1 ? y x 7 0 (st Rx Ry) mem[Ry] <-- Rx
? ? 0 z y x 7 0 (stx Rx Ry Rz) mem[Ry + Rz] <-- Rx
? ? ? ? y x 9 0 (mov Rx Ry) Ry <-- Rx

Control Flow Instructions

Encoding Assembly Meaning
? ? ? ? ? x 8 0 (jmpx Rx) PC <-- Rx
d7...d2 ? 1 (jmpi d7...d2) PC <-- d7...d2
d7...d2 x 2 (jsr Rx d7...d2) Rx <-- PC; PC <-- d7...d2
d7...d2 x 3 (bez Rx d7...d2) PC <-- d7...d2, if (Rx = 0)
d7...d2 x 4 (bnez Rx d7...d2) PC <-- d7...d2, if (Rx != 0)
d7...d2 x 5 (blz Rx d7...d2) PC <-- d7...d2, if (Rx < 0)
d7...d2 x 6 (blez Rx d7...d2) PC <-- d7...d2, if (Rx <= 0)
d7...d2 x 7 (bgz Rx d7...d2) PC <-- d7...d2, if (Rx > 0)
d7...d2 x 8 (bgez Rx d7...d2) PC <-- d7...d2, if (Rx >= 0)

 

p. ii

  1. (20pts) In lecture we wrote (some variations on) for-loops -- a way to distinguish code which is the loop's body from code which repeats that body a specified number of times. This problem considers a slightly different looping-construct, a while-loop. Some previous class examples where a while-loop would have been handy are:
    • trick-or-treat: "start with an empty bag of candy;
      while [it doesn't have 30 yummy candies], [visit-house]"
    • hilo: "start with the range [0,MAX);
      while [the range includes > 1 number], [split range into the appropriate half]"
    • mergesort (bottomup): "start with a list-of-(list-of-one-number);
      while [the list contains more than one list], [merge-all-pairs of the list]"
    Here is a more detailed example:
    ;; threes: natNum --> 1, or never finish?
    ;; No guarantee of termination.
    ;;
    (define (threes n)
      (cond [(<= n 1) n]
            [else (threes (if (even? n)
                              (/ n 2)
                              (+ (* 3 n) 1)))]))
    
    ; This function could be re-written in a form which separates
    ; the looping from the individual computation:
    ;
    (define (threes n)
      (while (lambda (m) (> m 1))
             (lambda (m) (if (even? m)  (/ m 2)  (+ (* 3 m) 1)))
             n))
    
    1. Write the function while. (Give one additional test case, more trivial than the previous example or 1b.)
      ;; while:  (alpha --> boolean), (alpha --> alpha), alpha --> alpha
      ;; Repeatedly call body;
      ;; Stop the moment (continue? init) is false.
      ;; That is, we call (body init), then (body (body init)), then ...
      ;; It's possible that body is called 0 times, if (continue? init) isn't true.
      ;;
      (define (while continue? body init)
        (cond [(not (continue? init)) init]
              [else (while continue? body (body init))]))
      
      
      ; A trivial example, that never even gets started:
      (while (lambda (z) false)
             (lambda (y) (error 'uh-oh "We should never get here"))
             17)
      = 17
      
    2. Use your while-loop to find the largest inexact number possible (within a factor of two): Start with the inexact number #i1.0; while [doubling-then-halving gives back the same number], [double it]. (As seen in an optional lab, inexact numbers will eventually overflow.) You can alternately start with pi or (sqrt 2) instead of #i1.0; these are also stored as inexact numbers -- scientific notation with ~20 significant figures, and exponent in (-320,+320] or so.
      (define accuracy (add1 1.0)) ; Within 100%.  Set to 0.50 to be within 50%.
                                   ; Except -- if accuracy isn't a whole number,
                                   ; we'll detect x != 2x/2 because of round-off error,
                                   ; before overflow kicks in.
                                   ; (Update the while loop to check "nearly="?)
      
      (while (lambda (x) (= x (/ (* x accuracy) accuracy)))
             (lambda (x) (* accuracy x))
             #i1.0)
      =  +8.988..e+307 ; A large number, approx 1e308.
      
  2. p. 1

  3. (20pts) For every actor, a website can provide us with a list of all the other actors they've co-starred with. Somehow, it is a mark of pride for an actor to have co-starred with Kevin Bacon ("to have KB# of 1"). Almost as prestigious is having co-starred with somebody who has co-starred with Kevin Bacon ("to have a KB# of 2"). (Kevin Bacon himself has a KB# of 0.) In general, an actor's KB# is n if they co-starred with some actor with a KB# of n-1 (and they've not co-starred with somebody with a smaller KB#).

    For example,
    Kevin Bacon was in 24 Hours (2001) with Charlize Theron.
    Charlize Theron was in The Devil's Advocate (1997) with Al Pacino
    Thus, Charlize Theron has a KB# of 1, while Al Pacino has a KB# of 2. Note that Matt Dillon has co-starred with Al Pacino (Madonna: Truth or Dare, 1991), but that doesn't make his KB# 3: because Matt has also starred with somebody with a smaller KB#: in this case, Mr. Bacon himself (Wild Things, 1998).

    We work towards a function which computes the KB# of each actor.
    1. Examples of the data: Provide a Scheme representation for an actor's name and co-stars. (The KB number is the next problem.) You need only include co-stars mentioned here; not the particular movies. You may use a couple of statements per actor, if needed. (Use back of prev. page. You can do this problem together with the next one, if you like.)
      ; An actor is:
      ;   (make-actor [string] [list-of-actors])
      ;
      (define-struct actor (name costars))
      
      (define ct (make-actor "charlize theron" empty))
      (define md (make-actor "matt-dillon"     empty))
      (define ap (make-actor "al pacino"       empty))
      (define kb (make-actor "kevin bacon"     empty))
      
      (set-actor-costars! ct (list kb ap))
      (set-actor-costars! md (list kb ap))
      (set-actor-costars! ap (list md ct))
      (set-actor-costars! kb (list ct md))
      
    2. Reminiscent of the airline-path-finding problem where we progressively marked cities as seen, include a field for each actor with their KB#, which we will fill-in with the correct KB value later. What might this value be initially, before we have computed the actual value? (What one actor is an exception to this?) (You can do this problem together with the previous one, if you like.)

      Add to each structure a field kb#, which is either a number or the sentinel value kb#-unknown.
      ; An actor is:
      ;   (make-actor [string] [list-of-actors] [number-or-kb#unknown])
      ; where kb# is either a kevin-bacon number, or kb#-unknown if not yet computed.
      (define-struct actor (name costars kb#))
      
      ; Sentinel value:
      (define kb#-unknown 'infinity)
      
      ;; kb#-unknown?: kb# --> boolean
      (define kb#-unknown? symbol?)
        ; Notice how this function lets us easily change
        ; our concept of unknown later on -- perhaps
        ; there could be several separate sentinels, all meaning
        ; unknown (but also conveying other nuances for other purposes).
      
      ;; create-actor: a wrapper around make-actor, for convenience.
      ;;
      (define (create-actor name) (make-actor name empty kb#-unknown))
      ;
      ; Note: Must set Mr. Bacon's kb# seperately.
      
      (define ct (create-actor "charlize theron"))
      (define md (create-actor "matt-dillon"))
      (define ap (create-actor "al pacino"))
      (define kb (create-actor "kevin bacon"))
      
      (set-actor-costars! ct (list kb ap))
      (set-actor-costars! md (list kb ap))
      (set-actor-costars! ap (list md ct))
      (set-actor-costars! kb (list ct md))
      
      ; Special:
      (set-actor-kb#! kb 0)
      
    3. Reminiscent of missionaries and cannibals, write a function one-step-more that, if given a list of actors with some KB# k (say, 3), would return a list of actors with KB# k+1 (4), and no less. (Compare to: taking a list of states reachable in (say) 3 boat-trips, and returning the list of states reachable in 4.) It can modify these structures with their newly-discovered KB#. You can use map-append, provided. Write a second function/expression to repeatedly call this one, to compute everybody's KB#. (To think about: when is this second function done?)

      (You may use a looping construct if you like, though you don't have to; for this exam (only), it's acceptable to blend together the code which handles the looping, with the code which computes KB#.)

      ;; map-append: (alpha --> list-of-beta), list-of-alpha --> list-of-beta.
      ;; Like map, but the individual results are lists, so append them all.
      ;;
      (define (map-append f lst)
        (cond [(empty? lst) empty]
              [(cons?  lst) (append (f (first lst)) (map-append f (rest lst)))]))
        ;
        ; NB Or, "(foldr (lambda (frst rr) (append (f frst) rr)) empty lst))"
      
      We solve this problem by starting at kevin bacon, finding all his co-stars, and give them a kb# of 1. Then, find all the co-stars of those actors, and give them kb# of 2 (except that we first remove all those who already had a kb# -- it must have been a smaller kb#.) This is an easy map actor-costars onto the list (well, upon a bit of reflection, some sort of map-append), followed by filtering in those with a still-uknown kb#. Repeat.
      Note that any actor who is never seen by the function is not related in any way to Kevin Bacon; their KB# is effectively infinity. This includes Ian, star of the epic 1968 home movie A Time to Drool. (Thus using 0 as a sentinel kb# is a poor choice -- actors not seen by the function will get confused with Mr. Bacon.)
      ;; increase-kb#!: list-of-actors --> list-of-actors.
      ;; Takes in a list of actors with the same kb# (call it k),
      ;; and returns a list of those who've co-starred with any in "actors",
      ;; with their kb# set to k+1.
      ;; Side-effect: set the kb# of some actors as mentioned.
      ;;
      (define (increase-kb#! actors)
        (cond [(empty? actors) empty]
              [else (local [(define k (actor-kb# (first actors)))]
                       (map (lambda (act) (begin (set-actor-kb#! act (add1 k)) act))
                            (filter (lambda (act) (kb#-unknown? (actor-kb# act)))
                                    (map-append actor-costars actors))))]))
      
      ; Tests: (Comment out before testing the main function though -- side-effected!)
      ;(increase-kb#! (list kb))    = (list ct md) ; These are now tagged with kb# 1.
      ;(increase-kb#! (list ct md)) = (list ap)    ; Note that kb, md filtered out.
      ;(increase-kb#! (list ap))    = empty        ; All ap's costars already have kb#.
      
      
      ; Now, repeatedly call increase-kb#! until it's empty,
      ; starting from (just) kb.
      ;
      (while cons? increase-kb#! (list kb)) = empty
      
      ; Check results:
      (actor-kb# kb) = 0
      (actor-kb# md) = 1
      (actor-kb# ct) = 1
      (actor-kb# ap) = 2
      
      Here is another version which keeps track of k, rather than always re-computing it. (To use this, we need to retreat from using while, since having the loop value be a list-of-two-items would work but starts to become cumbersome.)
      ;; increase-kb#!: list-of-actors, number --> list-of-actors.
      ;; Takes in a list of actors with kb# k,
      ;; and returns a list of those who've co-starred with any in "actors",
      ;; with their kb# set to k+1.
      ;; Side-effect: set the kb# of some actors as mentioned.
      ;;
      (define (increase-kb#! k actors)
        (map (lambda (act) (begin (set-actor-kb#! act (add1 k)) act))
             (filter (lambda (act) (kb#-unknown? (actor-kb# act)))
                     (map-append actor-costars actors))))
      
      ; Tests: (comment out before testing the main function though -- side-effected!)
      ;(increase-kb#! 0 (list kb))    = (list ct md) ; These are now tagged with kb# 1.
      ;(increase-kb#! 1 (list ct md)) = (list ap)    ; kb#2.  Note that kb, md removed.
      ;(increase-kb#! 2 (list ap))    = empty        ; ap's costars already have kb#.
      
      ;; solve-kb!: list-of-actors, natnum --> (void)
      ;; Repeatedly call increase-kb#! with increasing k.
      ;; Stop when there aren't any unseen actors left.
      ;;
      ;; This corresponds to the while-loop, in the previous version.
      ;;
      (define (solve-kb! actors k)
        (if (empty? actors)
            (void)
            (solve-kb (increase-kb#! k actors) (add1 k))))
      
      ; Get the whole thing going:
      (solve-kb! (list kb) 0)
      ; Check results:
      (actor-kb# kb) = 0
      (actor-kb# md) = 1
      (actor-kb# ct) = 1
      (actor-kb# ap) = 2
      
  4. p. 2

  5. (20pts) For this problem, you may use a looping construct if you like, though you don't have to; for this exam, it's acceptable to blend together the code which walks to the end of the first list, with the code which changes the list.

    ; Use the more sensible names:      ; For exam purposes only, allow short names:
    (define set-cons-first! set-car!)   (define scf! set-cons-first!)
    (define set-cons-rest!  set-cdr!)   (define scr! set-cons-rest!)
    

    1. Write the destructive function append!, which takes in two lists a and b, and it modifies a so that it contains all the elements of both lists. In particular, it changes a's last cons structure so that it refers to b. (You can have any return value you like for this function, though scheme's real append! returns the (newly modified) a.) a is guaranteed to be non-empty. (How does this effect the contract?) We have seen many examples of a function modifying the contents of a structure.
      ;; length1?: list --> boolean.
      ;; Does l contain exactly one item?
      ;;
      (define (length1? l)  (and (cons? l) (empty? (rest l))))
      
      (length1? empty) = false
      (length1? (list 'hi)) = true
      (length1? (list 'hi 'bye)) = false
      
      
      ;; append!: cons, list --> list
      ;; Side-effect: modify a's content so that it includes b.
      ;;
      ;; Implementation: recur down a until a's last cons cell,
      ;; then set it's "rest" field to be b, rather than empty.
      ;;
      
      (define (append! a b)
         (cond [(length1? a) (set-cons-rest! a b)]
               [else         (append! (rest a) b)]))]
         ; Alternately, a one-liner:
         ; (set-cons-rest! (while (compose not length1?) rest a)) b)
      
      
      (define x (list 'hi 'bye))
      (append! x empty) = (list 'hi 'bye)
      x = (list 'hi 'bye)
      ; Further tests in next part.
      
      A note on the contract: If you tried to use alpha as a type variable, the you'd want:
      ;; append!: (cons alpha list-of-alpha), list-of-alpha --> list-of-alpha
      
      Though note that it's not quite correct to assert that everything in the list is all the same type -- the lists could be "heterogenous", so that substituting "alpha" with "number" wouldn't work, nor would any other single value for "alpha".
    2. (define uno (list 'blue 'aqua))
      (define dos (list 'teal 'azure))
      
      (append! uno dos)
      ; Draw a picture of what things look like right now,
      ; including what uno and dos refer to.
      
      
      
      ; For exam soln set only, we'll stress how cons cells are structures:
      (define make-cons cons)
      
      
      (define bluey^   (make-cons 'blue  aqueous^))
      (define aqueous^ (make-cons 'aqua  tealy^))
      
      (define tealy^   (make-cons 'teal  azul^))
      (define azul^    (make-cons 'azure empty))
      
      (define dos tealy^)
      (define uno bluey^)
      ; Note that the third cons cell of uno
      ; and the first cons cell of dos 
      ; are the same identical cons cell.
      ; That is:  (eq?  dos  (rest (rest uno)))
      
      
      (append! uno dos)    ; A second time.
      ; Draw a picture of what things look like right now
      ; including what uno and dos refer to.
      ; (Careful, it may not be quite what you first thought!)
      
      
      
      (define bluey^   (make-cons 'blue  aqueous^))
      (define aqueous^ (make-cons 'aqua  tealy^))
      
      (define tealy^   (make-cond 'teal  azul^))
      (define azul^    (make-cons 'azure tealy^))
      
      (define dos tealy^)
      (define uno bluey^)
      ;
      ; Note that we now have circular lists:  (eq?  dos  (rest (rest dos)))
      
      
      
  6. p. 3

  7. (20pts) You are P, the chief engineer at Mission Imperceptible headquarters. Mission Imperceptible agents are briefed about each new mission by listening to a CD with their mission statement. After playing the message up to 2 times, the CD will (call) self-destruct!. (Some of the agents are a bit slow, and need a second listening.)

    Each CD has a unique serial-number: the first CD you create at headquarters has the number 1, the next has the number 2, etc.

    You have decided to implement a CD as a function (of no arguments): the first two times the function is called, the message is returned; if further called, the CD will call self-destruct! (a function with zero arguments) and just return its serial number. (Presume self-destruct! has already been provided -- you don't need to write it, just call it.)

    You shall write two functions,

    To maintain secrecy, once you have written these functions, nobody should be able to set! any other placeholder to subvert either of your functions.
    Hint: If you want to return two values from a local, you return a list of those values, and then attach names to them outside the local:
    (define two-funcs (local [(define (f ..) ...)
                              (define (g ..) ...)
                              (define (h ..) ...)]
                        (list f g)))   ; Export only two functions from the local.
    
    (define my-func1 (first  two-funcs))
    (define my-func2 (second two-funcs))
    

    1. After reading the descriptions of these functions below, first write some test cases, illustrating their use.
      (CDs-issued) = 0
      (define mission1 (CD-maker "take candy from baby"))
      mission1   ; = (lambda () ...)
      (CDs-issued) = 1
      (define mission2 (CD-maker "stir martini"))
      (mission1) = "take candy from baby"
      (mission1) = "take candy from baby"
      (mission1) = 1
      (mission1) = 1
      (mission2) = "stir martini"
      (mission2) = "stir martini"
      (mission2) = 2
      (mission1) = 1
      (mission2) = 2
      (CDs-issued) = 2
      (CDs-issued) = 2
      (CDs-issued) = 2
      
    2. p. 4

    3. Write the the functions CD-maker, CDs-issued.
      ; Assumed Provided (not required for you to write):
      ;; self-destruct!: --> (void)
      ;; side-effect: print a message of destruction and carnage.
      ;;
      (define (self-destruct!) (printf "  (boom)  "))
      
      ; Data definitions:
      ;; A message is a string.
      ;; A CD is a function: ( --> message-or-number)
      
      (define both-functions
        (local
           [(define TOO_LATE 2)          ; Number of calls before self-destructing.
            (define num-made 0)          ; CDs made so far
            
      
            ;; CDs-made: --> number
            ;;
            (define (CDs-made) num-made) ; Easy.
      
            ;; CDs-made: string --> CD
            ;;
            (define (CD-maker msg)
              (begin
                (set! num-made (add1 num-made))   ; Increment count.
                (local [(define calls-so-far 0)   ; Make variables local for this CD:
                        (define my-id# num-made)]
                  (lambda ()                      ; Now make the actual CD.
                     (begin (set! calls-so-far (add1 calls-so-far))
                            (if (<= calls-so-far TOO_LATE)
                                msg
                                (begin (self-destruct!)
                                       my-id#))))))))]
           (list CDs-made CD-maker)))
      (define CDs-issued (first   both-functions))
      (define CD-maker   (second  both-functions))
      

      If you don't want to have a local which returns a list of two functions which you then globally name, you can also use the approach used in one of the homeworks: having a password object take in one of two messages 'play-message or 'CDs-issued.

      If you wanted to implement CDs as structures, that'd be okay, but how would you prevent a user from just calling (CD-message some-cd) as many times as they like, bypassing any security mechanisms? You would have to make the define-struct hidden inside some local; this leaves the user with a structure they can't do anything with. You'd provide another function play (defined inside that same local), which could be used.

    4. Of course, if it is suddenly decided to change the allowed number of listenings from 2 to (say) 3, this should only require changing a single define in your code.

      1. If, somehow, you could set! the allowed number of listenings in DrScheme's interactions window (the lower one -- without pressing "Execute"), would it affect previously-made CDs, carried by agents currently in the field? (Yes or No).
        (Both answers are easily possible, depending on your code.) No.
      2. Succinctly: How would modify your code, to get the other answer? Move the (define TOO_LATE ..) to the local just inside CD-maker, so that every CD had its own version of TOO_LATE (just as they have their own version of my-id#).

    You don't need to worry about this, but: HQ will have to be careful to make sure we always call the actual functions written here, even if some double agent set!s our function names.

  8. p. 5

  9. (20 pts) Assembly language:
    Consider the following program. (It happens to compute the greatest common divisor of two numbers, using an algorithm known by Euclid, though you don't need to know that for this problem.)
    ;; gcd: natnum, natnum --> natnum
    ;; Given two numbers, return their greatest common divisor.
    ;; We must have bigger >= smaller, to work.
    ;;
    ;; Argument of termination (you don't need to repeat this):
    ;; every time this function is called, smaller decreases
    ;; by at least one, and we stop when it reaches 0, so termination 
    ;; guaranteed in at most smaller steps.
    
    
    ;;
    ;; For mathematicians (difficult): prove this algorithm actualy terminates 
    ;; much more quickly than the previous argument suggests.
    ;; Hint: how much do the arguments decrease over two consecutive calls?
    
    
    ;;
    (define (gcd bigger smaller)
      (if (zero? smaller)
          bigger
          (gcd smaller (remainder bigger smaller))))
    
    ; Tests -- you don't need to repeat:
    (gcd 5 0)  = 5
    (gcd 5 1)  = 1
    (gcd 5 4)  = 1
    (gcd 4 2)  = 2
    (gcd 12 8) = 4
    (gcd 2515 814) = 1
    (gcd 2516 814) = 74   ;  814 = 74*11;    2516=74*34.
    Notice how the second argument (smaller)
    is used as the first argument of the recursive call.
    
    
    

    (In real life we'd write a user-friendly version where the arguments could be in either order; that wrapper would just call this as a helper, providing the bigger number as the first argument.)

    1. Rewrite this function in Scheme, in an imperative fashion (i.e. your function takes no arguments, it uses set!, it expects the input values to be in the variables bigger and smaller, and it stores the output in a variable named gcd-result).
      (define bigger 2516)  ; These "inputs" must be changed for each test-case.
      (define smaller 814)
      (define gcd-result 'not-yet-computed)   ; Our function will set! this.
      
      (define tmp 'swap-space)  ;; A temporary variable.
      
      ;; do-gcd!: --> (void)
      ;; 
      ;; As gcd, but it modifies smaller, bigger, gcd-result, and tmp.
      ;;
      (define (do-gcd!)
        (if (zero? smaller)
            (set! gcd-result bigger)
            (begin (set! tmp smaller)
                   (set! smaller (remainder bigger smaller))
                   (set! bigger tmp)
                   (do-gcd!))))
      
      (do-gcd!) ; Run the program.
      gcd-result = 74
      
      ; Running the program again with bigger set to be 2515 yields 1.
      (set! bigger 2515)
      (set! smaller 814)
      (do-gcd!)
      gcd-result = 1
      
    2. Rewrite your imperative version in Jam2000 assembly code. (The Jam2000 reference sheet is attached near front page.) You specify where bigger, smaller, gcd-result and your program are located in main-memory. (The user will make sure those memory locations contain the inputs, when they execute your assembly code.) Be sure to provide comments, showing the relation between your Jam2000 code and the imperative function whence it derived.
      Note that the "%" (see Jam's mod) is the same as Scheme's remainder.

      ; Program will inhabit addresses 50 through 61.
      
      ; We'll have smaller in R0 and at address 100
      ;            bigger  in R1 and at address 101
      ;            tmp     in R8               
      ; and        gcd-result        at address 102.
      ; 
      (ldi  R0 100)   ; mem[50]  ; R0 <-- address of smaller
      (ld   R0 R0)    ; mem[51]  ; R0 <-- smaller
      (ldi  R1 101)   ; mem[52]  ; R1 <-- address of bigger
      (ld   R1 R1)    ; mem[53]  ; R1 <-- bigger
                      ; do-gcd:
      (bez  R0 59)    ; mem[54]  ; (if (zero? smaller) branch to store-result. Else..
      (mov  R8 R0)    ; mem[55]  ;   (set! tmp smaller)
      (mod  R0 R1 R0) ; mem[56]  ;   (set! smaller (remainder bigger smaller))
      (mov  R1 R8)    ; mem[57]  ;   (set! bigger tmp)
      (jmpi 54)       ; mem[58]  ;   (do-gcd)
                      ; store-result:
      (ldi  R2 102)   ; mem[59]  ; R2 <-- address of gcd-result
      (st   R2 R1)    ; mem[60]  ; (set! gcd-result bigger)
      (halt)          ; mem[61]
      
      Using gcd-result as your temporary variable is acceptable: a low-level hack that doesn't quite reflect your thinking, but that's exactly what low-level langauges don't help with.
  10. p. 6