<jupyter_start><jupyter_text>01 Operators, Data Types & Control Flow PRIMER Basic Operators	 &emsp;&emsp; __Simple Operators__ 	 &emsp;&emsp; Algebraic Operators 	 &emsp;&emsp; Operator Precedence 	 &emsp;&emsp; Readability  Variables and Assignment 	 &emsp;&emsp; Assigning Variables 	 &emsp;&emsp; Augmented Assignment 	 &emsp;&emsp; Shortcuts 	 &emsp;&emsp; __Naming Variables__      &emsp;&emsp; __Example Use of Keywords: `print`__  Comparing Variables using Booleans      &emsp;&emsp; __Comparison Operators__      &emsp;&emsp; __Logical Operators__ 	 &emsp;&emsp; __Time Telling Example__ 	 &emsp;&emsp; Operator Precedence 	 &emsp;&emsp; __Stacking Boolean Operators__  Types	 &emsp;&emsp; __Introspection__ 	 &emsp;&emsp; __Booleans__ 	 &emsp;&emsp; __Strings__ 	 &emsp;&emsp; __Numeric Types__ 		 &emsp;&emsp; &emsp;&emsp; __Integers__ 		 &emsp;&emsp; &emsp;&emsp; __Floating Point__              &emsp;&emsp; &emsp;&emsp; &emsp;&emsp; __Rounding Floating Point Numbers__ 			 &emsp;&emsp; &emsp;&emsp; &emsp;&emsp; __ScientificNotation__          &emsp;&emsp; &emsp;&emsp; Complex Numbers      &emsp;&emsp; __Casting__  Summary  Review Exercises  Simple OperatorsWe can use Python like a calculator.__Simple arithmetical operators:__$+$    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;         Addition $-$    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;         Subtraction $*$    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;         Multiplication $/$    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  Division $//$   &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;         Floor division (round down to the next integer)$\%$   &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;         Modulo (remainder)$**$   &nbsp; &nbsp; &nbsp; &nbsp;                Exponent<jupyter_code><a id='AlgebraicOperators'></a>
<h3>Algebraic Operators</h3> 
Express the following simple expressions using python code. <br>
Click on the cell to type in it. <br>
Press "Shift" + "Enter" to run the cell. 

$3 + 8$ 


3 + 8


a = 1 + 3
print(a)

<a id='OperatorPrecedence'></a>
### Operator Precedence


__Operator precedence:__ The order in which operations are performed when there are multiple operations in an expression

e.g. multiplication before addition.


Python follows the usual mathematical rules for precedence. 

> 1. Parentheses &nbsp; e.g. $(2+4)$
1. Exponents &nbsp; &nbsp; &nbsp; e.g. $2^2$
1. Multiplication, Division, Floor Division and Modulo (left to right)
1. Addition and Subtraction (left to right)

- The expression should __evaluate correctly__.
- The expression should be __easily readable__. 


__Easily Readable__

Simple enough for someone else reading the code to understand.

It is possible to write __code__ that is correct, but might be difficult for someone (including you!) to check.

#### Correct Evaluation

A common example: 

$$
\frac{10}{2 \times 50} = 0.1
$$

10 / 2 * 50

is incorrect.



Multiplication and division have the same precedence.

The expression is evaluated 'left-to-right'. 

The correct result is acheived by using brackets &nbsp; $()$, as you would when using a calculator. 



$$
\frac{10}{2 \times 50} = 0.1
$$

__How would you enter this using a calculator to get the correct order of precedence?__



<a id='Readability'></a>
### Readability


An example that __evaluates__ the following expression correctly:

$$
2^{3} \cdot 4 = 32
$$

but is __not easily readable__:


2**3*5


$$
2^{3} \cdot 4 = 32
$$

A better (__more readable__) expression:

(2**3)*4

It is best practise to use spaces between characters to make your code more readable.

You will be marked on readbility in your assessment.

Start developing good habits now!

(2**3)*4

(2**3) * 4

<a id='VariablesAssignment'></a>
## Variables and Assignment


We can easily solve the equations so far using a calculator.

Let's look at some special operations that Python allows us to do.





What if we want to evaluate the same expression multiple times, changing the numerical constants each time?

Example:
>$x^{y} \cdot z = $ <br>

