# Fun with Numbers¶

This notebook demonstrates the basic numeric data types and mathematical operations in Python.

## Integers¶

Integers are whole numbers, including zero and negative whole numbers.

### Literals¶

When we write a piece of data directly in our code, this is called a **literal**: we are literally writing the data.

We write an integer in Python by writing it out in decimal format:

```
27
```

27

Python also accepts hexadecimal (base-16) integer literals:

```
0x1B
```

27

Note, though, that Jupyter prints the number out in decimal.

We can also write octal literals, but these aren't very common:

```
0o273
```

187

There is no limit in Python to the size of an integer, so long as it fits in memory:

```
1304710347018840570104710740571080012034901
```

1304710347018840570104710740571080012034901

If a number fits in a C `long`

, Python will use one, but if it does not it will use an arbitrary-sized integer representation.

NumPy and Pandas, however, will typically store integers in a fixed size. A NumPy integer array has a fixed width (defaulting to 64 bits, `int64`

), and cannot store values that exceed its specified size.

### Variables¶

As discussed in the videos, we can store values in variables:

```
x = 27
```

And get those values back:

```
x
```

27

## Floating-Point Numbers¶

Python supports floating-point numbers for ‘decimal’ (really floating-point) arithmetic. They are the usual format for computations approximating real numbers.

```
3.7
```

3.7

We can also write them with exponential notation:

```
6.02e23
```

6.02e+23

This means $6.02 \times 10^{23}$.

Negative exponents are also supported:

```
3.3356e-9
```

3.3356e-09

## Arithmetic Operations¶

Python defines the usual arithmetic operations — `+`

, `-`

, `*`

, `/`

— in a way that maps as closely as possible to their abstract mathematical notations.

We write them using the corresponding operators:

```
8 + 20
```

28

```
9 * 1.2
```

10.799999999999999

For `+`

, `-`

, and `*`

, if all the operands are integers, the result is an integer:

```
3 + 4
```

7

If any operand is floating-point, the result is floating-point:

```
1.0 + 2
```

3.0

We can see that this is a floating-point number, because Python includes `.0`

, even though it is `3`

. We can double-check, though, with the `type`

function:

```
type(1.0 + 2)
```

float

Division (`/`

) always returns a floating-point value, even if the operands are integers:

```
4 / 2
```

2.0

```
2 / 4
```

0.5

If you want C- or Java-style division, where the result is truncated down, use the *floor division* operator `//`

:

```
5 // 2
```

2

Python implements the conventional order of operations from arithmetic:

```
4 * 2 + 3
```

11

Parentheses let us specify a different order:

```
4 * (2 + 3)
```

20

The full list of Python operators, and their precedence, is in the Python reference manual.

## You Try¶

What is 5 plus 7?

```
```

What is 5 divided by the sum of 3 and 4?

```
```

## No Magic¶

A note for those who are relatively new to programming: things are probably far *less* magic or special than they appear.

Python has a concept of an *expression*. An expression can be any of several things:

- A literal (
`42`

) - A variable reference (
`x`

) - A function call (
`f(x)`

) - The result of an operator (
`3 + y`

) - Parentheses around an expression (
`(2 + 4)`

)

It generally *does not matter* what kind of expression you have — a Python context that takes an expression will take any kind of expression, so long as its result is of the correct type (e.g. you can't divide a number by a string).

So, for example, the two sides of a `+`

operator can be any expression: a literal, variable, function call, or whatever. There's nothing special about particular kinds of expressions in the overwhelming majority of contexts. The only thing that matters for determining if an particular kind of expression is valid in a particular context is whether it returnds the right type of variable.

```
```