How to shorten a decimal in python

You want to round your answer.

round(value,significantDigit) is the ordinary solution to do this, however this sometimes does not operate as one would expect from a math perspective when the digit immediately inferior (to the left of) the digit you're rounding to has a 5.

Here's some examples of this unpredictable behavior:

>>> round(1.0005,3)
1.0
>>> round(2.0005,3)
2.001
>>> round(3.0005,3)
3.001
>>> round(4.0005,3)
4.0
>>> round(1.005,2)
1.0
>>> round(5.005,2)
5.0
>>> round(6.005,2)
6.0
>>> round(7.005,2)
7.0
>>> round(3.005,2)
3.0
>>> round(8.005,2)
8.01

Assuming your intent is to do the traditional rounding for statistics in the sciences, this is a handy wrapper to get the round function working as expected needing to import extra stuff like Decimal.

>>> round(0.075,2)

0.07

>>> round(0.075+10**(-2*6),2)

0.08

Aha! So based on this we can make a function...

def roundTraditional(val,digits):
   return round(val+10**(-len(str(val))-1), digits)

Basically this adds a really small value to the string to force it to round up properly on the unpredictable instances where it doesn't ordinarily with the round function when you expect it to. A convenient value to add is 1e-X where X is the length of the number string you're trying to use round on plus 1.

The approach of using 10**(-len(val)-1) was deliberate, as it the largest small number you can add to force the shift, while also ensuring that the value you add never changes the rounding even if the decimal . is missing. I could use just 10**(-len(val)) with a condiditional if (val>1) to subtract 1 more... but it's simpler to just always subtract the 1 as that won't change much the applicable range of decimal numbers this workaround can properly handle. This approach will fail if your values reaches the limits of the type, this will fail, but for nearly the entire range of valid decimal values it should work.

So the finished code will be something like:

def main():
    printC(formeln(typeHere()))

def roundTraditional(val,digits):
    return round(val+10**(-len(str(val))-1))

def typeHere():
    global Fahrenheit
    try:
        Fahrenheit = int(raw_input("Hi! Enter Fahrenheit value, and get it in Celsius!\n"))
    except ValueError:
        print "\nYour insertion was not a digit!"
        print "We've put your Fahrenheit value to 50!"
        Fahrenheit = 50
    return Fahrenheit

def formeln(c):
    Celsius = (Fahrenheit - 32.00) * 5.00/9.00
    return Celsius

def printC(answer):
    answer = str(roundTraditional(answer,2))
    print "\nYour Celsius value is " + answer + " C.\n"

main()

...should give you the results you expect.

You can also use the decimal library to accomplish this, but the wrapper I propose is simpler and may be preferred in some cases.


Edit: Thanks Blckknght for pointing out that the 5 fringe case occurs only for certain values here.

When we truncate values, we remove the decimal portion of a value. But what if we want to keep a certain number of decimal places? Let’s see how to program that in Python.

IN THIS ARTICLE:

  • Truncate values in Python to a certain number of decimals
  • Examples: truncate to a number of decimal digits
    • Truncate single Python values to a decimal amount
    • Truncate a sequence to decimal places with a list comprehension
    • Truncate a list to decimal places with a for loop

# Truncate values in Python to a certain number of decimals

With Python’s math.trunc() function we truncate floating-point values into whole numbers (Python Docs, n.d.). That turns 4.578 into 4 and makes -2.9 into -2. But that function always truncates to an integer, without an option to keep a certain number of decimal places.

So what to do instead? Luckily, with just a bit of code we can make our own function that truncates to decimal places. Here’s how that code looks:

import math

def truncate(number, decimals=0):
    """
    Returns a value truncated to a specific number of decimal places.
    """
    if not isinstance(decimals, int):
        raise TypeError("decimal places must be an integer.")
    elif decimals < 0:
        raise ValueError("decimal places has to be 0 or more.")
    elif decimals == 0:
        return math.trunc(number)

    factor = 10.0 ** decimals
    return math.trunc(number * factor) / factor