>$2^{3} \cdot 4 = $ <br>
$4^{5} \cdot 3 = $ <br>
$6^{2} \cdot 2 =$ &nbsp; ...







What if we want to use the value of the expression in a subsequent computation?

Example:

>$a = b + c$

>$d = a + b$

In both these cases programming can improve the speed and ease of computation by using *assignment*.

<a id='AssigningVariables'></a>
### Assigning Variables


When we compute something, we usually want to __store__ the result.

This allows us to use it in subsequent computations. 

*Variables* are what we use to store values. 

c = 10
print(c)

Above, the variable `c` is used to 'store' the value `10`. 

The function `print` is used to display the value of a variable. 

(We will learn what functions are and how we use them later).



To compute $c = a + b$ , 
<br>where $a = 2$ and $b = 11$:

a = 11
b = 11
c = a + b

print(c)

If we want to change the value of $a$ to $4$ and recompute the sum,

we re-write `a = 2` 

as `a = 4` 

and run the cell again to execute the code. 

__Try this yourself__. 

Change the value of a or b.

Re-run the cell to update the value.

(Click on the cell to type in it. <br>
Press "Shift" + "Enter" to run the cell.)

Then run the `print(c)` block to view the new value.

__In the cell below find $y$ when__:
<br>$y=ax^2+bx+c$, 
<br>$a=1$
<br>$b=1$
<br>$c=-6$
<br>$x=-2$

# create variables a, b, c and x
# e.g. a = 1  


#type: print (y) to reveal the answer


What value did you get for y?

Now change the value of $x$ so that $x = 0$ and re-run the cell to update the value. 

What value did you get for y this time?

<a id='AugmentedAssignment'></a>
### Augmented Assignment

The case where the assigned value depends on a previous value of the variable. 

Example:

a = 2
b = 11
a = a + b
print(a)

This type of expression is not a valid algebraic statement since '`a`' appears on both sides of '`=`'. 

However, is very common in computer programming. 




__How it works:__
    
 > `a = a + b`
    
 The final value of `a` (left-hand side) is equal to the sum of the initial value of `a` and `b`

<a id='Shortcuts'></a>
### Shortcuts

Augmented assignments can be written in short form.

For __addition__:

`a = a + b`  &nbsp;&nbsp; &nbsp; can be written &nbsp;&nbsp;&nbsp; `a += b`

# Long-hand addition
a = 2
b = 11
a = a + b
print(a)

# Short-hand addition
a = 2
b = 11
a += b
print(a)

For __subtraction__:

`a = a - b`  &nbsp;&nbsp; &nbsp; can be written &nbsp;&nbsp;&nbsp; `a -= b`


# Long-hand subtraction
a = 1
b = 4

print(a)

# Short-hand subtraction
a = 1
b = 4

print(a)

The <a href='#AlgebraicOperators'>basic algebraic operators</a> can all be manipulated in the same way to produce a short form of augmented assigment. 

Complete the cells below to include the __short form__ of the expression and `print(a)` to check your answers match. 

__Multiplication__

# Long-hand multiplication
a = 10
c = 2
a = c*a
print(a)

# Short-hand multiplication
a = 10
c = 2

__Division__

# Long-hand division
a = 1
a = a/4
print(a)

# Short-hand division
a = 1

__Floor Division__

# Long-hand floor division
a = 12
a = a//5
print(a)

# Short-hand floor division
a = 12

__Floor Division (of negative nunbers)__

# Long-hand floor division
a = -12
a = a//5
print(a)

# Short-hand floor division
a = 12

__NOTE:__ Floor division always rounds DOWN. 

$$\frac{-12}{5} = -2.4$$

The cloest integer __less than__ -2.4 is -3.

__Modulo__

# Long-hand modulo
a = 12
c = 5
a = a % c
print(a)


# Short-hand modulo
a = 12
c = 5

__Exponent__

# Long-hand exponent
a = 3
c = 2
a = a ** c
print(a)

# Short-hand exponent
a = 3
c = 2

##### Note:  The sentences beginning with "#" in the cell are called comments.  
These are not computed as part of the program but are there for humans to read to help understand what the code does.

<a id='NamingVariables'></a>
## Naming Variables
__It is good practice to use meaningful variable names. __

e.g. using '`x`' for time, and '`t`' for position is likely to cause confusion. 

