C.B.Price 2/12/2016 Draft 3 1 Register Machines are Turing Machines are Register Machines While the Turing Machine captures the fundamental essence of computation, it does not “look like” the register based machines which sit upon our desks. Here we demonstrate that the operation of a Turing machine is equivalent to a register-based machine like those CISC and RISC machines we discussed in the first session. So I say to you “If it runs on a Turing Machine, then it will run on a Pentium. But also, if it runs on a Pentium, it will run on a Turing Machine” During our demonstration, we will discover the smallest number of programming language “constructs” required to produce any computer programme! This session was both backwards looking and forwards looking. Starting with the central notion of the Turing Machine, we looked back to the register-based CISC and RISC machines we discussed in the first session. We also look forward to the next session where we will explore some unusual languages (and I don’t mean C, C++ or Java). So let’s start the story. This is illustrated in the diagram below, where we wish to replace the Turing Machine (it’s tape and read-write head, and its “programme” expressed as a table which moves from state S1 to S2) with a bunch or registers and an ALU. The registers hold numbers and the ALU does arithmetic operations such as add, multiply divide. Here’s the situation: m s n (a) m s ALU n (b) z In (a) we have the Turing Machine and in (b) we have the register machine. We work like this. Let’s divide the Turing tape into three sections, the left part m, the right part n and a middle part s. Think, to keep it fairly simple, as the symbols on the tape as either 0’s or 1’s. In that case, we can think of m ,n, and s as binary numbers, and binary numbers can be integers (1, 2, 5, 10, 456). So m represents the left part of the tape as a number which we can put into register m, n represents the right part of the tape as a number which we can put into register n, and s is the current symbol which we are reading and writing which we can put into register s. Register z is just an additional ‘help’ register. That’s fine, so what does the ALU do? Good question. Remember that the Turing Machine started in some state, read a symbol, wrote a symbol, shifted left or right and entered a new state. So that’s what we must do. The first thing is the shifting left or right. This must be “simulated” by the register machine (whose ALU can do things like add, subtract, multiply and divide). C.B.Price 2/12/2016 Draft 3 2 There are also some more fundamental questions which we must ask. How many registers do we need to simulate a Turing Machine, and how many ALU instructions do we need? We shall see. 1. The Register-Machine equivalent of Moving the Read/Write head to the Right. What follows here is not a cast-iron proof. That’s beyond our grasp. It’s a demonstration which proceeds by examples, but which I believe stands up quite well. Its limitation is that the symbols on the tape are restricted to 0’s and 1’s, since this simplifies the discussion a lot. The full proof is given in section 4 (careful going there!). Before we begin, let’s just revisit some facts concerning binary numbers and shifting them. Here is a classic example of a binary number being shifted to the left. Let’s have a think: 8 4 2 1 8 4 2 1 0 1 1 1 1 1 1 0 On the left, we have our starting number in binary with the value 0*8 + 1*4 + 1*2 + 1*1 = 7. A shift to the left gives us 1*8 + 1*4 + 1*2 + 0*1 = 14 (right-most diagram). So a shift to the left is equivalent to multiplying the number by 2. This arrangement of bits is the “normal” or “classical” arrangement, where the value of the bits gets greater (by a factor of 2) as we move to the left. But in our current thinking, we need to consider the “mirror” arrangement of bits, where the value of bits gets greater (by a factor of 2) as we move to the right. Trust me! Let’s look at this “mirror” situation, below. On the left we have a binary number with decimal value 7. Then we shift it to the left. The resulting whole part of the number is 3 and the remainder is one. Shifting left is dividing by 2, so 7/2 = 3 rem1. 1 2 4 8 1 0 1 1 1 rem 1 2 4 8 1 0 1 0 whole OK, now let’s take a couple of examples of a real Turing Machine Tape, and move the read/write head one place to the right. We can describe the situation of the tape using three numbers, m,s,n. as shown below. The number m is the number on the tape to the left of the cell we are looking at. The number n is the number on the tape to the right of the cell we are looking at. The number s is the value in the cell the read/write head is looking at (0 or 1). Here’s an example of a Turing Machine at a particular moment. C.B.Price 2/12/2016 Draft 3 8 4 2 1 3 1 2 4 8 0 1 1 0 1 1 1 0 m n s Remember, the Turing machine, at any time, is in a particular state, and it reads a symbol s from the tape and writes a new symbol to the tape, and moves left or right on the tape, and enters a new state. In the above diagram we capture the Turing Machine in her current state. We read the symbol s (0 or 1); here it is 0. Also we capture the data to the left of the “arrow” as the number m, and the data to the right, as the number “n”. So what happens when the “arrow” moves to the right? There are two possibilities, depending on whether s = 0 or s = 1. Let’s explore these. The case for s = 0. Here’s the starting state for the first example. Note the symmetrical arrangement of the value of the bits. 8 4 2 1 1 2 4 8 0 1 1 0 1 1 1 0 m n Here we have m = 3, s = 0 (pointed to by the arrow) and n = 7. That’s fine, so let’s see what happens when the head moves to the right, 8 4 2 1 0 1 1 0 1 1 2 4 1 1 0 m 8 n So the new values are m’ = 6, s’ = 1, n’ 3. So what’s happened to the numbers? Well it appears that the following has happened: m’ = 2 x m 6=2x3 n’ = n/2 (whole number division) 3 = 7/2 (remainder 1) s’ = remainder n/2 remainder 7/2 = 1 C.B.Price 2/12/2016 Draft 3 4 So the results of the tape read/write head moving to the write seem to be expressed in these three arithmetical calculations. Cool. They are close to being correct, but they are not exactly correct. We can why they are not correct this in the following example. The case for s = 1. 8 4 2 1 1 2 4 8 0 1 1 1 0 1 1 0 m n Here we have m = 3, s = 1 (pointed to by the arrow), and n=6. Note the difference with the previous example. Importantly here we have s = 1 which will help us clear up our incorrectness. OK let’s shift to the right. Here’s what we get. 8 4 2 1 1 2 4 0 1 1 1 0 1 1 m 8 0 n So now we have in this example, m’=7, s’ = 0, n’=3 .This agrees with our previous example (almost). Let’s see what agrees. First we have n’ = n/2 (whole number) 3 = 6/2 (remainder 0) s’ = remainder n/2 remainder 6/2 = 0 The problem was with the calculation of m’. In the first example, we said that m’ = 2m but here that does not work because 7 does not equal 2 x 6. The reason is that the value of s has been shifted into m. Here, s=1 so it adds a 1 to the value of m’. In the first example we had s=0 so the 0 was added in and we did not notice it. But now we must, so in general, we write m’ = 2 x m + s 7=2x3+1 That’s put it to bed. We have discovered that the movement of the read/write head to the right on a Turing Machine tape is equivalent to the following three basic arithmetic calculations. C.B.Price 2/12/2016 Draft 3 5 s* rem(n / 2) m* s 2m n* n / 2 These calculations, which only use the operations of addition, multiplication, division and getting the remainder, do exactly the same as a Turing Machine moving to the right on a tape. So we have discoverer that a Turing Machine moving to the right on its tape can be emulated by some simple arithmetic operations executed by a register-based machine. This is the first part of the demonstration that register machines and Turing Machines are the same. Before we take the demonstration further, it is interesting to find the minimal number of instructions required to support these three calculations. 2. A Set of Minimal Instructions As we have seen, in our first session, complex instructions may be better realized as simple instructions. The complex instructions provided by a CISC processor are rarely used; it is the RISC instructions which are ultimately produced by a compiler and are executed by our machine. So we ask what are these minimal instructions, and how many do we need? The answer is just two. Let’s tell this story. We have identified that we need addition, multiplication, division and remaindering, but these are not the simplest operations we have to use. It’s possible to replace all of these operations based upon the following instruction set: mov reg,0 Put 0 into register “reg” inc reg Add 1 to the contents of register “reg” decjmpreg reg,lab If register “reg” is zero, jump to the instruction labelled “lab” else subtract 1 from “reg” and do the next instruction jmp lab Jump to the instruction labelled “lab” hlt Halt We shall also show in a moment that the first, fourth and fifth instructions can be replaced by combinations of the second and third. While most instructions are easy to understand, the third appears a little daunting, so let’s see an example or two of this instruction in operation. This will help us understand how to perform the three basic arithmetic operations required for the shift-right operation. Let’s start with this one. m* = s + 2m So here we go. The three columns show how the registers change as we jump around the instructions. C.B.Price 2/12/2016 Draft 3 6 Columns are in sequence; we do column 1 then 2 then 3. We need three columns because there are jumps and therefore loops. e e e e a b c d x x x x L3: L4: mov ecx,3 mov ebx,0 decjmpreg ecx,L4 inc ebx inc ebx jmp L3 hlt e e e e a b c d x x x x e e e e a b c d x x x x 3 0 2 1 0 1 3 5 2 4 6 The three columns show how the registers change as we jump around the instructions. So we start by moving 3 into ecx and 0 into ebx. Then we hit the decjmpreg instruction. This checks ecx to see if it is zero (if so, we would jump to L4), but it is not zero, so we decrement it by one and continue. Then we have two inc ebx instructions so we increment ebx by two. Then we jump to L3. Here again the decjmpreg instruction looks at ecx, finds it is not zero so decrements it by one giving the result 1 and then executes the following instruction. Register ebx is incremented twice so that ebx becomes 4. We jump back up to L3 and check if ecx is zero, it’s not so we decrement it to zero. Two more inc’s sets ebx to 6. Jump again to L3 where the decjmpreg instruction has ecx as 0, so we finally jump to label L4 and halt. Whew! It’s interesting to see what’s happened. Register ecx was initially 3, and the program has ended with ebx as 6, in other words two times ebx. In other words the program multiplies the contents of ecx by two and sticks the result into ebx. It’s not hard to see why. In the loop, every time we decrement ecx by one, we increment ebx by two. So that’s how we do the multiplication by 2 in the second basic arithmetic calculation m* = s + 2m. I guess you can work out how to multiply by 5! I said we can simplify the “mov reg, number” instruction and the “jmp lab” instruction. First let’s see how we can get rid of the mov reg, number instruction. Let’s consider mov ecx,3. Well the following code will do this: assume ecx is zero inc ecx inc ecx inc ecx Not much to say about that, we’ve replaced a “move reg, number” instruction by an equivalent number of “inc”’s. Now how do we reduce the “jmp label” instruction? Remember that decjmpreg reg,lab instruction jumps to “lab” when “reg” is zero, so the following code will give us an unconditional jump, jmp lab: C.B.Price 2/12/2016 Draft 3 L1: 7 assume ecx is zero … … decjmpreg ecx,L1 But hang on a bit, you’re probably getting a little worried that in both of these I’ve assumed that a register is zero, that’s a pretty hard assumption. Can we not set a register to zero using our two “atomic” instructions? Well, yes, and this is how it is done. e e e e a b c d x x x x L1: L2 … … decjmpreg ecx,L2 jmp L1 … e e e e a b c d x x x x e e e e a b c d x x x x 3 2 1 0 The register ecx is assumed to contain 3 at the start, but this could be any number. It’s easy to see what this program does, it loops decrementing ecx until ecx is zero then it jumps to L2 and continues with the rest of the program. So that’s how to set a register to zero. Now we need to understand how we can add the value of s to 2m to complete the basic arithmetic calculation m* = s + 2m. Actually, this is not a general addition, since s can only be 0 or 1. So, we only need to add a 1 to m* if s=1. The following code does just this. decjmpreg ebx,L3 inc edx L3: Remember that edx holds the value of the intermediate variable z which is used to calculate m* = s + 2m. and that ebx holds the value of s. So if s = 1 (then ebx holds 1) the decjmpreg instruction decrements ebx by one (since it is not zero) and does not jump to L3. So the following instruction inc edx increments z by one which is adding the value of s (=1) onto 2m. On the other hand if s = 0 (ebx holds 0) then the d decjmpreg instruction jumps straight to L3 not incrementing edx, in other words adding 0 to z. Now let’s turn to the other two basic arithmetic operations s* = rem(n/2) n* = n/2 C.B.Price 2/12/2016 Draft 3 8 Look at this code: e e e e a b c d x x x x L3: L4: mov ecx,5 mov eax,0 mov ebx,0 decjmpreg ecx,L4 inc ebx decjmpreg ecx,L4 inc eax jmp L3 hlt e e e e a b c d x x x x e e e e a b c d x x x x 5 0 0 0 4 2 1 1 3 1 0 0 1 1 2 It starts off with 5 in ecx and ends up with 2 in eax and 1 in ebx. So what? Well, this code is actually computing two parts of the Turing Machine we needed, as seen above. We have 5/2 = 2 (whole numbers) which computes n* = n/2 and we have remainder(5/2) = 1 which computes s* = rem(n/2). Try it out for other values in ecx (e.g. 4) and check that it works. So at this point we have demonstrated that we can build a register based Turing Machine using four registers and two instructions. That’s all the hardware and software atoms we need to construct any computer that can execute algorithms (well-ordered randomless programs). Here’s our instruction set: inc reg Add 1 to the contents of register “reg” decjmpreg reg,lab If register “reg” is zero, jump to the label “lab” else subtract 1 from “reg” and do the next instruction The complete code for the Turing machine when the read/write head moves once space to the right is shown below. There’s annotations to make things quite clear. Remember that all jmp’s and mov’s can be replaced with decjmpreg’s and inc’s. This machine is running on 4 regs and 2 instructions. C.B.Price 2/12/2016 Draft 3 9 L2: decjmpreg eax,L1 inc edx z = 2m inc edx jmp L2 L1: decjmpreg ebx,L3 inc edx L3: L4: L6: L7: decjmpreg edx,L4 inc eax jmp L3 mov ebx,0 decjmpreg ecx,L6 inc ebx decjmpreg ecx,L6 inc edx jmp L4 decjmpreg edx,L7 inc ecx jmp L6 eax holds m ebx holds s ecx holds n edx holds z If s is 1 z = z + 1 m* = z s* = rem(n/2) z = n/2 whole n* = z hlt Finally, let’s write the code for our General Purpose Register (GPR) Turing Machine based on four registers and our two atomic operations, translating the mov’s and the jmp’s into our two primitive operations. This is shown in Section 5. 3. The Register Machine Equivalent of the Entire Turing Machine The above register machine provided the same functionality of the “move to right” movement of the read/write head. But remember that a Turing machine operation consists of the following steps. The machine starts in State S. It reads the symbol at the current head position. It writes a symbol at the current head position. The head moves left or right. The machine goes into state S*, depending on its previous state and the current symbol read s. So we have to code these additional elements. All of these elements are written as code. Here’s an overview of how the code is structured. It consists of repeated blocks, one block for each state. Remember that eax contains the entire tape to the left and ecx contains the entire tape to the right. We presented the head-movement code for move-left above. There is similar code for move-right. When we are in state S and prepare to move to state S*, then we will either select the move-left or the move-right code. So each state will contain two blocks of “movement” code like this. C.B.Price 2/12/2016 Draft 3 Head move left code 10 Head move right code So let’s say we are in state S0 and we read the symbol s2. To know what to do next for the case of the tape Turing machine, we looked up S0 (as primary key) and s2 as secondary key in the Turing Machine database table; Current State S S0 S0 S0 Symbol read s s1 s2 s3 Symbol to write s* s*1 s*2 s*3 Direction to move d R L R New state S* S1 S1 S2 So when we are in state S0 and read symbol s2 then we are looking at the second row in the table which tells us to write s*2 and move to the left and into the state S1. Let’s run this example again, but taking a portion of the Turing Machine table for the parity detector we saw previously. Here, the first three lines are as follows: Current State S Even Even Even Symbol read s 0 1 @ Symbol to write s* 0 0 0 Direction to move d R R N New state S* Even Odd Halt So if we are in the Even state and read a 1 then we write a 0, move to the right and go into the Odd state. So how do we do this with code? We sandwich the head movement code with two other blocks of code like this, for the parity detector example. C.B.Price 2/12/2016 State Even Draft 3 11 read the symbol s store s if(s == 0), set s = 0 and jmp to move-right code if(s == 1), set s = 0 and jmp to move-right code Head move left code Head move right code use the stored s if(s == 0), jump to the even state code if(s == 1), jump to the odd state code So we are in state Even we read the symbol s which is a 1, we save it in a register and then we jump to the head move right code. Then we used the stored read symbol to jump to the new state code which is odd. You will see that the Turing Machine table rows (one for each state – read symbol pair) are coded through if (x = a) type statements. We have seen that it is possible using our two atomic operations. So that’s how we do that. To effect these enhancements, we have had to add an additional register to our principal set of 4 registers to store s. Also, as explained in Section 5, we need an additional ‘help’ register to be able to zero our 4 principal registers. However, in section 6, we will show how to reduce these 6 registers to 2, to create a register-based machine with just two instructions and two registers. 4. Generalization of the Head Moving “Proof”. C.B.Price 2/12/2016 Draft 3 12 5. Code for the Right head movement using only two instructions. Here is the full code listing for the right head movement using only two instructions. We have added an additional register “esi” in order to be able to set our four principal registers to zero. ; ; ; ; ; ; ; ; TuringMachineRightFull.asm Computation of Right Branch of Turing machine using only two assembler instructions Register mapping m = eax, s = ebx, Register containing a zero (for jumps) esi. CBPrice n = ecx, z = edx February 19 2010 includelib kernel32.lib includelib user32.lib .586 .MODEL flat,stdcall .STACK 4096 .code ;===================== CODE SEGMENT ====================== decjmpreg macro reg, target cmp reg,0 jz target dec reg endm main PROC ; ============================================================== ; clear registers to zero --------; we must assume that one register is set to zero. Use esi (This increases our machine to 5 registers) sub esi,esi ; sets register esi to zero. (Subtracts what ever is in this register from itself to give a solid zero). ; ; A1: zero eax -------------------sub eax,eax decjmpreg eax, A2 decjmpreg esi, A1 ; remember this is an unconditional jmp A2: ; ; A3: zero ebx -------------------sub ebx,ebx decjmpreg ebx, A4 decjmpreg esi, A3 A4: ; ; A5: zero ecx -------------------sub ecx,ecx decjmpreg ecx, A6 decjmpreg esi, A5 A6: ; ; zero edx -------------------sub edx,edx C.B.Price 2/12/2016 A7: Draft 3 13 decjmpreg edx, A8 decjmpreg esi, A7 A8: ; ============================================================== ; Now, set m, s and n to some initial values. These will be set by the Turing Machine starting state; here we do it explicitly. ; ; The values are, m=11, n=8 and s=1 ; ; ; ; ; ; ; ; Set mov inc inc inc inc inc inc inc inc inc inc inc eax to the value of m (11) ---------------------eax,0bh (decimal 11) eax eax eax eax eax eax eax eax eax eax eax Set mov inc inc inc inc inc inc inc inc ecx to the value of n (8) -----------------------ecx,8 ecx ecx ecx ecx ecx ecx ecx ecx Set ebx to the value of s (1) -----------------------mov ebx,1 inc ebx ; ; Here is the code to do a shift to the right L2: ; ; L1: ; L3: ; ; L4: decjmpreg eax,L1 inc edx inc edx jmp L2 decjmpreg esi, L2 decjmpreg ebx,L3 inc edx decjmpreg edx,L4 inc eax jmp L3 decjmpreg esi, L3 mov ebx,0 decjmpreg ecx,L6 inc ebx C.B.Price 2/12/2016 ; ; L6: ; ; L7: Draft 3 14 decjmpreg ecx,L6 inc edx jmp L4 decjmpreg esi,L4 decjmpreg edx,L7 inc ecx jmp L6 decjmpreg esi, L6 hlt main ENDP END main 6. Reducing the Number of Registers needed to two. In our development above, we have seen that we need two instructions and six registers to emulate a Turing machine. I was concerned about the lack of ‘symmetry’ in this result and have worked out how to reduce the number of registers to two. So I have discovered that we only need two registers as well as two instructions to emulate the Turing machine and therefore all computers. Here’s what I did. It’s all to do with ‘prime numbers’ (1,2,3,5,7,11,…). At the same time, this gave me an answer to a problem which has been troubling me over the last few days, the concept of “Godelization of location in space”. So now I shall attempt an explanation of how to get down to two registers, based on a Godelization of 2D space, though I shall show you how this can be extended to n-dimensional space. It’s quite easy to understand. Let’s consider the following situation. We have a point on the 2D plane with co-ordinates (x,y) = (1,2). This could be the location of an asteroid in a 2D game. How can we create a single unique number to represent this position, ie a number which is a Godelization of this location in 2D space? y 2 x 1 First we have to understand something fundamental. The x-value of 1 and the y-value of 2 are independent which means they are not related. To get to the location (1,2) we have to take one step in the x-direction and then two steps in the y-direction. No movement in the x-direction will change the y location and vice-versa. C.B.Price 2/12/2016 Draft 3 15 Let’s proceed by example. Let’s refer to the Godelization of this location as G(1,2), remembering we wish to associate a unique number (or code) for this location. We must be able to retrieve the location (1,2) by decoding the associated Godel number in the future. The x-axis is associated with the prime number 2 and the y-axis is associated with the prime number 3. First let’s look at the Godelization of this location. We take the prime numbers 2 and 3 as mentioned above as a basis. We define the Godelization of 2D space GS(x,y),as follows GS ( x, y ) 2 x.3 y In English this means ‘take 2 to the power of x and multiply it by 3 to the power of y’. Ok. Let’s deal with the ‘power’ concept first. For example ‘2 to the power of 4’ (x = 4) means 2x2x2x2, that is 2 multiplied by itself four times. Easy. So let’s work the above example, for the point at location (1,2). Here, x = 1 and y =2. So we have G(1, 2) 21.32 which means 2 x (3 x 3) = 18. This is a unique Godel number which identifies this location in 2D space. To show that this Godel number is unique for this location, we must be able to decode (retrieve) the location (x=1, y=2) from this Godel number. Here’s how we do it. There are two stages, one for x and one for y. First, lets decode x. To do this, we repeatedly divide the Godel number by the associated prime number, 2, as long as we do not get a remainder. Here we go (i) 18 / 2 = 9 (ii) 9 / 2 = ‘can’t do’ (we got a remainder) so stop. (iii) Count the successful divisions. We have done one successful division. So x = 1. Now let’s decode y. To do this we repeatedly divide the Godel number by the associated prime number, 3. Here we go (i) 18 / 3 = 6 (ii) 6 /3 = 2 (iii) 2 / 3 = ‘cant do’ (we got a remainder) so stop. (iv) Count the successful divisions. We have done two successful divisions. So y = 2. We have decoded the values (x,y) = (1, 2) from the Godel number 18. This is happening because GS(1,2) = 2x3x3, and this number is divisible by 2 once and by 3 twice. It’s easy to see how we could extend this into Godelization of 3D space. We need to use the next prime number (5) for the z-dimension and calculate the function GS ( x, y, z ) 2 x.3 y.5z What’s going on here? Well we are building a Godel number which is combining several elements of data in a way that we can extract each element from the Godel number. The use of ‘prime’ numbers is crucial here, so in the process of combining the elements, the elements remain separate, they do not ‘interfere’ with each other, and so we can extract the elements from the single Godel number. C.B.Price 2/12/2016 Draft 3 16 So, for example GS (3, 4,5) 23.34.55 = (2x2x2)x(3x3x3x3)x(5x5x5x5x5) which is divisible by 2 three times, and is divisible by 3 four times and is divisible by 5 five times. So we can retrieve our starting umbers 3,4,5! To extend this procedure to Godelize n-space we form the product GS ( x1 , x2 ,..., xn ) 2 x1.3x2 ....N xn where N is the n’th prime number. How do we use this to reduce the number of registers? Let’s say we have three registers a,b,c holding numbers a,b,c. Then we Godelize these numbers (3D-space) as above to produce a single number r which we put into a single register r, like this: r GS (a, b, c) 2a.3b5c We can then use this single register in our register machine, and can recover the values in a,b,c by dividing by 2,3,5 respectively. But how do we use this strange register in the machine presented in sections 2,3 and 5? Well, remember that we only need two instructions inc reg and decjmpreg reg,L which work on the registers reg. How can these instructions work on our new single register r? Lets take the inc instruction first. We assume that r GS (a, b, c) 2a.3b5c . Let’s take the case of incrementing a by 1 to a + 1. This is done using the formula 2a 1 2.2a for example, let’s say that a = 4 which we want to inc to 5. Now 25 2.24 or in basic English (hehe) 2x2x2x2x2 = 2x(2x2x2x2). So to inc register a (contained in r) all we need to do is to multiply the number in r by 2! We saw how to do this in the lecture. Similarly, if we want to inc register b then we use the equivalent formula 3b 1 3.3b so we multiply the number in register b by 3 (which we also saw in class) and so on. Now we need to think about how to decrement a register, since this is needed for the decjmpreg reg,L instruction. (Remember this instruction jumps to label L if the contents of reg is zero, else it decrements the number in reg. Let’s see how to decrement the value in register a. Here we use the formula 2a1 2a 2 For example, if a = 4 we want to decrement to a = 3. So we calculate 23 24 2 x 2 x 2 x 2 2 2 In other words we have to divide by 2! It looks like we need two mathematical operations to produce our Turing Machine, multiplication and division. But we have seen that multiplication is repeated addition and C.B.Price 2/12/2016 Draft 3 17 that division is repeated subtraction, so we only need the two mathematical operations of addition and subtraction in other words incrementing and decrementing. So we have seen that the first requirement of the decjmpreg reg,L can be met, by division. But what about the “jump” part, where we jump to label L if the content of reg is zero. We have seen in Section 5 the need to have a register with initial value zero. Let’ call this register z. Then, the instruction decjmpreg z,L will make an unconditional jmp (jump) to the label L. So to round-up, we conclude that we need two registers for our machine, one is r and the other is a “zeroed-out” register z. So therefore I state the following theorem. Theorem 1. For every Turing Machine T there exists a register-based machine R which exhibits the same behaviour as T. This register-based machine consists of two registers and two instructions. 7. Solutions to Worksheet Problems Here is the code corresponding to the worksheet problems. ; CBPrice February 2010 ; ; Solutions to the Session 4 exercises includelib kernel32.lib includelib user32.lib .586 .MODEL flat,stdcall .STACK 4096 decjmpz decjmpreg macro target jcxz target dec ecx endm macro reg, target cmp reg,0 jz target dec reg endm .code main PROC ; ; assigning a number to a register -------------------------------------inc eax inc eax inc eax ; setting a register to zero -------------------------------------------mov eax,5 L1: L2: ;put a number in eax to be zeroed decjmpreg eax,L2 jmp L1 nop C.B.Price 2/12/2016 Draft 3 18 ; copy the contents of eax into ebx ------------------------------------mov eax,5 mov ebx,0 L3: L4: decjmpreg eax,L4 inc ebx jmp L3 nop ; adds the numbers in eax and ebx and puts the result into ecx ----------mov eax,3 mov ebx,4 mov ecx,0 L5: L6: L7: decjmpreg ebx,L6 inc ecx jmp L5 decjmpreg eax,L7 inc ecx jmp L6 nop ; if(x == 0) then execute code block A else if(x == 1) then execute code blockB. mov eax,1 decjmpreg eax,L8 ;code for block B here jmp L9 L8: ;code for block A here L9: nop ; done ; code to subtract ebx from eax mov eax,5 mov ebx,3 L12:decjmpreg ebx,L10 decjmpreg eax,L11 jmp L12 L10:nop L11:nop ; code to test if eax and ebx are equal (looks like subtraction! ------------mov eax,5 mov ebx,5 L15:decjmpreg ebx,L13 decjmpreg eax,L14 jmp L15 L13:mov eax,1 C.B.Price 2/12/2016 Draft 3 19 L14:nop ;; code to test if x == 3. if(x == 3) then goto code block A else goto code block B mov eax,2 decjmpreg decjmpreg decjmpreg decjmpreg L16:nop eax,L16 eax,L16 eax,L16 eax,L17 ; code block B L17:nop ; code block A 8. Postscript In writing this session I have become aware of something truly fundamental. A computer can be seen as (i) numbers stored in two registers, and (ii) two mathematical operations on these numbers. Why does mathematics have the power to represent all potential computers and their applications and not philosophy or physics? I do not restrict this question to electronic, mechanical, or electro-mechanical computers, but embrace “natural” computers such as Stonehenge. I’ve experienced this awareness once before while working during my early research. Why does mathematics capture nature? This includes all science, from the reproduction of rabbits, the formation of animal skin patterns (zebra stripes, leopard spots), the trajectories of balls, bullets and spacecraft. Simulations of all of these can be performed by computer programs. We have seen that these programs can be reduced to two instructions and two registers, where these programs express algorithms. Therefore we conclude with this theorem Theorem 2. Since the natural world (in all of its complexity) can be simulated by a computer, and since any algorithmic computer can be reduced to two registers and two instructions, the natural world consists of two registers and two instructions and proceeds by a “natural” algorithm.