No account yet?
Moore's law says that we will double transistor capacity every 18-24 months. And this seems to be holding at least for now. Very soon we will have transistors the size of atoms and you can't get smaller than that.
See "Digital electronics" module for more info, as I don't want to repeat my notes.
To compute the sum of binary numbers we need an adder. We'll first look at the half adder then extend to the full adder.
Half Adder: This sums two binary inputs and creates a carry, if the inputs are 1 and 1. It does not except a carry as an input
Full Adder: Like a half adder but also excepts a carry as an input and will add that to the sum
Now that we have a full adder the simplest way of summing two multi digit binary numbers is to create a chain of full adders where the sum of each digit is computed with the carry from the previous digit sum.
This is the fundamental computer architecture and the key idea is the data and program are stored in the same place. This allows for cool self modifying programs.
Von Neumann Bottleneck: Limitation of the data transfer rate between CPU and memory. This was "fixed" by adding CPU (on-chip) caches, though Harvard architecture was the better fix.
This is another architecture where the data memory and instruction memory are stored separately, with separate buses for collecting the data. This solves the Van Neumann Bottleneck but means you can't have self modifying programs. However these days our computers use modified harvard architecture which is more complex and allows the processor to treat data as instructions and instructions as a data hence self modifying programs are again possible. We also kept the CPU caches from harvard architecture.
There are 3 types of buses, each used for a different purpose.
Memory stored very close to CPU, as a buffer between the RAM and CPU. Stores frequently accessed items.
Divided into two levels:
Very fast.
Level 1 is faster than level 2.
For more information review your "machine architecture" notes.
The instruction set architecture is basically the design of the instructions which allows the programmer to control the hardware. Alot of specific design choices are considered when making an instruction set architecture.
The ISA describes the:
This next part is going to overlap alot with machine architecture so i'll just touch on the essentials.
MIPS assumes:
Some examples of common MIPS assembly instructions:
When making an instruction architecture you want a way of standardising the format of the instructions to reduce the circuit complexity, and make programming easier. MIPS is a RISC language which means it has very few instructions and only 3 formats.
(Opcode, Rs, Rd, Imm)
Bits: 6, 5, 5, 16
(Opcode, Rs1, Rs2, Rd, shift, funct)
Bits: 6, 5, 5, 5, 5, 6
(Opcode, Address)
Bits: 6, 26
The operating system is the interface between the computer user and the computer hardware.
Kernel: Main component of OS, which loaded at boot time. It has full control of the CPU.
The main functions of the OS are:
Examples of Input/output devices: Hard disk, CD, Graphics card, sound card, ethernet card, modem
These are connected to the cpu via a bus. However Buses are slow and if we had to pause the execution of the whole cpu to wait for an input to be received or output to be sent, it would causes a bottleneck. To solve this the operating system has Interrupts.
Interrupts: A signal to the cpu that input or output device has sent something on the bus. An interrupt handler announces thse signals to the CPU so that it can process it, then it resumes the paused process.
These are programs currently being executed. They consist of one or more thread(s) of instructions and an Address Space
Mutual exclusion: A property of processes which is says that no two threads can run the critical section at the same time. Where the critical section is a part of the program which accesses the same shared resource.
You can imagine a scenario where two threads had access to the same counter variable and changed it in some way. But if they ran at the same time one thread would change the counter accessed by the other thread causing all sorts of problems. This is why there must be mutual exclusion
The life cycle of a process is quite intuitive. It gets created, it waits for it's turn to run, it's gets run, then it stops. In addition it can also wait for other events. Each of these states has an equally intuitive name.
The actions done to move a process between these states also have special, harder to memorize, names that we have to learn because it makes it easier to communicate what the OS is doing to people.
This is a container of information (data structure) used by the kernel to mange the processes. It contains all the information you could possibly need to know about it. Such as:
If you want processes to run in parallel you need to let them share the CPU space at the same time. Now this isn't possible, so we'll go with the next best thing: Context Switching.
This is where we periodically pause the execution of a process save all the necessary data needed for resuming to a PCB in the OS, then later after the other processes have had their turn, we resume it using the stored PCB data.
Note: This is time consuming and so it's why pc's have multiple cores so that processes can run in parallel for real without this added overhead.
Unlike the more traditional subjects, Computer science problems are all about what method is used to achieve a goal and how good of a method it is, rather than just can you achieve the goal.
Problem in computer science are defined by:
Computer science at it's core really just boils down to doing Computations with limited Resources and with Correctness
In most contexts Resources are the time or memory used by the computations and uses, and Correctness refers to if the solution is actually answers the problem (or in the case of optimisation: if it is the best answer to the problem)
This is where you take a real world problem and transform it into an idealised (mathematical) version which can be understood by a computer but also where the solution to this new variation can still be used to give the answer to the original real world problem.
To understand abstraction a bit better lets take a look at how we can apply it to the travelling salesman problem (TSP).
The TSP is where a salesman wishes to find the shortest tour of a given collection of cities. (So that he saves as much time/fuel as possible.) To solve this we need to find a way of abstracting the real world problem into something we can obtain a computational solution for. We can do this with the following steps
This is a problem which asks a question about a given thing and the answer is either yes or no.
Common features:
Since all the information is contained within which regions touch each other we can abstract it as a graph colouring problem
Graph G = (V,E) where v is a set of vertices and E is a set of connecting edges. Colour the graph such that all pair of vertices joined by an edge are coloured differently.
This is a problem where you have lots of possible solutions for a given input and you need to return one. If there is no solution you need to say so.
To solve we a search where we are given an instance we need to find a solution from the possible solutions that fits the search relation for that instance. (or in plain english the solution needs to fit the criteria). Else there is no solution and we return "False".
Abstract to a list of symbols. However, must consider that in the case of lists of lists, the data structures will be more complex
Telephone directory, File structure
Abstract to:
These are problems where you have lots of possible solutions for a given input and you need to return the best one according to some criteria.
Abstract to a weighted graph.
(use abstraction described in detail earlier)
Given sports day events that must be scheduled at various times throughout the day, where each event takes 30 minutes and certain events can occur at the same time as long as the athletes are available what is the earliest time sports day can finish if there is the maximum number of events in the noon slot
After abstracting a problem we then need an algorithm to solve that problem. We'll look at some different algorithms which exist for some of the fundamental computer science problems.
Algorithm: a process or set of rules to be followed in calculations or other problem-solving operations, especially by a computer.
Greedy algorithm: An algorithm which makes choices based on what look best in the moment. (finds the local optimum but not the global)
We can abstract this as a Graph colouring problem, where the vertices are regions of the map and edges are adjacent regions.
We'll look at two different algorithms greedy colouring and point removal (brute force)
We abstract this as a graph where the vertices are the events and events which conflict are connected by edges. Then the largest number of events which can scheduled in one slot is equivalent to finding the maximum independent set of the vertices. To find a way of grouping the remaining events into slots we can treat it as a vertex graph colouring problem, and then assign each colour to a slot.
Note: Maximum ≠ maximal. Maximal independent set is a set which is not contained in any other set. However there may still be large independent sets, such as the maximum.
We'll look at a heuristic greedy algorithm for findinging a large independent set.
This algorithm works on the heuristic principle that if you remove as few vertices as possible at each step, you'll be able to create a large independent set. However whilst this will produce a large independent set it unfortunately does not produce the largest independent set. So it is still just a greedy algorithm
We abstract the TSP as a weighted graph, and proceed to find the shortest cycle where each node is visited once. (Hamiltonian cycle)
A short but not optimally short path can be found with a greedy algorithm:
In Order to allow algorithms to be able to be described in a way which is sufficiently precise so that it can be programmed and analysed but still flexible enough that it can be used in any programming language, we will write them in a special language called Pseduo-code.
When it comes to algorithms we may be interested in proving:
A programming language provides a way of translating an algorithm into a form, called a program, which can be executed by the computer.
Note: Algorithm ≠ Computer program. Whilst a program is concertely and explicitly defined in the programming language the algorithm can have many different implementations. Not only are there different implementations for each programming language but even with the same one there different implementations.
Programming paradigm: a way to classify programming languages based on their features.
There are lots and lots of paradigms, that people have come up with to group languages together but we'll just look at the most common.
Aliasing: Situation where the same memory location can be accessed by different pointers (names). Some people think this is a dangerous feature
Syntax: Rules which tell us what can or can't be written in a programming language.
Semantics: Proving with formality what a program means.
Formally defining the semantics of a programming language should be done for the following reasons:
If we define semantics informally (like C, Fortran, python and many languages do) we can cause ambiguity which can cause errors.
There are different types of formal semantics we can use:
Compiled languages: The whole language is compiled at once into machine code.
Interpreted languages: Only one instruction at a time is translated to machine code and this is done during runtime.
Hybrid languages are also possible which combine compilation and interpretation to get the best of both worlds.
Regular expression: An expression which selects characters in the text from the alphabet ∑\sum
Some examples of regular expressions:
Theorem: A string is denoted by a regular express iff it is accepted by a final state machine
A finite state machine is a mathematical model of computation which can be in one of a finite number of states and can have it's state changed by inputs.
A finite state machine has:
Pictorial representation of an FSM:
We measure time taken by algorithm rather than measure time taken by the implementation because this way it doesn't vary according to the programming language, computer or the processor speed. Thus it is machine-independent
Fundamental assumptions of algorithms:
basic operation: An operation that takes one FDFE cycle.
Worst-case time complexity: This is given as a function of n, the input size, and tells how many units of time c, it would take to run the algorithm in the worst case. It is expressed as a function because if it was a constant then no matter what we picked we could find a value of n, for which the time surpassed that bound.
Big O notation: This lets us denote the worst-case time complexity and give an upper bound on the time.
Define precisely what we mean when we say that two functions f (n) : N → N and g(n) : N → N are such that f = O(g). [2]
There exists some n ∈ N and some positive rational k ∈ Q such that f(n) ≤ kg(n) whenever n ≥ n0.
Efficiently checkable/solvable: Can be checked/solved in polynomial time
Polynomial-time reduction: A polynomial time algorithm to convert one decision problem into another. where if one is true the other must also be true.
This is a famous unsolved computer science problem which attempts to show if a problem can be checked in polynomial time to can be solved in polynomial time. Suspected to be false.
This is the idea of relying on computing power instead of intelligence by using a naive method to find all possible instances and pick the best/correct one.