This custom truncate() function has two parts. We first validate and handle the function’s decimals parameter. Then we perform the actual truncation to a certain number of decimal places.

To validate we use Python’s cascaded if statement. Its first condition checks with isinstance() if the decimals parameter is an integer. When it isn’t, we generate a TypeError. That notifies the user that the function is used in the wrong way.

Then we see if the decimals parameter is under zero. When it is, we generate a ValueError to signal this incorrect value.

The last condition checks if decimals equals 0. When it does, the custom function should truncate to a whole number. So we execute the math.trunc() function to do that.

Now we get to the second part of the function. This is where we truncate to a certain number of decimal places. First we determine the correction factor. For that we raise 10.0 to the power of the decimals parameter. We store that value in the factor variable.

Then we call the math.trunc() function. Inside the function’s parentheses we specify the value to truncate (number) multiplied with our correction factor. Then we divide by the factor variable to get the proper number of decimal places.

Say we want to truncate 12.3456 to 2 decimal places. The function then first multiplies that value with 100 (102). math.trunc() then truncates 1234.56 to a whole number. We then divide with 100 to get the result in 2 decimal places: 12.34.

To use the custom truncate() function we call it with two values: a floating-point value and the number of decimal places to truncate to. For example:

truncate(12.3456, 2)
# Returns: 12.34

Truncation is something else than rounding. When we truncate, we throw away any fractional value. But the value before the decimal point (.) never changes. When we round a value, however, then then the number before . can change.

# Examples: truncate to a number of decimal digits

Now that we got a custom function that truncates to a certain number of decimal places, let’s see how we use it.

# Truncate single Python values to a decimal amount

One option is to call truncate() on single numerical values. For example:

import math

def truncate(number, decimals=0):
    """
    Returns a value truncated to a specific number of decimal places.
    """
    if not isinstance(decimals, int):
        raise TypeError("decimal places must be an integer.")
    elif decimals < 0:
        raise ValueError("decimal places has to be 0 or more.")
    elif decimals == 0:
        return math.trunc(number)

    factor = 10.0 ** decimals
    return math.trunc(number * factor) / factor


# Example values
valueA = 12.3456789
valueB = 1.2338597
valueC = 53

# Truncate the values to 3 decimal places
truncA = truncate(valueA, 3)
truncB = truncate(valueB, 3)
truncC = truncate(valueC, 3)

# Output the results
print(valueA, "truncated =", truncA)
print(valueB, "truncated =", truncB)
print(valueC, "truncated =", truncC)

Here we first import the math module. Then we copy/paste the custom truncate() function.

Then we make three variables, valueA through valueC. The first two are floating-point values, the other is an integer.

Next we truncate those variables to three decimal places. For that we call truncate() with two arguments. The first is the variable to truncate. The second is 3 so that we truncate to three decimal digits.

The final statements output the results with Python’s print() function. Here’s how that displays the original value and truncated version:

12.3456789 truncated = 12.345
1.2338597 truncated = 1.233
53 truncated = 53.0

# Truncate a sequence to decimal places with a list comprehension

We may also need to truncate every value in a list or array. If that truncation is all we have to do, then a list comprehension is an easy and efficient approach.

This example program does just that:

import math

def truncate(number, decimals=0):
    """
    Returns a value truncated to a specific number of decimal places.
    """
    if not isinstance(decimals, int):
        raise TypeError("decimal places must be an integer.")
    elif decimals < 0:
        raise ValueError("decimal places has to be 0 or more.")
    elif decimals == 0:
        return math.trunc(number)

    factor = 10.0 ** decimals
    return math.trunc(number * factor) / factor


# A list with random values
values = [
    3.46410162, 6.70820393, 11.04536102,
    15.29705854, 21.21320344, 31.4960315
]

# Truncate each value to 2 decimals
valuesTrunc = [truncate(value, 2) for value in values]

# Output results
print("Original values:\n", values)
print("Truncated values:\n", valuesTrunc)

