Python basics 3 - floats

Real numbers

Python saves the real numbers (floating point numbers) in 64 bit of information divided by sign, exponent and mantissa (also called significand). Let’s see an example:

[2]:
3.14
[2]:
3.14
[3]:
type(3.14)
[3]:
float

WARNING: you must use the dot instead of comma!

So you will write 3.14 instead of 3,14

Be very careful, whenever you copy numbers from documents in latin languages, they might contain very insidious commas!

Scientifical notation

Whenever numbers are very big or very small, to avoid having to write too many zeros it is convenient to use scientifical notation with the e like \(xen\) which multiplies the number x by \(10^n\)

With this notation, in memory are only put the most significative digits ( the mantissa ) and the exponent, thus avoiding to waste space.

[4]:
75e1
[4]:
750.0
[5]:
75e2
[5]:
7500.0
[6]:
75e3
[6]:
75000.0
[7]:
75e123
[7]:
7.5e+124
[8]:
75e0
[8]:
75.0
[9]:
75e-1
[9]:
7.5
[10]:
75e-2
[10]:
0.75
[11]:
75e-123
[11]:
7.5e-122

QUESTION: Look at the following expressions, and try to find which result they produce (or if they give and error):

  1. print(1.000.000)
    
  2. print(3,000,000.000)
    
  3. print(2000000.000)
    
  4. print(2000000.0)
    
  5. print(0.000.123)
    
  6. print(0.123)
    
  7. print(0.-123)
    
  8. print(3e0)
    
  9. print(3.0e0)
    
  10. print(7e-1)
    
  11. print(3.0e2)
    
  12. print(3.0e-2)
    
  13. print(3.0-e2)
    
  14. print(4e2-4e1)
    

Too big or too small numbers

Sometimes calculations on very big or extra small numbers may give as a result math.nan (Not a Number) or math.inf. For the moment we just mention them, you can find a detailed description in the Numpy page

Exercise - circle

✪ Calculate the area of a circle at the center of a soccer ball (radius = 9.1m), remember that \(area=pi*r^2\)

Your code should print as result 263.02199094102605

Show solution
[12]:

263.02199094102605

Note that the parenthesis around the squared r are not necessary because the power operator has the precedence, but they may help in augmenting the code readability.

We recall here the operator precedence:

Operator

Description

**

Power (maximum precedence)

+ -

unary plus and minus

* / // %

Multiplication, division, integer division, modulo

+ -

Addition and subtraction

<= < > >=

comparison operators

== !=

equality operators

not or and

Logical operators (minimum precedence)

Exercise - fractioning

✪ Write some code to calculate the value of the following formula for x = 0.000003, you should obtain 2.753278226511882

\[\Large -\frac{\sqrt{x+3}}{\frac{(x + 2)^3}{\log{x}}}\]
Show solution
[13]:
x = 0.000003

# write here


[13]:
2.753278226511882

Exercise - summation

Write some code to calculate the value of the following expression (don’t use cycles, write down all calculations), you should obtain 20.53333333333333

\[\normalsize \sum_{j=1}^{3}{\frac{j^4}{j + 2}}\]
Show solution
[14]:
# write here


[14]:
20.53333333333333

Reals - conversion

If we want to convert a real to an integer, several ways are available:

Function

Description

Mathematical symbol

Result

math.floor(x)

round x to inferior integer

\[\lfloor{8.7}\rfloor\]

8

int(x)

round x to inferior integer

\[\lfloor{8.7}\rfloor\]

8

math.ceil(x)

round x to superior integer

\[\lceil{5.3}\rceil\]

6

round(x)

round x to closest integer

\[\lfloor{2.49}\rceil\]

2

\[\lfloor{2.51}\rceil\]

3

QUESTION: Look at the following expressions, and for each of them try to guess which result it produces (or if it gives an error).

  1. math.floor(2.3)
    
  2. math.floor(-2.3)
    
  3. round(3.49)
    
  4. round(3.51)
    
  5. round(-3.49)
    
  6. round(-3.51)
    
  7. math.ceil(8.1)
    
  8. math.ceil(-8.1)
    

QUESTION: Given a float x, the following formula is:

math.floor(math.ceil(x)) == math.ceil(math.floor(x))
  1. always True

  2. always False

  3. sometimes True and sometimes False (give examples)

Show answer

QUESTION: Given a float x, the following formula is:

math.floor(x) == -math.ceil(-x)
  1. always True

  2. always False

  3. sometimes True and sometimes False (give examples)

Show answer

Exercise - Invigorate