You will be marked on readbility in your assessment.

Start developing good habits now!

Problems with poorly considered variable names: 

1. You're much more likely to make errors.
1. It can be difficult to remember what the program does.  
1. It can be difficult for others to understand and use your program. 


__Different languages have different rules__ for what characters can be used in variable names. 

In Python variable names can use letters and digits, but cannot start with a digit.

e.g. 

`data5 = 3` &nbsp; &nbsp; &nbsp; $\checkmark$

`5data = 3` &nbsp; &nbsp; &nbsp; $\times$

__Python is a case-sensitive language__

e.g. the variables '`A`' and '`a`' are different. 



__Languages have *reserved keywords*__ that cannot be used as variable names as they are used for other purposes. 

The reserved keywords in Python are:

`['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']`

A keyword already has a use assigned to it.

Reserved words are colored bold green when you type them in the Notebook so you can see if one is being used. 

 

If you try to assign something to a reserved keyword, you will get an error e.g. it is not possible to create a variable with the name __`for`__:

for = 12

<a id='ExampleUseKeywordsprint'></a>
### Example Use of Keywords: `print`
We can print output from our program using the word `print`.
A print call is ended by a newline by default.
This is shown below: 

c = 10
print(c)
print(c)

However, we can choose a different line ending using the __keyword__ `end`. 

print(c, end=" ")
print(c)

print(c, end="")
print(c)

The print function can take mutiple inputs, seperated by commas.
<br>The default output seperator is a space.
<br>However, we can choose a different seperator using the keyword `sep`. 

print(c, c, c)
print(c, c, c, sep=':')

Reserved words are colored bold green when you type them in the Notebook so you can see if one is being used. 

 

If you try to assign something to a reserved keyword, you will get an error e.g. it is not possible to create a variable with the name __`for`__:

for = 12

__Sometimes it is useful to have variable names that are made up of two words.__ 

A convention is to separate the words in the variable name using an underscore '`_`'. 

 e.g. a variable name for storing the number of days: 
```python 
 num_days = 10
```

Can you think of a suitable variable name for each of the following quantities? 

__temperature__

__height__

__depth of hole__

__class__


<a id='ComparingVariablesBooleans'></a>
## Comparing Variables Using Booleans

__Boolean:__ A type of variable that can take on one of two values:
- true
- false



<a id='ComparisonOperators'></a>
### Comparison Operators
__Comparison Operator:__ An operator that is used to compare the values of two variables. 

__Commonly used comparison operators:__

$==$   &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;         Equality <br>
$!=$   &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;         Inequality <br>
$>$    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  Greater than <br>
$<$    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  Less than <br>
$>=$   &nbsp; &nbsp; &nbsp; &nbsp;         Greater than or equal to <br>
$<=$   &nbsp; &nbsp; &nbsp; &nbsp;         Less than or equal to <br>




One way to visualise how a Boolean works is consider the answer when we make a verbal comparison...

__Example:__ Comparing variables a and b using comparison operators returns a boolean variable:

a = 10.0
b = 9.9

# Check if a is equal to b 
print("Is a equal to b?")
print(a==b)


# Check if a is more than b.
print("Is a greater than b?")
print(a > b)

__Complete the cell below by writing the correct comparison operator in each set of empty brackets.__ 

a = 14
b = -9
c = 14


# Check if a is less than b.
print("Is a less than b?")
print()

# Check if a is equal to c 
print("Is a equal to c?")
print()

# Check if a is not equal to c 
print("Is a not equal to c?")
print()

# Check if a is less than or equal to b 
print("Is a less than or equal to b?")
print()

# Check if a is less than or equal to c 
print("Is a less than or equal to c?")
print()

# Check if two colours are the same
colour0 = 'blue'
colour1 = 'green'
print("Is colour0 the same as colour1?")
print()

<a id='LogicalOperators'></a>
### Logical Operators

The comparisons we have looked at so far consider two variables.

*Logical operators*:

> ```python 
  and
  or
  not
  ```
  
allow us to make multiple comparisons at the same time.





The code
```python
X and Y
```
will evaluate to `True` if statement `X` *and* statement `Y` are both true.

Otherwise will evaluate to `False`. 



The code
```python
X or Y
```
will evaluate to `True` if statement `X` *or* statement `Y` is true. 

