How to Specify the Number of Decimal Places in Python?

Problem Formulation

Using Python, we frequently need to deal with different kinds of numbers. We need to ask ourselves how to specify the number of decimal places in Python.

By default, any number that includes a decimal point is considered a floating-point number. These binary floating-point numbers are hardware-based and lose accuracy after about 15 decimal places. They are not always the best approach for dealing with decimal places.

Let’s look at different methods to specify the number of decimal places in Python and see which methods work best for your project at hand!

Method 1. Data Types for Specifying Decimal Points

If we start with a blank slate, we will probably use data types created with decimals in mind. But often enough, we find ourselves in situations presenting data types that aren’t designed to deal with decimals.

We’ll cover these data types and show you how we can transform their types to achieve decimal status, too.

a. floats

Floats are Python’s default way of displaying numbers with decimal places. Let’s create a variable and add a value with a decimal point.

my_float = 18.50623

When we check the type of our variable, we see that Python has automatically recognized it as a float.

print(type(my_float))

b. integers

Integers are numbers without any decimal places. 

my_integer = 19
print(type(my_integer))

c. strings

Strings are sequences of Unicode characters wrapped in single or double-quotes. 

my_string = '18.50623'
print(type(my_string))

d. tuples

A tuple is a collection of Python objects separated by commas.

my_tuple = (1, 8, 5, 0, 6, 2, 3)
print(type(my_tuple))

An easy way to use integers and strings with decimal places is by converting them to floats. Once they are converted to floats, we can use them the same way as any other float. Note that when converting a string, the string should contain a decimal point. 

Let’s go ahead and convert our integer and our string.

my_integer = 19
my_floated_integer = float(my_integer)

print(type(my_integer))
print(type(my_floated_integer))
print(my_integer)
print(my_floated_integer)

my_string = '18.50623'
my_floated_string = float(my_string)

print(type(my_string))
print(type(my_floated_string))
print(my_string)
print(my_floated_string)

And that’s it. Now we can specify the number of decimal places for our new floats using the following methods. 

We have other ways to construct decimal instances using floats, integers, strings, and tuples. We’ll cover the decimal module and the construction of those instances later in this post.

Method 2. Specifying Decimal Places in Floating Point Values

Floating point values are Python’s default way to deal with decimals.

These binary floating point values are hardware based, which means they do not work the same way as we learnt arithmetic at school.

Floating point values are only accurate until the 15th decimal place. This can lead to many issues, not just within Python.

Let’s look at this quick example:

float1 = 0.1 + 0.1 + 0.1
float2 = 0.3
float3 = float1 == float2
print(float1) # -> 0.30000000000000004
print(float2) # -> 0.3
print(float3) # -> False

Python is telling us that 0.3 is not the same as 0.3. At least not when we use floats.

That being said, floats are not useless. Being the default Python decimal manager, we can easily set our precision in floating point values, easily specifying the number of decimal places.

Let’s look at a few methods.

a. % operator

We can use the modulo operator to cut off any unrequired decimal places.

my_float = 18.50623
my_short_float = '%.2f'%my_float

b. format()

The format method accomplishes the same with a slightly different syntax.

my_short_float = f'{my_float:.2f}'

c. round()

The round method requires two arguments to return our specified number of decimal places. 

my_short_float = round(my_float, 2)

All three methods deliver the same result. So, let’s move on to a more precise way of specifying the number of decimal places in Python.

Method 3. Specifying Decimal Places using the Decimal Module

a. Decimal() 

Python’s decimal module works the same way as the arithmetic we learned at school. We can construct decimal instances by using the Decimal class of the decimal module. We can construct decimal instances from integers, strings, floats, and tuples. 

The decimal module represents decimal numbers exactly, which is why it is favored in accounting applications and anywhere else where monetary values are used.

We can change the precision we need directly in the module. We need to import the decimal module for all of the following methods first.

import decimal

Ok, now we have imported our decimal module, let’s look at the current context.

b. getcontext()

With the getcontext method, we can change our settings for precision – how many significant figures we want – and for rounding.

Ok, let’s take a look.

print(decimal.getcontext())
# Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=, traps=InvalidOperation, DivisionByZero, Overflow)++

The current context shows us the settings we can tweak for our decimal operations. In this post, we’ll only focus on two of the settings, precisions(prec) and rounding.

Precision

Significant figures are counted on both sides of the decimal point. 

  • Every non-zero digit is a significant figure
  • Leading zeros in front of any non-zero digits are not significant. It doesn’t matter if they are before or after the decimal point. 
  • Trailing zeros after non-zero digits are significant
  • Zeros after a non-zero digit in a decimal number are significant. 
  • Trailing zeros after a non-zero digit in a non-decimal number are not significant

Let’s quickly look at a few examples. Each of these decimal numbers has seven digits. Let’s clarify how many of those digits are significant.

val1 = 0.123456 # the leading zero is not significant, the trailing zero is -> 6 significant figures
val2 = 0.012345 # both leading zeros are not significant -> 5 significant figures
val3 = 1.012345 # in-between zeros are significant -> 7 significant figures
val4 = 1.123450 # trailing zeros following non-zero digits are significant -> 7 significant figures
val5 = 1234500 # trailing zeros in non-decimal numbers are not significant -> 5 significant figures

So, why do we use significant figures, you ask? Isn’t it more accurate to use as many decimal places as possible?

No. Let’s take a quick example:

sigfig1 = decimal.Decimal(5.23)
sigfig2 = decimal.Decimal(4.872)
sigfig_division = sigfig1 / sigfig2
print(sigfig_division)

The result of our division has a precision of 28 significant figures as set up by default. Our variables have 3 (sigfig1) and 4 (sigfig2) significant figures.

