Truncate to three decimals in Python

How do I get 1324343032.324?

As you can see below, the following do not work:

>>1324343032.324325235 * 1000 / 1000
1324343032.3243253
>>int(1324343032.324325235 * 1000) / 1000.0
1324343032.3239999
>>round(int(1324343032.324325235 * 1000) / 1000.0,3)
1324343032.3239999
>>str(1324343032.3239999)
'1324343032.32'

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

You can use an additional float() around it if you want to preserve it as a float.

%.3f'%(1324343032.324325235)

Method 2

You can use the following function to truncate a number to a set number of decimals:

import math
def truncate(number, digits) -> float:
    # Improve accuracy with floating point operations, to avoid truncate(16.4, 2) = 16.39 or truncate(-1.13, 2) = -1.12
    nbDecimals = len(str(number).split('.')[1]) 
    if nbDecimals <= digits:
        return number
    stepper = 10.0 ** digits
    return math.trunc(stepper * number) / stepper

Usage:

>>> truncate(1324343032.324325235, 3)
1324343032.324

Method 3

I’ve found another solution (it must be more efficient than “string witchcraft” workarounds):

>>> import decimal
# By default rounding setting in python is decimal.ROUND_HALF_EVEN
>>> decimal.getcontext().rounding = decimal.ROUND_DOWN
>>> c = decimal.Decimal(34.1499123)
# By default it should return 34.15 due to '99' after '34.14'
>>> round(c,2)
Decimal('34.14')
>>> float(round(c,2))
34.14
>>> print(round(c,2))
34.14

About decimals module

About rounding settings

Method 4

How about this:

In [1]: '%.3f' % round(1324343032.324325235 * 1000 / 1000,3)
Out[1]: '1324343032.324'

Possible duplicate of round() in Python doesn’t seem to be rounding properly

[EDIT]

Given the additional comments I believe you’ll want to do:

In : Decimal('%.3f' % (1324343032.324325235 * 1000 / 1000))
Out: Decimal('1324343032.324')

The floating point accuracy isn’t going to be what you want:

In : 3.324
Out: 3.3239999999999998

(all examples are with Python 2.6.5)

Method 5

‘%.3f’%(1324343032.324325235)

It’s OK just in this particular case.

Simply change the number a little bit:

1324343032.324725235

And then:

'%.3f'%(1324343032.324725235)

gives you 1324343032.325

Try this instead:

def trun_n_d(n,d):
    s=repr(n).split('.')
    if (len(s)==1):
        return int(s[0])
    return float(s[0]+'.'+s[1][:d])

Another option for trun_n_d:

def trun_n_d(n,d):
    dp = repr(n).find('.') #dot position
    if dp == -1:  
        return int(n) 
    return float(repr(n)[:dp+d+1])

Yet another option ( a oneliner one) for trun_n_d [this, assumes ‘n‘ is a str and ‘d‘ is an int]:

def trun_n_d(n,d):
    return (  n if not n.find('.')+1 else n[:n.find('.')+d+1]  )

trun_n_d gives you the desired output in both, Python 2.7 and Python 3.6

trun_n_d(1324343032.324325235,3) returns 1324343032.324

Likewise, trun_n_d(1324343032.324725235,3) returns 1324343032.324


Note 1 In Python 3.6 (and, probably, in Python 3.x) something like this, works just fine:

def trun_n_d(n,d):
    return int(n*10**d)/10**d

But, this way, the rounding ghost is always lurking around.

Note 2 In situations like this, due to python‘s number internals, like rounding and lack of precision, working with n as a str is way much better than using its int counterpart; you can always cast your number to a float at the end.

Method 6

Use the decimal module. But if you must use floats and still somehow coerce them into a given number of decimal points converting to string an back provides a (rather clumsy, I’m afraid) method of doing it.

>>> q = 1324343032.324325235 * 1000 / 1000
>>> a = "%.3f" % q
>>> a
'1324343032.324'
>>> b = float(a)
>>> b
1324343032.324

So:

float("%3.f" % q)

Method 7

I believe using the format function is a bad idea. Please see the below. It rounds the value. I use Python 3.6.

>>> '%.3f'%(1.9999999)
'2.000'

Use a regular expression instead:

>>> re.match(r'd+.d{3}', str(1.999999)).group(0)
'1.999'

Method 8

Almo’s link explains why this happens. To solve the problem, use the decimal library.

Method 9

Maybe this way:

def myTrunc(theNumber, theDigits):

    myDigits = 10 ** theDigits
    return (int(theNumber * myDigits) / myDigits)

Method 10

Okay, this is just another approach to solve this working on the number as a string and performing a simple slice of it. This gives you a truncated output of the number instead of a rounded one.

num = str(1324343032.324325235)
i = num.index(".")
truncated = num[:i + 4]
    
