[python] How to truncate float values?

I want to remove digits from a float to have a fixed number of digits after the dot, like:

1.923328437452 ? 1.923

I need to output as a string to another function, not print.

Also I want to ignore the lost digits, not round them.

This question is related to python floating-point

The answer is


When using a pandas df this worked for me

import math
def truncate(number, digits) -> float:
    stepper = 10.0 ** digits
    return math.trunc(stepper * number) / stepper

df['trunc'] = df['float_val'].apply(lambda x: truncate(x,1))
df['trunc']=df['trunc'].map('{:.1f}'.format)

The result of round is a float, so watch out (example is from Python 2.6):

>>> round(1.923328437452, 3)
1.923
>>> round(1.23456, 3)
1.2350000000000001

You will be better off when using a formatted string:

>>> "%.3f" % 1.923328437452
'1.923'
>>> "%.3f" % 1.23456
'1.235'

Just wanted to mention that the old "make round() with floor()" trick of

round(f) = floor(f+0.5)

can be turned around to make floor() from round()

floor(f) = round(f-0.5)

Although both these rules break around negative numbers, so using it is less than ideal:

def trunc(f, n):
    if f > 0:
        return "%.*f" % (n, (f - 0.5*10**-n))
    elif f == 0:
        return "%.*f" % (n, f)
    elif f < 0:
        return "%.*f" % (n, (f + 0.5*10**-n))

Am also a python newbie and after making use of some bits and pieces here, I offer my two cents

print str(int(time.time()))+str(datetime.now().microsecond)[:3]

str(int(time.time())) will take the time epoch as int and convert it to string and join with... str(datetime.now().microsecond)[:3] which returns the microseconds only, convert to string and truncate to first 3 chars


use numpy.round

import numpy as np
precision = 3
floats = [1.123123123, 2.321321321321]
new_float = np.round(floats, precision)

def precision(value, precision):
    """
    param: value: takes a float
    param: precision: int, number of decimal places
    returns a float
    """
    x = 10.0**precision
    num = int(value * x)/ x
    return num
precision(1.923328437452, 3)

1.923


At my Python 2.7 prompt:

>>> int(1.923328437452 * 1000)/1000.0 1.923


def trunc(num, digits):
   sp = str(num).split('.')
   return '.'.join([sp[0], sp[1][:digits]])

This should work. It should give you the truncation you are looking for.


The truely pythonic way of doing it is

from decimal import *

with localcontext() as ctx:
    ctx.rounding = ROUND_DOWN
    print Decimal('1.923328437452').quantize(Decimal('0.001'))

or shorter:

from decimal import Decimal as D, ROUND_DOWN

D('1.923328437452').quantize(D('0.001'), rounding=ROUND_DOWN)

Update

Usually the problem is not in truncating floats itself, but in the improper usage of float numbers before rounding.

For example: int(0.7*3*100)/100 == 2.09.

