Repository navigation
WIP: updates2026 #177
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
WIP: updates2026 #177
Changes from all commits
9677793
3aa1375
6b8075e
4766fcc
dbbf94a
da630ac
a72db8d
154a446
e883867
8a17105
13bf49e
dfb35c4
8d215ac
ecfd151
e569a70
0b21614
d78017a
9bdd471
ffa8b69
74b53ee
c3883c3
e7c5f3c
a668c1e
3f8f0d3
beb4fc4
1d71c95
b64ea6e
534a9e6
905f138
c5fc4bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,65 @@ | ||||||
| --- | ||||||
| title: Basic Types | ||||||
| --- | ||||||
|
|
||||||
| # Basic Types in Programming Languages | ||||||
|
|
||||||
| In order to effectively work in any programming language, we need a basic understanding of a number of fundamental types. We will give these types by the names in C++, although there are generally analogues in other languages. | ||||||
|
|
||||||
| ## Boolean Types | ||||||
|
|
||||||
| Boolean types represent true/false values. In C++ the type is called `bool` and it takes 1 byte of memory. | ||||||
|
|
||||||
| ## Integer Types | ||||||
|
|
||||||
| All programming languages will have some types to describe integer values. We use these to represent things that in mathematics are in the set of _natural numbers_ $\mathbb{N}$ or _integers_ $\mathbb{Z}$. In C++ we might most commonly use: | ||||||
|
|
||||||
| - `int`: integers that can be positive or negative, and take 4 bytes of memory. | ||||||
| - `unsigned int`: integers that can only be positive, and take 4 bytes of memory. Because they don't have to represent negative numbers as well, `unsigned int` can represent larger values than `int`. | ||||||
| - `std::size_t`: unsigned integers that can represent that size of the largest possible object; this is usually determined by the addressing on an architecture. For example, on a 64-bit system `size_t` will typically be 8 bytes. This is the standard type to use for things like indexing arrays/vectors since it can't be negative and is guaranteed to be able to represent the largest index of an element of an array. | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggest to add something like
|
||||||
|
|
||||||
| There are many other types that C++ offers, although not all of them are standard. You should use the C++ documentation to check whether a type that you want to use is standardised and portable across different architectures. (As an example, I used to use `uint` for unsigned integers until some Mac users informed me that it doesn't compile with the `clang` compiler!) | ||||||
|
|
||||||
| ## Strings and Characters | ||||||
|
|
||||||
| A single character can be represented using `char`, which takes a single byte. For strings you are advised to use the C++ type `std::string`. In some places you will come across `char*`, an C-style array of `char`, as an alternative to C++ strings. These should only be used where necessary for compatibility. The most common place for this to come up is command line arguments for the `main` function. | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, nerd comment:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did originally write up a bunch of stuff about pointers but I was worried that this is the prelim material and they don't know what a pointer is yet. I only really included char* because I was worried they would see it in command line arguments. Perhaps it's better to defer char* to later to avoid confusing them? Most of the time they should be using std::string anyway nowadays. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair - I suppose we would anyway cover it on the first day via a little Hello world program, so maybe we don't even need to cover it in the prereqs then. |
||||||
|
|
||||||
| ## Floating Point Representation of Real Numbers | ||||||
|
|
||||||
| The real numbers, $\mathbb{R}$, is the set of numbers along the number line. There are infinitely many real numbers in any finite interval, and this poses a problem for computation: we clearly cannot represent all the real numbers exactly, since we have a finite amount of space in which to represent them. Floating point representation is how we typically deal with approximating the real numbers in code. Floating point numbers can in principle have any level of precision, but the most common are: | ||||||
|
|
||||||
| - `float`: 32 bits (4 bytes), | ||||||
| - `double`: 64 bits (8 bytes), | ||||||
| - `long double`: Usually 80 or 128 bits depending on processor, | ||||||
| - `half`: 16 bits, not part of the C/C++ standard but often used on hardware like GPUs. | ||||||
|
|
||||||
| The data for floating point numbers are split into two parts, the mantissa and the exponent. It is comparable to scientific notation (when you write a number as $a \times 10^b$) except that it uses powers of 2 instead of 10. We can write a floating point number $n$ as | ||||||
|
|
||||||
| $n = m \times 2^e$ | ||||||
|
|
||||||
| where $m$ is the mantissa and $e$ is the exponent. The mantissa is usually represented such that there is a radix point after the first significant (non zero) digit. In other words, the binary `001011` would represent the mantissa `1.011` (again, in base 2). The exponent is a signed integer. | ||||||
|
|
||||||
| The size of the datatype affects both the precision of the mantissa and the range of values for the exponent (and therefore how large and small the values represented can be). | ||||||
|
|
||||||
| - `float` has around 7 significant figures | ||||||
| - `double` has around 16 significant figures | ||||||
|
|
||||||
| Floating point computation **is not exact**. | ||||||
|
|
||||||
| - Adding values of very different sizes leads to significant loss of precision since values must be converted to have the same exponent to be added together. This means the difference in scale is pushed into the mantissa, which then loses precision due to leading `0` digits on the smaller number. In some cases the smaller number may be so small that the closest representable number with that exponent is `0` and so the addition is lost completely. | ||||||
| - Subtracting values which are close in size leads to cancellation of many digits and a result with far fewer significant digits and therefore lower precision. | ||||||
| - Identities from real arithmetic do not necessarily hold, in particular **addition and multiplication are not associative**, so $(a + b) + c \neq a + (b + c)$ in floating point! | ||||||
| - Handling these difficulties in numerical methods is a major field in and of itself. Many numerical algorithms are specially crafted to correct rounding errors in floating point arithmetic. | ||||||
|
|
||||||
| ### Floating Point Precision | ||||||
|
|
||||||
| Higher precision floating point numbers (like `double` as opposed to `float`) will give more accurate results when doing numerical work, but may also be slower to perform operations. Historically `double` operations have taken more time to compute than `float` operations, although this is no longer typically the case on modern CPUs. Nevertheless, if you are exploiting SIMD registers for maximal performance, fewer `double` values can fit in an available register and therefore fewer operations can be performed in a given amount of time. Some fast algorithms use single precision `float` or even half precision floating point numbers in areas where the results will not be significantly impacted by this. This is particularly common in areas like statistics and machine learning where the statistical variance is much larger than the precision of the floating point numbers. You must always bear in mind that the use of lower precision floating point types can lead to numerical instability from cancellation errors or division/multiplication by extreme values causing under or overflow. You should always have tests for robustness and precision to check that any compromises made to precision are acceptable. | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggest to add something like the following for perspective:
|
||||||
|
|
||||||
| ## Containers | ||||||
|
|
||||||
| Containers are important to most programming languages; almost all programmers will need to work on things like lists of data, or vectors and matrices. Some commonly used containers, that we will use repeatedly throughout this course, are: | ||||||
|
|
||||||
| - `std::array<T, N>`: a type for storing exactly `N` elements of type `T`, with `N` known at compile time. | ||||||
| - `std::vector<T>`: a type for storing arbitrary numbers of elements of type `T`. | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| - `std::map<A, B>`: a type for storing key-value pairs where keys are unique and have type `A` and values have type `B`. | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| --- | ||
| title: Data Representation | ||
| --- | ||
|
|
||
| # Background: Basic Data Representation | ||
|
|
||
| In order to write effective scientific programs, you will need to be able to translate real world and mathematical concepts into some kind of data representation. This is arguably the most fundamental process to understand in computing, since nothing can be worked with that cannot be represented. You may find that standard representations for many common objects (like vectors, complex numbers etc.) already exist, but it is absolutely vital that you understand how to construct these yourself. In this section, we will look at some examples of how to translate concepts into data representations in a language agnostic way. | ||
|
|
||
| ## What is a data representation? | ||
|
|
||
| In order to represent something on a computer we need to have a properly formalised idea of exactly what information needs to be stored and how. Computers themselves have only sequences of zeros and ones to work with, and the computer itself doesn't know what it is you're trying to represent with it and can't make any decisions on its own about the correct thing to do with them. | ||
|
|
||
| Later in this course we will look at the object-oriented approach of combining data and functionality together, but for now we will restrict ourselves to the more fundamental topic of data alone. | ||
|
|
||
| ## Defining structures | ||
|
|
||
| Programming languages usually provide us with a number of basic types of data that we can utilise, including: | ||
|
|
||
| - integers | ||
| - real numbers (approximated as "floating point") | ||
| - characters and strings | ||
| - arrays / lists | ||
|
|
||
| Almost all languages, including C++ and Python, will give us ways of bundling data together into a larger structure that a collection of named _fields_ of various types. In C++ and Python these are called _classes_[^struct-class]. Deciding what fields are needed for a class is a a fundamental skill in translating your ideas into computable data. | ||
|
|
||
| In C++, we must choose explicitly both the name and the _type_ of the data being held: is it an integer, or string, a floating point number? This is because C++ is _statically typed_ (variables must have a well known type that cannot change over the course of the program) whereas a language like Python is _dynamically typed_ (variables have the type of whatever data is assigned to them, and their type can change when their data is updated). | ||
|
|
||
| [^struct-class]: Some of you may be familiar with _structs_ from C; the `struct` keyword from C is also valid in C++ and is also used to define a class. When declaring a data type with `struct` the members are public by default, whereas when using `class` the members are private by default; this is the only distinction made in C++ between these two keywords. | ||
|
|
||
| ## Example 1a: a circle | ||
|
|
||
| Suppose our model requires us to represent a circle in a 2D space. This could be because we need to draw it for a graphical output, or we need to keep track of everything that happens within a given radius of some object, or perhaps we need to do collision detections for a physical simulation. What information do we need to store in order to represent a circle on a computer? | ||
|
|
||
| In order to answer this question, we should start by thinking about the least information necessary to fully define a circle: it will need a position $(x,y)$ and a radius, $r$. Everything else about a circle can be derived from this information: the circumference, the area, whether something is inside or outside of the circle, and so on. In a purely mathematical sense, $x$, $y$, and $r$ are all _real numbers_; on a computer our best way to represent real numbers is _floating point_ numbers, i.e. `float` or `double`. A class to represent a circle could look like this in C++: | ||
|
|
||
| ```cpp | ||
| class Circle | ||
| { | ||
| public: | ||
| double centre_x; | ||
| double centre_y; | ||
| double radius; | ||
| }; | ||
| ``` | ||
|
|
||
| or like this in Python: | ||
|
|
||
| ```python | ||
| class Circle: | ||
| centre_x: float | ||
| centre_y: float | ||
| radius: float | ||
| ``` | ||
|
|
||
| Note that in Python we have included the optional type annotations for clarity, and that `float` in Python has double precision and is therefore equivalent to `double` in C++. | ||
|
|
||
| ## Example 1b: adding colour to a circle | ||
|
|
||
| Consider now the graphical application of our circle class: we don't just need to know where it is and how big it is any more, but also what colour to render it. A colour on the computer is usually represented as a triple $(r, g, b)$ of _red_, _green_, and _blue_ intensities from 0 to 255. We can write a simple class to represent a colour then in the following way: | ||
|
|
||
| ```cpp | ||
| class Colour | ||
| { | ||
| public: | ||
| int r; | ||
| int g; | ||
| int b; | ||
| }; | ||
| ``` | ||
|
|
||
| If we've defined a `Colour` class, we can add it to our `Circle` class: | ||
|
|
||
| ```cpp | ||
| class Circle | ||
| { | ||
| public: | ||
| double centre_x; | ||
| double centre_y; | ||
| double radius; | ||
| Colour colour; | ||
| }; | ||
| ``` | ||
|
|
||
| This kind of nested data structure is very helpful in building up complex structures, and more more readable than giving the `Circle` class its own separate red, green, and blue member variables. | ||
|
|
||
| The Python equivalent would be: | ||
|
|
||
| ```python | ||
| class Colour: | ||
| r: int | ||
| g: int | ||
| b: int | ||
|
|
||
| class Circle: | ||
| centre_x: float | ||
| centre_y: float | ||
| radius: float | ||
| colour: Colour | ||
| ``` | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggest to add a final remark along the lines of
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should add here something like:
?