# 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.

## 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.