print(truncated)

Output:

'1324343032.324'

Of course then you can parse:

float(truncated)

Method 11

Function

def truncate(number: float, digits: int) -> float:
    pow10 = 10 ** digits
    return number * pow10 // 1 / pow10

Test code

f1 = 1.2666666
f2 = truncate(f1, 3)
print(f1, f2)

Output

1.2666666 1.266

Explain

It shifts f1 numbers digits times to the left, then cuts all decimals and finally shifts back the numbers digits times to the right.

Example in a sequence:

1.2666666 # number
1266.6666 # number * pow10
1266.0    # number * pow10 // 1
1.266     # number * pow10 // 1 / pow10

Method 12

After looking for a way to solve this problem, without loading any Python 3 module or extra mathematical operations, I solved the problem using only str.format() e .float(). I think this way is faster than using other mathematical operations, like in the most commom solution. I needed a fast solution because I work with a very very large dataset and so for its working very well here.

def truncate_number(f_number, n_decimals):
      strFormNum = "{0:." + str(n_decimals+5) + "f}"
      trunc_num = float(strFormNum.format(f_number)[:-5])
      return(trunc_num)

# Testing the 'trunc_num()' function
test_num = 1150/252
[(idx, truncate_number(test_num, idx)) for idx in range(0, 20)]

It returns the following output:

[(0, 4.0),
 (1, 4.5),
 (2, 4.56),
 (3, 4.563),
 (4, 4.5634),
 (5, 4.56349),
 (6, 4.563492),
 (7, 4.563492),
 (8, 4.56349206),
 (9, 4.563492063),
 (10, 4.5634920634),
 (11, 4.56349206349),
 (12, 4.563492063492),
 (13, 4.563492063492),
 (14, 4.56349206349206),
 (15, 4.563492063492063),
 (16, 4.563492063492063),
 (17, 4.563492063492063),
 (18, 4.563492063492063),
 (19, 4.563492063492063)]

Method 13

I think the best and proper way is to use decimal module.

import decimal

a = 1324343032.324325235

decimal_val = decimal.Decimal(str(a)).quantize(
   decimal.Decimal('.001'), 
   rounding=decimal.ROUND_DOWN
)
float_val = float(decimal_val)

print(decimal_val)
>>>1324343032.324

print(float_val)
>>>1324343032.324

You can use different values for rounding=decimal.ROUND_DOWN, available options are ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_UP, and ROUND_05UP. You can find explanation of each option here in docs.

Method 14

I suggest next solution:

def my_floor(num, precision):
   return f'{num:.{precision+1}f}'[:-1]

my_floor(1.026456,2) # 1.02

Method 15

You can also use:

import math

nValeur = format(float(input('Quelle valeur ?    ')), '.3f')

In Python 3.6 it would work.

Method 16

a = 1.0123456789
dec = 3 # keep this many decimals
p = 10 # raise 10 to this power
a * 10 ** p // 10 ** (p - dec) / 10 ** dec
>>> 1.012

Method 17

Maybe python changed since this question, all of the below seem to work well

Python2.7

int(1324343032.324325235 * 1000) / 1000.0
float(int(1324343032.324325235 * 1000)) / 1000
round(int(1324343032.324325235 * 1000) / 1000.0,3)
# result for all of the above is 1324343032.324

Method 18

I am trying to generate a random number between 5 to 7 and want to limit it to 3 decimal places.

import random

num = float('%.3f' % random.uniform(5, 7))
print (num)

Method 19

I develop a good solution, I know there is much If statements, but It works! (Its only for <1 numbers)

def truncate(number, digits) -> float:
    startCounting = False
    if number < 1:
      number_str = str('{:.20f}'.format(number))
      resp = ''
      count_digits = 0
      for i in range(0, len(number_str)):
        if number_str[i] != '0' and number_str[i] != '.' and number_str[i] != ',':
          startCounting = True
        if startCounting:
          count_digits = count_digits + 1
        resp = resp + number_str[i]
        if count_digits == digits:
            break
      return resp
    else:
      return number

Method 20

Based on @solveMe asnwer (https://stackoverflow.com/a/39165933/641263) which I think is one of the most correct ways by utilising decimal context, I created following method which does the job exactly as needed:

import decimal

def truncate_decimal(dec: Decimal, digits: int) -> decimal.Decimal:
    round_down_ctx = decimal.getcontext()
    round_down_ctx.rounding = decimal.ROUND_DOWN
    new_dec = round_down_ctx.create_decimal(dec)
    return round(new_dec, digits)

Method 21

>>> float(1324343032.324325235) * float(1000) / float(1000)

1324343032.3243253

>>> round(float(1324343032.324325235) * float(1000) / float(1000), 3)

1324343032.324


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x