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...
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'
21 Answers
You can use an additional float() around it if you want to preserve it as a float.
%.3f'%(1324343032.324325235)
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
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
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)
'%.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.
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)
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'
Almo's link explains why this happens. To solve the problem, use the decimal library.
Maybe this way:
def myTrunc(theNumber, theDigits):
myDigits = 10 ** theDigits
return (int(theNumber * myDigits) / myDigits)
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)
Function
def truncate(number: float, digits: int) -> float:
pow10 = 10 ** digits
return number * pow10 // 1 / pow10