Otherwise will evaluate to `False`.

__Examples:__

$10 < 9$   &nbsp; &nbsp;&nbsp; &nbsp;  is false

$15 < 20$  &nbsp; &nbsp;                is true

print(10 < 9 and 15 < 20)

print(10 < 9 or 15 < 20)

Guess the answer (`True` or `False`):

# print(1 < 2 and 3 < 4)

# print(1 < 2 or 4 < 3)

# print(1 < 2 and 4 < 3)

In Python, the 'not' operator negates a statement, e.g.:

a = 12
b = 7
print(a < b)
print(not a < b)

<a id='TimeTelling'></a>
### Time-telling Example

Let's write a simple computer program that uses these comparison and logical operators.

Based on the current time of day, the program will answer two questions:

>__Is it lunchtime?__

>`True`

if it is lunch time.

<br>

>__Is it time for work?__

>`True`

if it is `not`:
- before work (`time < work_starts`)
- after work (`time > work_ends `)
- lunchtime (the previous question assigns the value `True` or `False` to variable `lunchtime`).

# Example : Time-telling program

time = 9.00          # current time

work_starts = 8.00    # time work starts 
work_ends =  17.00    # time work ends

lunch_starts = 13.00  # time lunch starts
lunch_ends =   14.00  # time lunch ends

# lunchtime if the time is between the start and end of lunchtime


# work_time if the time is not...
# ... before work
# ... or after work
# ... or lunchtime            
                 

print("Is it work time?")


print("Is it lunchtime?")



# Example : Time-telling program
# Example solution

time = 13.05          # current time

work_starts = 8.00    # time work starts 
work_ends =  17.00    # time work ends

lunch_starts = 13.00  # time lunch starts
lunch_ends =   14.00  # time lunch ends

# lunchtime if the time is between the start and end of lunchtime
lunchtime = time >= lunch_starts and time < lunch_ends

# work_time if the time is not...  
work_time = not (   time < work_starts     # ... before work
                 or time > work_ends       # ... or after work
                 or lunchtime)             # ... or lunchtime
                 

print("Is it lunchtime?")
print(lunchtime)

print("Is it work time?")
print(work_time)


(Solution in 01a_BasicOperators_DataTypes_SOLS.ipynb)

If we change the value of `time`, the program output changes. 

__Try it yourself__

Click on the cell containing the time-telling program to select it.

Change the value of variable `time` to a value that is:
 - before work
 - during work 
 - during lunchtime 
 - after work
 
 
Each time you change the value of `time` re-run the cell by pressing "shift" + "enter" to check if the answer is as you expect; lunchtime, work-time or neither. 

Note that the comparison operators (`>=`, `<=`, `<` and `>`) are evaluated before the Boolean operators (`and`, `or`).
<a id='OperatorPrecedence'></a>
### Operator Precedence


> 1. Parentheses
1. Exponents 
1. Multiplication, Division, Floor Division and Modulo (left to right)
1. Addition and Subtraction (left to right)
1. Comparison Operators (left to right)
1. Boolean not
1. Boolean and
1. Boolean or

a = 3 + 1 < 4 or 3 * 1 < 4

a = ((3 + 1) < 4) or ((3 * 1) < 4)

Both expressions show the same equation but the second is more __readable__.  

<a id='StackingBooleanOperators'></a>
###  Stacking Boolean Operators


Extract from time-telling program:

```python

time = 13.05          # current time
lunch_starts = 13.00  # time lunch starts
lunch_ends =   14.00  # time lunch ends

lunchtime = time >= lunch_starts and time < lunch_ends

print("Is it lunchtime?")
print(lunchtime)

```

We can rewrite the line: `lunchtime = time >= lunch_starts and time <= lunch_ends` 
<br> to *stack* the logical operations.  

# Extract from time-telling program

time = 13.05          # current time
lunch_starts = 13.00  # time lunch starts
lunch_ends =   14.00  # time lunch ends

lunchtime = lunch_starts <= time < lunch_ends

print("Is it lunchtime?")
print(lunchtime)

<a id='Types'></a>
## Types
All variables have a 'type', which indicates what the variable is, e.g. a number, a string of characters, etc. 



Type is important because it determines:
 - how a variable is stored
 - how it behaves when we perform operations on it
 - how it interacts with other variables. 