According to the rules of significant figures, however, a result can’t have more accuracy than the variables we have used, so we limit the decimal result to have the same amount of significant figures as our variable with the lesser amount of significant figures, which is sigfig1 with 3.

We can control this by telling getcontext how many significant figures we want our precision to use. 

decimal.getcontext().prec = 3

Now, let’s check the current context.

print(decimal.getcontext()) 

There you go. We have changed the decimal precision to 3 significant figures. 

Now printing our result has the exact precision we need it to have.

print(sigfig_division)

Let’s look at what happens when we use the decimal module with the current settings. 

Let’s use a number with a couple of decimal places. How about the orbital speed of our planet? We’re orbiting at 18.506238539154285 miles a second, so it’s reckoned, the sun that is the source of all our power. 

orbital_speed = 18.506238539154285

Let’s check which data type we have used.

print(type(orbital_speed))

As expected, Python tells us our orbital speed is a float. Now, let’s use the Decimal class to create a decimal instance of our float.

orbital_speed_decimal = decimal.Decimal(orbital_speed)

Let’s check our new data type.

print(type(orbital_speed_decimal))

It tells us type is a decimal, great. In the last part, we learned how to use the precision settings to control the number of significant figures we display. Let’s set them to 5 and see if it returns 18.506.

decimal.getcontext().prec = 5
print(orbital_speed_decimal)

That’s strange. The decimal places haven’t been shortened. What happened here?

Let’s check our precision settings:

print(decimal.getcontext())

No, precision is set at 5 as we intended. 

Unfortunately, within the decimal module, precision and rounding only come into play during arithmetic operations, which means, if we don’t have an arithmetic operation to process, the precision won’t be applied. 

There is a workaround, though. We need to use an arithmetic operation that doesn’t change our value. Multiplying our decimal by 1 will do exactly that: 

print(orbital_speed_decimal) * 1

Rounding

Any time we want to shorten decimals, we need to determine how we want to round the remaining number.

Let’s take another look at our getcontext settings:

print(decimal.getcontext())

Rounding is set to ROUNDHALFEVEN and can be changed with the same decimal.getcontext() command we used for changing the precision. 

decimal.getcontext().rounding = decimal.ROUND_DOWN

Rounding options include ROUNDCEILING, ROUNDDOWN, ROUNDFLOOR, ROUNDHALFDOWN, ROUNDHALFEVEN, ROUNDHALFUP, ROUNDUP, and ROUND05UP

The final decimal module method we’ll look at offers the best of both worlds. Let’s take a look at the method quantize().

c. quantize()

The quantize method rounds to a fixed number of decimal places. That makes this method the perfect companion for any projects, including currencies or any other monetary applications. Let’s look at the syntax.

quant_orbital_speed = decimal.Decimal(orbital speed).quantize(
                        decimal.Decimal('.01'), rounding = decimal.ROUND_UP)

The first argument defines at which position we want to round our decimal number. There are two ways we can do this. First, we can use zeros to indicate how many decimal places we want and the digit 1 to indicate where to round.

quantize(decimal.Decimal('.01')

returns two decimal places after the decimal point

quantize(decimal.Decimal('.0001')

returns 4 decimal places after the decimal point

Or second, we can use zeros to indicate how many decimal places we want and where to round.

quantize(decimal.Decimal('1.00')

returns 2 decimal places after the decimal point

quantize(decimal.Decimal(β€˜1.0000’)

returns 4 decimal places after the decimal point

quantize(decimal.Decimal(β€˜1.’)

returns a whole number without decimal places

quant_orbital_speed = decimal.Decimal(orbital speed).quantize(
                         decimal.Decimal(β€˜.01’), rounding = decimal.ROUND_UP)

The second argument defines how to round. If we don’t add a second argument, the default value in getcontext() will determine how to round

Method 4. Removing Decimal Places using the Math Module

Removing decimal places and returning to an integer type is very simple if you know which outcome you are looking for.

It can be as simple as just chopping off all existing decimal places. Python has a math module that allows us to do just that.

Let’s give it a go, and start by importing the math module.

import math

And let’s add our planet’s orbital speed to have a value to work with.

orbital_speed = 18.506238539154285

The three following methods remove all decimal places by converting our float into an integer.

a. trunc()

The trunc method takes our float and removes any decimal places, leaving us only with the remaining integer.

orbital_trunc = math.trunc(orbital_speed)
print(orbital_trunc)

b. ceil()

The ceil method takes our float and rounds up to the integer that is greater than our float. 

orbital_ceil = math.ceil(orbital_speed)
print(orbital_ceil)

c. floor()

The floor method takes our float and rounds down to the integer that is smaller than our float. 

orbital_floor = math.floor(orbital_speed)
print(orbital_floor)

Using the above methods is a straightforward way to return to an integer rounded however we need it.

Summary

Python offers a variety of options for different situations dealing with decimals. Depending on our project at hand, we took a look at some of the most valuable ways to specify the number of decimal places in Python. 

  • We covered common data types to specify the number of decimal places in Python.
  • We walked through the fast and straightforward ways to set decimal places of floats using the modulo operator, the format method, and the round method.
  • We learned how to use the decimal module for more accuracy, as needed for financial applications and when we want to use significant decimal places (3.50 instead of 3.5).
  • And finally, we had a quick look at how the math module enables us to determine that we don’t want any decimal places at all. 

Programmer Humor

πŸ‘±β€β™€οΈ Programmer 1: We have a problem
πŸ§”β€β™‚οΈ Programmer 2: Let’s use RegEx!
πŸ‘±β€β™€οΈ Programmer 1: Now we have two problems

… yet – you can easily reduce the two problems to zero as you polish your “RegEx Superpower in Python“. πŸ™‚