✪ Excessive studies lead you search on internet recipes of energetic drinks. Luckily, a guru of nutrition just posted on her Instagram channel @HealthyDrink this recipe of a miracle drink:

Pour in a mixer 2 decilitres of kiwi juice, 4 decilitres of soy sauce, and 3 decilitres of shampoo of karitè bio. Mix vigorously and then pour half drink into a glass. Fill the glass until the superior deciliter. Swallow in one shot.

You run shopping the ingredients, and get ready for mixing them. You have a measuring cup with which you transfer the precious fluids, one by one. While transfering, you always pour a little bit more than necessary (but never more than 1 decilitre), and for each ingredient you then remove the excess.

  • DO NOT use subtractions, try using only rounding operators

Example - given:

kiwi = 2.4
soia = 4.8
shampoo = 3.1
measuring_cup = 0.0
mixer = 0
glass = 0.0

Your code must print:

I pour into the measuring cup 2.4 dl of kiwi juice, then I remove excess until keeping 2 dl
I transfer into the mixer, now it contains 2.0 dl
I pour into the measuring cup 4.8 dl of soia, then I remove excess until keeping 4 dl
I transfer into the mixer, now it contains 6.0 dl
I pour into the measuring cup 3.1 dl of shampoo, then I remove excess until keeping 3 dl
I transfer into the mixer, now it contains 9.0 dl
I pour half of the mix ( 4.5 dl ) into the glass
I fill the glass until superior deciliter, now it contains: 5 dl
Show solution
[15]:
import math

kiwi = 2.4
soy = 4.8
shampoo = 3.1
measuring_cup = 0.0
mixer = 0.0
glass = 0.0


# write here


I pour into the measuring cup 2.4 dl of kiwi juice, then I remove excess until keeping 2 dl
I transfer into the mixer, now it contains 2.0 dl
I pour into the measuring cup 4.8 dl of soia, then I remove excess until keeping 4 dl
I transfer into the mixer, now it contains 6.0 dl
I pour into the measuring cup 3.1 dl of shampoo, then I remove excess until keeping 3 dl
I transfer into the mixer, now it contains 9.0 dl
I pour half of the mix ( 4.5 dl ) into the glass
I fill the glass until superior deciliter, now it contains: 5 dl

Exercise - roundminder

✪ Write some code to calculate the value of the following formula for x = -5.51, you should obtain 41

\[\large \lvert{\lceil{x}\rceil}\rvert + \lfloor{x}\rceil^2\]
Show solution
[16]:
import math

x = -5.51   # 41
#x = -5.49  # 30

# write here


[16]:
41

Reals - equality

WARNING: what follows is valid for *all* programming languages!

Some results will look weird but this is the way most processors (CPU) operates, independently from Python.

When floating point calculations are performed, the processor may introduce rounding errors due to limits of internal representation. Under the hood the numbers like floats are memorized in a sequence of binary code of 64 bits, according to IEEE-754 floating point arithmetic standard: this imposes a physical limit to the precision of numbers, and sometimes we ight get surprises due to conversion from decimal to binary. For example, let’s try printing 4.1:

[17]:
print(4.1)
4.1

For our convenience Python is showing us 4.1, but in reality in the processor memory ended up a different number! Which one? To discover what it hides, with format function we can explicitly format the number to, for example 55 digits of precision by using the f format specifier:

[18]:
format(4.1, '.55f')
[18]:
'4.0999999999999996447286321199499070644378662109375000000'

We can then wonder what the result of this calculus might be:

[19]:
print(7.9 - 3.8)
4.1000000000000005

We note the result is still different from the expected one! By investigating further, we notice Python is not even showing all the digits:

[20]:
format(7.9 - 3.8, '.55f')
[20]:
'4.1000000000000005329070518200751394033432006835937500000'
[ ]:

What if wanted to know if the two calculations with float produce the ‘same’ result?

WARNING: AVOID == WITH FLOATS!

To understand if the result between the two calculations with the floats is the same, YOU CANNOT use the == operator !

[21]:
7.9 - 3.8 == 4.1    # TROUBLE AHEAD!
[21]:
False

Instead, you should prefer alternative that evaluate if a float number is close to anoter, like for example the handy function math.isclose:

[22]:
import math

math.isclose(7.9 - 3.8, 4.1)   # MUCH BETTER
[22]:
True

By default math.isclose uses a precision of 1e-09, but, if needed, you can also pass a tolerance limit in which the difference of the numbers must be so to be considered equal:

[23]:
math.isclose(7.9 - 3.8, 4.1, abs_tol=0.000001)
[23]:
True

QUESTION: Can we perfectly represent the number \(\sqrt{2}\) as a float?

