Sitemap
Geek Culture

A new tech publication by Start it up (https://medium.com/swlh).

Numeric Types in Python

--

Photo by Matej Rieciciar on Unsplash

If you’re in States, Happy post 4th of July!

Can’t believe I’m out of school for the past 3 years which also means I haven’t done Maths actively, though it started trailing off slowly after March 2015. I had taken my final formal Math class during winter session of 2015 to complete minor requirement. The class was called Elementary Numerical Theory . The subject made me put humongous winter blizzard events sideway. Those numbers you learn since you can remember your time at schools, are not numbers; they are rich with their properties. Hello prime, pi, gcd, hello to all those succinct formulas that basically lets you know what are the values of the variables of equations like ‘oiler’, oh my. I also learned how those knowledge in numbers were used in the past like in Caesar cipher, and today in modern application such as public, private keys in cryptography. Then I realized that’s why they are called Mathematician; thought came across works of true geniuses. 🪄

I guess Elementary Numerical Theory had different flavor than Calculus, I loved my college Calculus classes though! Once you grasp it, you’ll become a ninja, like my high-school friends — still inspired, where you solve fancy looking equations, and answer would mostly be either 0, 1, or ∞. So grateful to have such wonderful calc profs that even made me to consider making Math as a second major. I liked the flip classroom teaching; I guess I would like remote learning that’s happening during the pandemic as well. I am like 93.999% sure since I voluntary took one of the graduate class remotely. ⚠️ Comfort zone.

Ok, that’s the prequel to the real content Numeric Types in Python. Thank you for bearing with my nostalgic blabbering. Here we go Numeric Types! 🏄🏽‍♀️

In this article we’ll learn about Python implementation of integer numbers Z, rational numbers Q, real numbers R, <strike>complex numbers C</strike>, and boolean truth values.

I am going to talk about small quirks that we may not come across in most everyday scenarios maybe unless we’re working on number sensitive areas such as aerospace engineering.

Integers

Unlike languages like Java where we have byte , short, int , long , integer object can be of variable length; limited by the amount of memory available.

On running the file, we get:

size of integer value 8 is 28 bytes
size of integer value 976562500000000000000000000 is 36 bytes

Constructors and base:

Constructor for an integer is int(x) or int(x, base=10) where default base is 10. We can also pass string representation of a number to get an integer or convert numbers in different bases to integer type.

If we just assign a number to a variable like a=3, under a hood it’ll be calling __int__() dunder method. If you need to know what is a dunder method, I have written an article few weeks ago.

On running the file, we get:

value of a: 5, type = <class 'int'>
value of b: 5, type = <class 'int'>
value of c: 5, type = <class 'int'>
value of d: 5, type = <class 'int'>
value of e: 5, type = <class 'int'>

Different operation on both negative and positive integers.

Press enter or click to view image in full size
operations on integers

Now let’s come to floats… 💨 ☁️

Floats

In Python, it is a default implementation for representing real numbers. Just a recap, real number is of the form p/q where p and q belongs to Integer (Z), and q is not 0.

Float uses fixed number of bytes, 8 bytes which is equals to 64 bits.

The 64 bits are used up as follows:

  • sign -> 1 bit
  • exponent -> 11 bits, so range [-2¹⁰ , 2¹⁰ -1]
  • significant digits -> 52 bits (recap, significant digits is all digits except leading and trailing 0s)

Some floating numbers that do have finite decimal representation but do not have finite binary representation; eg. 0.1 . So some of the float equality gives surprising output.

Press enter or click to view image in full size
float equality

Here 0.1+0.1+0.1 gives 0.30000000000000004 which is obviously not equals to 0.3.

To mitigate this, there are two ways we can do equality testing — absolute and relative. Python has isclose(a, b, *, rel_tol=1e-09, abs_tol=0.0) in math module to calculate relative and absolute tolerance. Relative tolerance is in % and is used for equality testing of numbers that are not close to 0. Absolute tolerance is used for equality testing of numbers close to 0.

Here’s an example:

Here’s an output:

sum_1: 0.30000000000000004, b: 0.3
is sum_1 == b? using isclose() with relative tolerance of 5% and default absolute tolerance: True
sum_2: 0.6000000000000001, d: 0.6
is sum_2 == d? using isclose() with default relative and absolute tolerance: True
is sum_2 == d? using isclose() with relative tolerance of 1/10^16 and default absolute tolerance: False
is sum_2 == d? using isclose() with relative tolerance of 1/10^15 and default absolute tolerance: True
e: 1e-05, f: 1e-12
is e == f? using isclose() with default relative and absolute tolerance: False
is e == f? using isclose() with default relative tolerance and absolute tolerance of 0.00001: True

For rounding floating point numbers, Python has round(number, [ndigits]) method which takes an optional parameter ndigits that tells how many decimal points we want to consider while rounding.

For breaking ties, like 1.5, -1.5, 1.25, 1.35, Python uses Banker’s Rounding (BR). BR states rounding to the nearest value with ties rounded to the nearest value with even least significant digits.

Now let’s dive into Decimals!

There is a module called decimal which lets you define and use builtin methods for decimal numbers. It works similar to how we are used to finite representation of decimal numbers unlike the float we have seen, for eg the float representation of 0.1+0.1+0.1.

Get Diane Khambu’s stories in your inbox

Join Medium for free to get updates from this writer.

Decimal constructors can be created in many ways:

On running the file, we get:

integer way: 123
string way: 1.23
floating point way: 1.229999999999999982236431605997495353221893310546875
tuple way: -1.23

We can perform decimal operation and see results like we are used to:

Press enter or click to view image in full size

Check that Decimal('0.3') is not equal to 0.3 because default decimal number representation in Python is a float type.

We have something called context that enables us to scope precision of a decimal number.

On running the file, we get:

default global decimal precision: 28
default global decimal precision: ROUND_HALF_EVEN
local decimal precision: 2
local decimal rounding: ROUND_DOWN
outside of local context (ctx) manager scope: 2

Examine that local context ctx still maintains its precision outside of its local scope.

Unless a requirement, it is advised to use floats rather than decimal in Python since there are resource overhead in drawing a precision we want like how we see in pen and paper mode.

I’ll leave complex number for you to explore.

Now let’s come to Booleans! (George Boole)

Class bool contains two singleton objects True and False . Here’s some interesting facts about these two objects:

Press enter or click to view image in full size

From the cli, we see that bool class is a subclass of int . Even though value of True is 1 they are two different objects, vice-versa for another bool object False .

Python has built-in function bool([x]) that gives boolean value of any argument passed to it.

On running the file, we get:

val 1's boolean value is True
val 0's boolean value is False
val -1's boolean value is True
val -1111's boolean value is True
val 1111's boolean value is True

We see that all numbers except +0 and -0, all integers gives True.

In fact, we also have truth value associated with objects we build.

Any built-in objects that are empty or None has boolean value of False .

Let’s see a custom object’s truth value:

On running the file, we get:

Default truthy value of object light pink oleander is True

See default boolean value of an object is True . If __bool__ or __len__ dunder method is not defined, default truth value is True . If both __bool__ and __len__ dunder methods are defined, __bool__ takes precedence.

Let’s change the truth value to false:

On running the file, we get

Setting truthy value to False
Truthy value of object ivory oleander is False

I think this gives you an idea on why we can short circuit with if statements. I used to wonder why this works in Python even though we are not evaluating a boolean object.

We also have methods like all(iterable) that checks all items in an iterable collection is true (AND), and any(iterable) that checks if any item in an iterable collection is true (OR).

We also have chaining method for comparison operators! This with logical operator can be a bit interesting.

I’ve seen how boolean value of an object can be used to make code succinct and also pythonic.

That’s all for this post! I hope it gave you useful information about numeric types in Python!

Congratulations and thank you for reading! Will see you soon in my next article.

mmm.. thinking about math, maybe I would like to someday go over Linear Algebra again and see the coolness of vector calculation — eigenvector, eigenvalue, dot product ... 🥴

Reference:

Python : Deep Dive

--

--