e.g.multiplication of two real numbers is different from multiplication of two complex numbers.

<a id='Introspection'></a>
### Introspection 

We can check a variable's type using *introspection*. 

To check the type of a variable we use the function `type`.

x = True
print(type(x))

a = 1
print(type(a))

a = "1"
print(type(a))

a = 1.0
print(type(a))

__Note__ that `1`, `1.0` and `"1"` have different *types*.

Complete the cell in your interactive textbook to find the `type` of `a` when it is written as shown below:

a = 1

a = 1.0

What is the first type? What is the second type? 

 - __bool__ means __Boolean__ variable.
 - __str__ means __string__ variable. 
 - __int__ means __integer__ variable.
 - __float__ means __floating point__ variable. 

This distinction is very important for numerical computations.

We will look at the meaning of these different types next...

<a id='Booleans'></a>
### Booleans
A type of variable that can take on one of two values - true or false.  This is the simplest type.

a = True
b = False

# test will = True if a or b = True
test = a or b  

print(test)
print(type(test))

##### Note: We can use a single instance of the print function to display multiple pieces of information if we sperate them by commas.

e.g. `print(item_1, item_2)`


print(test, type(test))

__Re-cap: what does a evaluate to? (`True` or `False`)__

a = (5 < 6 or 7 > 8)
print(a)

<a id='Strings'></a>
### Strings

A string is a collection of characters.    


A string is created by placing the characters between quotation marks. 

You may use single or double quotation marks; either is fine e.g.

    my_string = 'This is a string.'
    
or

    my_string = "This is a string."

__Example:__ Assign a string to a variable, display the string, and then check its type:

my_string = "This is a string."

print(my_string)

print(type(my_string))

We can perform many different operations on strings. 

__Example__: Extract a *single* character as a new string:

> *__NOTE:__ Python counts from 0.*

my_string = "This is a string."

# Store the 3rd character of `my_string` as a new variable
s = my_string[2]

print(s)

print(type(s))

The number that describes the position of a character is called the *index*.

What is the character at index 4?

What is the index of the *second* i character?

my_string = "This is a string."

my_string[4]

This shows that we count spaces as characters.

__Try it yourself__. 

`my_string = "This is a string."`

In the cell provided in your textbook:

 - store the 4th character as a new variable
 - print the new variable
 - check that it is a string

# Store the 4th character as a new variable

# Print the new variable

# Check the type of the new variable

We can extract a *range of* characters as a new string by specifiying the index to __start__ at and the index to __stop__ at:


my_string = "This is a string."

# Store the first 6 characters
s = my_string[0:6]

# print 
print(s)

# check type
print(type(s))

$$
\underbrace{
\underbrace{t}_{\text{0}} \
\underbrace{h}_{\text{1}}\
\underbrace{i}_{\text{2}}\
\underbrace{s}_{\text{3}}\
\underbrace{}_{\text{4}}\
\underbrace{i}_{\text{5}}\
}_{\text{s}}
\underbrace{s}_{\text{6}}\
\underbrace{}_{\text{7}}\
\underbrace{a}_{\text{8}}\
\underbrace{}_{\text{9}}\
\underbrace{s}_{\text{10}}\
\underbrace{t}_{\text{11}}\
\underbrace{r}_{\text{12}}\
\underbrace{i}_{\text{13}}\
\underbrace{n}_{\text{14}} \
\underbrace{g}_{\text{15}} \
\underbrace{.}_{\text{16}} \
$$

__Note:__ 
 - The space between the first and second word is counted as the 5th character. 
 - The "stop" value is not included in the range. 

# Store the last 4 characters and print
s = my_string[-4:]
print(s)

$$
my\_string = 
\underbrace{t}_{\text{-17}} \
\underbrace{h}_{\text{-16}}\
\underbrace{i}_{\text{-15}}\
\underbrace{s}_{\text{-14}}\
\underbrace{}_{\text{-13}}\
\underbrace{i}_{\text{-12}}\
\underbrace{s}_{\text{-11}}\
\underbrace{}_{\text{-10}}\
\underbrace{a}_{\text{-9}}\
\underbrace{}_{\text{-8}}\
\underbrace{s}_{\text{-7}}\
\underbrace{t}_{\text{-6}}\
\underbrace{r}_{\text{-5}}\
\underbrace{
\underbrace{i}_{\text{-4}}\
\underbrace{n}_{\text{-3}} \
\underbrace{g}_{\text{-2}} \
\underbrace{.}_{\text{-1}} \
}_{\text{s}}
$$