Show answer

QUESTION: Which of these expressions give the same result?

import math
print('a)', math.sqrt(3)**2 == 3.0)
print('b)', abs(math.sqrt(3)**2 - 3.0) < 0.0000001)
print('c)', math.isclose(math.sqrt(3)**2, 3.0, abs_tol=0.0000001))
Show answer

Exercise - quadratic

✪ Write some code to calculate the zeroes of the equation \(ax^2-b = 0\)

  • Show numbers with 20 digits of precision

  • At the end check that by substituting the value obtained x into the equation you actually obtain zero.

Example - given:

a = 11.0
b = 3.3

after your code it must print:

11.0 * x**2 - 3.3 = 0  per x1 = 0.54772255750516607442
11.0 * x**2 - 3.3 = 0  per x2 = -0.54772255750516607442
Is 0.54772255750516607442 a solution? True
Is -0.54772255750516607442 a solution? True
Show solution
[24]:

a = 11.0
b = 3.3

# write here


Exercise - trendy

✪✪ You are already thinking about next vacations, but there is a big problem: where do you go, if you don’t have a selfie-stick? You cannot leave with this serious anxiety: to uniform yourself to this mass phenomena you must buy the stick which is most similar to others. You then conduct a rigourous statistical survey among turists obssessed by selfie sticks with the goal to find the most frequent brands of sticks, in other words, the mode of the frequencies. You obtain these results:

[25]:
b1,b2,b3,b4,b5 = 'TooManyLikes', 'Boombasticks', 'Timewasters Inc', 'Vanity 3.0','TrashTrend' # brand
f1,f2,f3,f4,f5 = 0.25, 0.3, 0.1, 0.05, 0.3   # frequencies (as percentages)

We deduce that masses love selfie-sticks of the brand 'Boombasticks' and TrashTrend, both in a tie with 30% turists each. Write some code which prints this result:

TooManyLikes is the most frequent? False ( 25.0 % )
Boombasticks is the most frequent? True ( 30.0 % )
Timewasters Inc is the most frequent? False ( 10.0 % )
Vanity 3.0 is the most frequent? False ( 5.0 % )
TrashTrend is the most frequent? True ( 30.0 % )
  • WARNING: your code must work with ANY series of variables !!

Show solution
[26]:

b1,b2,b3,b4,b5 = 'TooManyLikes', 'Boombasticks', 'Timewasters Inc', 'Vanity 3.0','TrashTrend'    # brand

f1,f2,f3,f4,f5 = 0.25, 0.3, 0.1, 0.05, 0.3  # frequencies (as percentages)  False True False False True
# CAREFUL, they look the same but it must work also with these!
#f1,f2,f3,f4,f5 = 0.25, 0.3, 0.1, 0.05, 0.1 + 0.2  #  False True False False True

# write here


Decimal numbers

For most applications float numbers are sufficient, if you are conscius of their limits of representation and equality. If you really need more precision and/or preditability, Python offers a dedicated numeric type called Decimal, which allows arbitrary precision. To use it, you must first import decimal library:

[27]:
from decimal import Decimal

You can create a Decimal from a string:

[28]:
Decimal('4.1')
[28]:
Decimal('4.1')

WARNING: if you create a Decimal from a costant, use a string!

If you pass a float you risk losing the utility of Decimals:

[29]:
Decimal(4.1)  # this way I keep the problems of floats ...
[29]:
Decimal('4.0999999999999996447286321199499070644378662109375')

Operations between Decimals produce other Decimals:

[30]:
Decimal('7.9') - Decimal('3.8')
[30]:
Decimal('4.1')

This time, we can freely use the equality operator and obtain the same result:

[31]:
Decimal('4.1') == Decimal('7.9') - Decimal('3.8')
[31]:
True

Some mathematical functions are also supported, and often they behave more predictably (note we are not using math.sqrt):

[32]:
Decimal('2').sqrt()
[32]:
Decimal('1.414213562373095048801688724')

Remember: computer memory is still finite!

Decimals can’t be solve all problems in the universe: for example,\(\sqrt{2}\) will never fit the memory of any computer! We can verify the limitations by squaring it:

[33]:
Decimal('2').sqrt()**Decimal('2')
[33]:
Decimal('1.999999999999999999999999999')

The only thing we can have more with Decimals is more digits to represent numbers, which if we want we can increase at will until we fill our pc memory. In this book we won’t talk anymore about Decimals because typically they are meant only for specific applications, for example, if you need to perform fincancial calculations you will probably want very exact digits!

Continue

Go on with the challenges