If you are forced to use floats (say, you're accelerating your code with numba), it's better to use cents as "internal representation" of prices: (70*3 == 210) and multiply/divide the inputs/outputs.


# value  value to be truncated
# n  number of values after decimal

value = 0.999782
n = 3
float(int(value*1en))*1e-n

So many of the answers given for this question are just completely wrong. They either round up floats (rather than truncate) or do not work for all cases.

This is the top Google result when I search for 'Python truncate float', a concept which is really straightforward, and which deserves better answers. I agree with Hatchkins that using the decimal module is the pythonic way of doing this, so I give here a function which I think answers the question correctly, and which works as expected for all cases.

As a side-note, fractional values, in general, cannot be represented exactly by binary floating point variables (see here for a discussion of this), which is why my function returns a string.

from decimal import Decimal, localcontext, ROUND_DOWN

def truncate(number, places):
    if not isinstance(places, int):
        raise ValueError("Decimal places must be an integer.")
    if places < 1:
        raise ValueError("Decimal places must be at least 1.")
    # If you want to truncate to 0 decimal places, just do int(number).

    with localcontext() as context:
        context.rounding = ROUND_DOWN
        exponent = Decimal(str(10 ** - places))
        return Decimal(str(number)).quantize(exponent).to_eng_string()

There is an easy workaround in python 3. Where to cut I defined with an help variable decPlace to make it easy to adapt.

f = 1.12345
decPlace= 4
f_cut = int(f * 10**decPlace) /10**decPlace

Output:

f = 1.1234

Hope it helps.


The core idea given here seems to me to be the best approach for this problem. Unfortunately, it has received less votes while the later answer that has more votes is not complete (as observed in the comments). Hopefully, the implementation below provides a short and complete solution for truncation.

_x000D_
_x000D_
def trunc(num, digits):_x000D_
    l = str(float(num)).split('.')_x000D_
    digits = min(len(l[1]), digits)_x000D_
    return (l[0]+'.'+l[1][:digits])
_x000D_
_x000D_
_x000D_

which should take care of all corner cases found here and here.


I did something like this:

from math import trunc


def truncate(number, decimals=0):
    if decimals < 0:
        raise ValueError('truncate received an invalid value of decimals ({})'.format(decimals))
    elif decimals == 0:
        return trunc(number)
    else:
        factor = float(10**decimals)
        return trunc(number*factor)/factor

Short and easy variant

def truncate_float(value, digits_after_point=2):
    pow_10 = 10 ** digits_after_point
    return (float(int(value * pow_10))) / pow_10

>>> truncate_float(1.14333, 2)
>>> 1.14

>>> truncate_float(1.14777, 2)
>>> 1.14


>>> truncate_float(1.14777, 4)
>>> 1.1477

def trunc(f,n):
  return ('%.16f' % f)[:(n-16)]

n = 1.923328437452
str(n)[:4]

round(1.923328437452, 3)

See Python's documentation on the standard types. You'll need to scroll down a bit to get to the round function. Essentially the second number says how many decimal places to round it to.


If you fancy some mathemagic, this works for +ve numbers:

>>> v = 1.923328437452
>>> v - v % 1e-3
1.923

You can do:

def truncate(f, n):
    return math.floor(f * 10 ** n) / 10 ** n

testing:

>>> f=1.923328437452
>>> [truncate(f, n) for n in range(5)]
[1.0, 1.9, 1.92, 1.923, 1.9233]

A general and simple function to use:

def truncate_float(number, length):
    """Truncate float numbers, up to the number specified
    in length that must be an integer"""

    number = number * pow(10, length)
    number = int(number)
    number = float(number)
    number /= pow(10, length)
    return number

int(16.5); this will give an integer value of 16, i.e. trunc, won't be able to specify decimals, but guess you can do that by

import math;

def trunc(invalue, digits):
    return int(invalue*math.pow(10,digits))/math.pow(10,digits);

Simple python script -

n = 1.923328437452
n = float(int(n * 1000))
n /=1000

Most answers are way too complicated in my opinion, how about this?

digits = 2  # Specify how many digits you want

fnum = '122.485221'
truncated_float = float(fnum[:fnum.find('.') + digits + 1])

>>> 122.48

Simply scanning for the index of '.' and truncate as desired (no rounding). Convert string to float as final step.

Or in your case if you get a float as input and want a string as output:

fnum = str(122.485221)  # convert float to string first
truncated_float = fnum[:fnum.find('.') + digits + 1]  # string output

Something simple enough to fit in a list-comprehension, with no libraries or other external dependencies. For Python >=3.6, it's very simple to write with f-strings.

The idea is to let the string-conversion do the rounding to one more place than you need and then chop off the last digit.

>>> nout = 3  # desired number of digits in output
>>> [f'{x:.{nout+1}f}'[:-1] for x in [2/3, 4/5, 8/9, 9/8, 5/4, 3/2]]
['0.666', '0.800', '0.888', '1.125', '1.250', '1.500']

Of course, there is rounding happening here (namely for the fourth digit), but rounding at some point is unvoidable. In case the transition between truncation and rounding is relevant, here's a slightly better example:

>>> nacc = 6  # desired accuracy (maximum 15!)
>>> nout = 3  # desired number of digits in output
>>> [f'{x:.{nacc}f}'[:-(nacc-nout)] for x in [2.9999, 2.99999, 2.999999, 2.9999999]]
>>> ['2.999', '2.999', '2.999', '3.000']

Bonus: removing zeros on the right

>>> nout = 3  # desired number of digits in output
>>> [f'{x:.{nout+1}f}'[:-1].rstrip('0') for x in [2/3, 4/5, 8/9, 9/8, 5/4, 3/2]]
['0.666', '0.8', '0.888', '1.125', '1.25', '1.5']

Here is an easy way:

def truncate(num, res=3):
    return (floor(num*pow(10, res)+0.5))/pow(10, res)

for num = 1.923328437452, this outputs 1.923


If you mean when printing, then the following should work:

print '%.3f' % number

>>> floor((1.23658945) * 10**4) / 10**4
1.2365

# divide and multiply by 10**number of desired digits