__Note:__ 
 - The second value in this range is empty.
 - This means the range ends at the end of the string.

__Try it yourself.__ 

In the cell provided in your textbook:

  - store the last 6 characters
  - print your new variable



# Store the last 6 characters as a new variable

# Print the new varaible

In the next cell provided:
 - store 6 characters, starting with the 2nd character; "his is"
 - print your new variable

# Store 6 characters, starting with "h"
print(my_string[1:7])
print(my_string[-16:-10])

# Print the new varaible

Is there an alternative way of extracting the same string?

__Example:__ Add strings together. 

start = "Py"

end = "thon"

word = start + end

print(word)

__Example:__ Add a section of a string to a section of another string:

start = "Pythagoras"

end = "marathon"

word = start[:2] + end[-4:]

print(word)

__Note__: We can use a blank space __or__ a 0 to index the first character; either is OK.

__Try it yourself:__ 
In the cell below add the variables `start` and `end` to make a sentence.

start = "My name is"

end = "Hemma"

# Add start and end to make a new variable and print it

Notice that we need to add a space to seperate the words "is" and "Hemma". 
We do this using a pair of quotation marks, seperated by a space. 

sentence = start + " " + end
# print(sentence)

<a id='NumericTypes'></a>
### Numeric Types
Numeric types are particlarly important when solving scientific and engineering problems. 



Python 3 has three numerical types:

- integers (`int`)
- floating point numbers (`float`)
- complex numbers (`complex`)

__Integers:__ Whole numbers. <br>
__Floating point:__ Numbers with a decimal place.<br>
__Complex numbers:__ Numbers with a real and imaginary part.<br>

Python determines the type of a number from the way we input it.

e.g. It will decide that a number is an `int` if we assign a number with no decimal place:


 


__Try it for yourself__ 

In the cell provided in your textbook:

 - Create a variable with the value 3.1
 - Print the variable type  
 - Create a variable with the value 2
 - Print the variable type

# Create a variable with the value 3.1


# Print the variable type


# Create a variable with the value 2


# Print the variable type 


What type is the first variable?

What type is the second variable?

__How could you re-write the number 2 so that Python makes it a float?__

Try changing the way 2 is written and run the cell again to check that the variable type has changed. 

<a id='Integers'></a>
### Integers
 - Integers (`int`) are whole numbers.
 - They can be postive or negative. 
 - Integers should be used when a value can only take on a whole number <br> e.g. the year, or the number of students following this course. 

<a id='FloatingPoint '></a>
### Floating Point  

Numbers that have a decimal point are automatically stored using the `float` type. 

A number is automatically classed as a float:
- if it has a decimal point
- if it is written using scientific notation (i.e. using e or E)...



<a id='ScientificNotation'></a>
### Scientific Notation 
In scientific notation, the letter e (or E) symbolises power of ten in the exponent. 

For example:

$$
10.45\textrm{e}2 = 10.45 \times 10^{2} = 1045
$$

$$
1.045\textrm{e}3 = 1.045 \times 10^{3} = 1045
$$

Examples using scientific notation.

a = 2e0
print(a, type(a))

b = 2e3
print(b)

c = 2.1E3
print(c)

<a id='Round'></a>
### Rounding floating point numbers.

You can round your answer to a defined number of digits after the decimal point using the `round` function:
<br>https://docs.python.org/3/library/functions.html#round


a = 0.768567

print(round(a,2))
print(round(a,3))
print(round(a,4))

__Try it yourself__ 

In the cell provided in your textbook:

- create a floating point variable for each number shown using scientific notation.
- print each variable to check it matches the number given in the comment. 

# Create a variable with value 62

# Print the variable

# Create a variable with value 35,000

# Print the variable

# Are there any other ways you could have expressed this? 

What alternative ways can be used to express 35,000?

<a id='ComplexNumbers'></a>
### Complex Numbers
Complex numbers have real and imaginary parts. 

We can declare a complex number in Python by adding `j` or `J` after the complex part of the number:

&nbsp; &nbsp; __Standard mathematical notation.__ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;__Python notation__

&nbsp; &nbsp; &nbsp; &nbsp;
$ a = \underbrace{3}_{\text{real part}} + \underbrace{4j}_{\text{imaginary part}} $        &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
`a = 3 + 4j` &nbsp; &nbsp; __or__ &nbsp; &nbsp; `a = 3 + 4J`

b = 4 - 3j
print(b, type(b))

<a id='Casting'></a>
## Type Conversions (Casting)

We often want to change between types. 

Sometimes we need to make sure two variables have the same type in order to perform an operation on them. 

Sometimes we recieve data of a type that is not directly usable by the program.

This is called *type conversion* or *type casting*. 


### Automatic Type Conversion
If we add two integers, the results will be an integer:

a = 4     # int
b = 15    # int

c = a + b

# print(c, type(c))

However, if we add an int and a float, the result will be a float:

a = 4     # int
b = 15.0  # float

c = a + b

# print(c, type(c))

If we divide two integers, the result will be a `float`:

a = 16  # int
b = 4   # int

c = a / b

# print(c, type(c))

When dividing two integers with floor division (or 'integer division') using `//`, the result will be an `int` e.g.

a = 16   # int
b = 3    # int

c = a // b

# print(c, type(c))

In general:
 - operations that mix an `int` and `float` will generate a `float`.
 - operations that mix an `int` or a `float` with `complex` will generate a `complex` type. 
 
 
If in doubt, use `type` to check.  

### Explicit Type Conversion

We can explicitly change (or *cast*) the type.

To cast variable a as a different type, write the name of the type, followed by the variable to convert in brackets. 

__Example: Cast from an int to a float:__

a = 1

a = float(a)

print(a, type(a))

# If we use a new variable name the original value is unchanged.

a = 1

b = float(a)      

# print(a, type(a))
# print(b, type(b))

# If we use the original name, the variable is updated. 

a = 1

a = float(a)       

# print(a, type(a))

__Try it yourself.__

In the cell provided: 

- cast variable `a` from a float back to an int. 
- print variable `a` and its type to check your answer 

# cast a as an int

# print a and its type 

##### Note: Take care when casting as the value of the variable may change as well as the type.

To demonstrate this we will complete a short exercise together...



In the cell below:
1. cast `i` as an `int` and print `i`.
1. cast `i` back to a `float` and print `i`.

i = 1.3                  # float
print(i, type(i))

# cast i as an int and print it
i = int(i)
print(i)

i = float(i)
print(i)

What has happened to the original value of `i`?



Note that rounding is applied when converting from a `float` to an `int`; the values after the decimal point are discarded. 

This type of rounding is called 'round towards zero' or 'truncation'.

A common task is converting numerical types to-and-from strings. 

Examples:
 - Reading a number from a file where it appears as as a string
 - User input might be given as a string. 

__Example: Cast from a float to a string:__


a = 1.023

b = str(a)

# print(b, type(b))

__Example: Cast from a string to a float:__

It is important to cast string numbers as either `int`s or `float`s for them to perform correctly in algebraic expressions.

Consider the example below:

a = "15.07"
b = "18.07"

print("As string numbers:")
print("15.07 + 18.07 = ", a + b)
      
print("When cast from string to float:")
print("15.07 + 18.07 = ", float(a) + float(b))


Note from the cell above that numbers expressed as strings can be cast as floats *within* algebraic expressions.

Only numerical values can be cast as numerical types.
e.g. Trying to cast the string `four` as an integer causes an error:

f = float("four")

<a id='Summary'></a>
# Summary

 - We can perform simple *arithmetic operations* in Python (+, -, $\times$, $\div$.....)
 - We can *assign* values to variables.
 - Expressions containing multiple operators obey precedence when executing operations.
 
 


 - Every variable has a type (`int`, `float`, `string`....).
 - A type is automatically assigned when a variable is created. 
 - Python's `type()` function can be used to determine the type of a variable.
 - The data type of a variable can be converted by casting (`int()`, `float()`....) 

- *Comparison operators* (==, !=, <, >....) compare two variables.
- The outcome of a comparison is a *Boolean* (True or False) value.
- *Logical operators* (`and`, `or`) compares the outcomes of two comparison operations.
- The outcome of a logical operation is a *Boolean* (True or False) value.
- The logical `not` operator returns the inverse Boolean value of a comparison.