This mini-program first imports the math module. Then we insert the custom truncate() function. After that we make a list with random floating-point values.

Then a list comprehension truncates each value in that list to 2 decimal places. For that we loop through the list with an in-line for loop expression (for value in values). On each list value we call the truncate() function. Since the function’s second argument is 2, each list value gets truncated to 2 decimal places. We store the result of that list comprehension in a new list named valuesTrunc.

The last bit of code uses print() to display the original and truncated list. Here’s how that looks:

Original values:
 [3.46410162, 6.70820393, 11.04536102, 15.29705854, 21.21320344, 31.4960315]
Truncated values:
 [3.46, 6.7, 11.04, 15.29, 21.21, 31.49]

If you don’t have to keep the original values, then you can also set the list to the outcome of the list comprehension:

# Truncate all numbers in the 'values' list
# to 3 decimals (and replace the original numbers)
values = [truncate(value, 2) for value in values]

# Truncate a list to decimal places with a for loop

Not every situation can use a list comprehension. If we want to do other tasks on each list value, and then truncate it, a for loop is the better option.

Here’s a quick example that truncates list values with Python’s for loop:

import math

def truncate(number, decimals=0):
    """
    Returns a value truncated to a specific number of decimal places.
    """
    if not isinstance(decimals, int):
        raise TypeError("decimal places must be an integer.")
    elif decimals < 0:
        raise ValueError("decimal places has to be 0 or more.")
    elif decimals == 0:
        return math.trunc(number)

    factor = 10.0 ** decimals
    return math.trunc(number * factor) / factor


# A list with random values
values = [
    3.46410162, 6.70820393, 11.04536102,
    15.29705854, 21.21320344, 31.4960315
]

valuesTrunc = []

# Truncate each value to 3 decimals
for value in values:
    valuesTrunc.append(truncate(value, 3))

# Output results
print("Original values:\n", values)
print("Truncated values:\n", valuesTrunc)

Here we again first import the math module. Then we paste the code of the custom truncate() function.

Next we make a list of random floating-point values (values). Then we make another list: valuesTrunc. That list is initially empty. But after the loop ran, it will hold the truncated values.

We make that loop next. This for loop goes through all elements in the values list. During each loop iteration, the value variable refers to a single list element. Inside the loop we truncate value to 3 decimal places with truncate(). We add the truncated result to the valuesTrunc list with its append() method.

The example ends with two print() statements. The first displays the original list, while the second outputs the truncated values:

Original values:
 [3.46410162, 6.70820393, 11.04536102, 15.29705854, 21.21320344, 31.4960315]
Truncated values:
 [3.464, 6.708, 11.045, 15.297, 21.213, 31.496]

By the way, if your program doesn’t need to keep the original list, you can also overwrite that list with its truncated values. An easy way to do that is with Python’s enumerate() function, like so:

# Loop through the original 'values' list, and
# truncate the numbers in place as we go
for index, value in enumerate(values):
    values[index] = truncate(value, 3)

FURTHER READING

  • How to truncate Python values to a whole number?
  • How to round Python values to an integer?
  • Round values in Python to a certain number of decimal places

Published December 20, 2019.

« All Python math articles

How do you shorten a decimal?

Put simply, if the last digit is less than 5, round the previous digit down. However, if it's 5 or more than you should round the previous digit up. So, if the number you are about to round is followed by 5, 6, 7, 8, 9 round the number up. And if it is followed by 0, 1, 2, 3, 4 round the number down.

How do you truncate to 2 decimal places in Python?

Just use the formatting with %. 2f which gives you round down to 2 decimal points.

What is .2f in Python?

2f is a placeholder for floating point number. So %d is replaced by the first value of the tuple i.e 12 and %. 2f is replaced by second value i.e 150.87612 .

How do you truncate to 4 decimal places in Python?

With Python's math. trunc() function we truncate floating-point values into whole numbers (Python Docs, n.d.). That turns 4.578 into 4 and makes -2.9 into -2 . But that function always truncates to an integer, without an option to keep a certain number of decimal places.