# Working with variables

## Working with numbers

### Convert strings into integer values

The input function returns a string of text, which is fine if we just want to read names. However, it is not so useful if we want to read in numbers. For instance, we might want to modify the egg timer we created in Chapter 2 so that the user can enter the number of seconds that the timer must run. This would allow the user to customize their egg from raw (0 seconds) to hard boiled (600 seconds). Python provides a function called, not surprisingly, int. The int function accepts a string and returns the number in that string.

The first statement uses the input function to read in a string from the user. The second statement uses the int function to convert this string into a number that can be used to set the length of time the program sleeps while the egg is cooked. The final egg timer program looks like this:

```# EG4-02 User Configurable Egg Timer

import time

time_text = input('Enter the cooking time in seconds: ')

time_int = int(time_text)

print('Put the egg in boiling water now')

time.sleep(time_int)

print('Take the egg out now')```

You could use this program anywhere you want to have a configurable timer or alarm. You just change the messages displayed to the user.

### Whole numbers and real numbers

We know that Python is aware of two fundamental kinds of data—text data and numeric data. Now we need to delve a little deeper into how numeric data works. There are two kinds of numeric data—whole numbers and real numbers. Whole numbers have no fractional part. Up until now, every program that we have written has made use of whole numbers. A computer stores the value of a whole number exactly as entered. Real numbers, on the other hand, have a fractional element that can’t always be held accurately in a computer.

As a programmer, you need to choose which kind of number you want to use to store each value.

### Real numbers and floating-point numbers

Real number types have a fractional part, which is the part of the number after the decimal point. Real numbers are not always stored exactly as they are entered into Python programs. Numbers are mapped to computer memory in a way that stores a value that is as close as possible to the original. The stored data is often called a floating-point representation. You can increase the accuracy of the storage process by using larger amounts of computer memory, but you are never able to hold all real values precisely.

This is not a problem, however. Values such as pi can never be held exactly because they “go on forever.” (I’ve got a book that contains the value of pi to 1 million decimal places, but I still can’t say that this is the exact value of pi. All I can say is that the value in the book is many times more accurate than anyone will ever need.)

When considering how numbers are stored, we need to think about range and precision. Precision sets out how precisely a number is stored. A particular floating-point variable could store the value 123456789.0 or 0.123456789, but it can’t store 123456789.123456789 because it does not have enough precision to hold 18 digits. The range of floating-point storage determines how far you can “slide” the decimal point around to store very large or very small numbers. For example, we could store the value 123,456,700, or we can store 0.0001234567. For a floating-point number in Python, we have 15 to 16 digits of precision, and we can slide the decimal point 308 places to the right (to store huge numbers) or 324 places to the left (to store tiny numbers).

The mapping of real numbers to a floating-point representation does bring some challenges when using computers. It turns out that a simple fraction such as 0.1 (a tenth) cannot be held accurately by a computer because of the way values are held. The value stored to represent 0.1 will be very close to that value, but not the same. This has implications for the way we write programs.

You might think that your all-powerful computer should be able to hold all values precisely. It comes as a bit of a shock to discover that this is not true and that a simple pocket calculator can outperform your powerful PC.

However, this lack of accuracy is not a problem in programming because we don’t usually have incoming data that is particularly precise anyway. For example, if I refine my hair counting device to measure hair length, it would be very difficult for me to measure hair length with more than a tenth of an inch (2.4 millimeters) of accuracy. For hair data analysis, we need only around three or four digits of accuracy. It is very unlikely that you will ever process any data that requires the 15 digits that Python can give you.

It is also worth noting at this point that these issues have nothing to do with Python. Most, if not all, modern computers store and manipulate floating-point values using a standard established by the Institute of Electronic and Electrical Engineers (IEEE) in 1985. All programs that run on a computer will manipulate values in the same way, so floating-point numbers in Python are no different from those in any other language.

The only difference between Python floating-point values and those in other languages is that a floating-point variable in Python occupies 8 bytes of memory, which is twice the size of the float type in the languages C, C++, Java, and C#. A Python floating-point variable equates with a double precision value in those languages.

If you really, really want to store things with even more accuracy (and I think this is terribly unlikely), you should look at the decimal and fraction libraries supplied with Python.

### Convert strings into floating-point values

The float function is used to convert values into floating-point values. A program can use the float function to convert a string of text into a floating-point value. It works in the same way as the int function:

The statements above could form the basis of an ultra-precise version of the egg timer program that lets the user time their egg to a fraction of a second. You can find this program in EG4-03 Ultra-precise Egg Timer.

The program works because the sleep function accepts a floating-point value for the duration of the delay.

`time.sleep(time_float)`

This means we can use the sleep function to create very short delays in programs.

The float function can also be used to convert an integer value into a floating-point value. This can be useful in older Python programs as a way of forcing the correct behavior of the divide operator (see the “What Could Go Wrong: Python Programs and Integer Division” discussion above).

`z = float(1)`

In the statement above, the variable z will be of type float, even though the value being assigned is an integer.

The behavior of float might seem rather familiar. This is because it behaves similarly to the int function, except that it delivers floating-point results.

### Perform calculations

In Chapter 2, we saw that Python expressions are made up of operators and operands. The operators identify actions to be performed, and the operands are worked on by the operators. Now we can add a bit more detail to this explanation. Expressions can be as simple as a single value or as complex as a large calculation. Here are a few examples of numeric expressions:

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

These expressions are evaluated by Python working from left to right, just as you would read them yourself. Again, just as in traditional math, multiplication and division are performed first, followed by addition and subtraction.

Python achieves this order by giving each operator a priority. When it works out an expression, it finds all the operators with the highest priority and applies them first. It then looks for the operators next in priority, and so on, until the result is obtained. The order of evaluation means that the expression 2 + 3 * 4 will calculate to 14, not 20.

If you want to force the order in which an expression evaluates, you can put parentheses around the elements of the expression you want to evaluate first, as in the final example above. You can also put parentheses inside parentheses if you want—provided you make sure that you have as many opening parentheses as closing ones. Being a simple soul, I tend to make things very clear by putting parentheses around everything.

It is probably not worth getting too worked up about expression evaluation. Generally speaking, things tend to be evaluated how you would expect.

Here is a list of some other operators, with descriptions of what they do, and their precedence (priority). The operators are listed with the highest priority first.

 OPERATOR HOW IT’S USED - Unary minus, the minus that Python finds in negative numbers, * Multiplication. Note the use of the * rather than the more mathematically correct but confusing x. / Division, because of the difficulty of drawing one number above another during editing, we use this character instead. + Addition. - Subtraction. Note that we use the same character as for unary minus.

This is not a complete list of the operators available, but it will do for now. Because these operators work on numbers, they are often called numeric operators. However, one of them, the + operator, can be applied between strings, as you’ve already seen.

### Convert between float and int

Sometimes a program might need to convert between floating-point and integer values. A program can do this by using the int function. We’ve already used the int function to convert strings of text into integer values. To do this, we used the version of the int function that accepts a string as an input:

`i = int('25')`

If the int function is supplied with a string containing a number, it will read that number out of the string. In other words, the statement above will result in the variable i containing the integer value 25.

Programs can also use the int function to convert a value from floating point to integer.

`i = int(2.9)`

This would result in the creation of an integer variable called i that contains the value 2. You might ask why the value if i is not set to 3, because it seems reasonable to “round” a value to the nearest integer. However, in this respect Python is not reasonable. Floating-point values are always truncated. In other words, the fractional part is always discarded.