<a id='ReviewExercises'></a>
## Review Exercises

Here are a series of short problems for you to practise each of the new Python skills that you have learnt today. 


### Review Excercise: Gravitational Potential
The gravitational potential, $V$, of a particle of mass $m$ at a distance $r$ from a body of mass $M$, is:

$$
V = \frac{G M m}{r}
$$

In the cell below, solve for $V$ when:

$G$ = *gravitational constant* = $6.674 \times 10^{-11} \textrm{Nm}^{2}\textrm{kg}^{-2}$.

$M = 1.65 \times 10^{12}\textrm{kg}$

$m = 6.1 \times 10^2\textrm{kg}$

$r = 7.0 \times 10^3\textrm{kg}$

Assign variables for $G, M, m$ and $r$ before solving. 
<br>Express the numbers using __scientific notation__.

<a href='#ScientificNotation'>Jump to Scientific Notation</a>

# Gravitational Potential

# Example Solution

G = 6.674 * 10e-11
M = 1.65 * 10e12
m = 6.1 * 10e2
r = 7.0 * 10e3

V = (G * M * m) / r

print(V)

### Review Exercise: Volume of a Cone
The volume of a cone is:
$$
V = \frac{1}{3}(base \ area)\times(perpendicular \ height)
$$

![title](img/cone.png)

In the cell below, find the internal volume of a cone of internal dimensions:

base radius, $r = 5cm$

perpendicular height, $h = 15cm$

Assign variables for $r$ and $h$ before solving.

pi = 3.142
# Internal volume

The cone is held upside down and filled with liquid.

The liquid is then transferred to a hollow cylinder.

Base radius of cylinder, $r_c = 4cm$.

<img src="img/cone-cyl.gif" alt="Drawing" style="width: 200px;"/>

The volume of liquid in the cylinder is:

$V = (base \ area)\times(height \ of \ liquid)$


In the cell below, find the height of the liquid in the cylinder?

Assign a variables for $r_c$ before solving.

# H = height of liquid in the cylinder


The total height of the cyclinder, $H_{tot}$ is 10cm.

In the cell below, use a __comparison operator__ to show if the height of the liquid, $H$, is more than half the total height of the cylinder.  

<a href='#ComparisonOperators'>Jump to Comparison Operators</a>

# Is the height of the liquid more than half the total height of the cylinder?

Lastly, go back and change the radius of the __cone__ to 2.5cm. 

Re-run the cells to observe how you can quickly re-run calculations using different initial values. 

### Review Exercise: Manipulating Strings
<a href='#Strings'>Jump to Strings</a>

__(A)__ 
In the cell below, print a new string whose:
 - first 3 letters are the last 3 letters of `a` 
 - last 3 letters are the first 3 letters of `b` 

a = "orangutans"
b = "werewolves"

__(B)__ 

In the cell below, use `c` to make a new string that says: `programming`.

c = "programme"

__(C)__ 

In the cell below, __cast__ `d` and `e` as a different type so that:

`f` = (numerical value of `d`) +  (numerical value of `e`)


using standard arithmetic. 

<a href='#Casting'>Jump to Type Conversion (Casting)'</a>

Print `f`

d = "3.12"
e = "7.41"


Use __shortcut notation__ to update the value of `f`.
The new value of f should equal the __remainder (or modulo)__ when f is divided by 3.

<a href='#Shortcuts'>Jump to Shortcuts</a>

# What is the remainder (modulo) when f is divided by 3

In the cell below, change the type of the variable f to ab integer.  

<a href='#Casting'>Jump to Type Conversion (Casting)'</a>

# f expressed as an integer<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11110781902758436, 'fraction_numerical': 0.01742170602352523, 'mean_word_length': 3.51894497255322, 'pattern_counts': {'":': 0, '<': 137, '<?xml version=': 0, '>': 131, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '283986', 'license': 'MIT', 'n_tokens_mistral': 11645, 'n_tokens_neox': 10767, 'n_words': 4863, 'path': '.ipynb_checkpoints 2/01Primer__Operators_DataTypes_ControlFlow-checkpoint.ipynb', 'repo_name': 'hphilamore/ILAS_PyEv2019', 'size': '33751'}