102

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' 
6
  • 7
    There is no such value in the set that are represented by floating-point numbers. Commented Dec 21, 2011 at 20:55
  • 3
    In case Karl's comment is not clear enough: There is no such number as 1324343032.324 in binary floating point. If you switch to a higher version of Python (2.7 or 3.1 or later) the interpreter will display 1324343032.324 for you. But in actuality, the number you are computing with is neither 1324343032.324 nor 1324343032.3239999 regardless of Python version. The only way to get exactly 1324343032.324 is to use the decimal module or some other arbitrary-precision math library, such as gmpy. Commented Dec 21, 2011 at 23:14
  • 1
    @nullstellensatz stackoverflow.com/questions/783897/truncating-floats-in-python Commented Feb 4, 2015 at 22:49
  • 1
    @AbhranilDas this question is a duplicate of the one you pointed to. Since both of the questions have misleading answers, I have marked this one as a duplicate, so that all issues related to truncating can be dealt with in one place. Also, check out my comments and suggested answer for the original question. Commented Feb 5, 2015 at 3:59
  • 2
    Maybe python changed since this question, int(1324343032.324325235 * 1000) / 1000.0 seems to work well Commented Mar 4, 2020 at 20:18

21 Answers 21

97

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

val = '%.3f'%(1324343032.324325235) 
Sign up to request clarification or add additional context in comments.

13 Comments

This is basically the correct answer, just use val = '%.3f'%(1324343032.324325235) instead of print.
This answer is correct, if you want to round (up) to a given number of decimal places. However, what the question is asking, and what I wanted to know, is how to truncate to a particular number of decimal places. For me, '%.3f'%(1324343032.3243) and '%.3f'%(1324343032.3245) give different results. (I am using Python 2.7.8).
'%.2f' % 8866.316 is round but not truncate
you are rounding; take a look at my answer
This it not truncating.
|
93

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 

5 Comments

This should really be the accepted answer. The code is simple, elegant, and makes the most sense. Use the standard truncate function, however first shift the decimal place, shifting the decimal place back once the truncate has been performed.
note floating point precision errors truncate(-1.13, 2) == -1.12, i've change it a bit (with a bitter taste in the mouth) to math.trunc(round(stepper * number, digits * 3)) / stepper
you can just do int(stepper * number) / stepper
I've tried this with the following numbers: number = 16.4 and digits = 2; the resulting value is 16.39 unfortunately.
@MoKanj Good point, I have updated the answer to improve the accuracy.
37

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

4 Comments

I think this should be one of the more accepted answers... it teaches you how to utilize & modify modules to your advantage, which expresses how truly dynamic and powerful python can be
@solveme the only issue with this and personally I don't know why the standard math lib doesn't have round in it., is that the decimal library being very high precision reportedly comes with a performance cost. still a 100x better than the answer directly above which would throw an exception with a number too big. good job.
The problem here is that it's trading the undesirable string manipulation for the equally (if not more) undesirable package import, plus the added overhead of decimal. Which one is worse will probably depend on the specific use case.
Looks like, If module import is so bad, it's better to not use python at all.
15

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)

Comments

8

'%.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.

Comments

7

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 

Comments

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) 

1 Comment

It's good that you mentioned the decimal module first, because that is the only fully correct answer. One thing to be a little careful of with the rest is that b in your example will be displayed as 1324343032.3239999 on versions of Python before 2.7. And indeed, this is the value that OP is seeing when he tries. Of course, both values are indistinguishable, in terms of binary floating point.
6

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' 

Comments

5

I suggest next solution:

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

2 Comments

I like this because it is using the modern Python string interpolation. But I don't understand why you have made it one more length than it needs to be and then cut off the last character. This can't be to do with rounding, as your solution does what the OP asked for, truncation, not rounding (as demonstrated by your example).
Taking one extra digit and then removing it is necessary, because formatting a number with the string itself rounds the number! For example: f'{0.55:.2f}'[:-1] returns '0.5', but f'{0.55:.1f}' returns '0.6'. This is also why this solution will fail on pathological cases like 1.9999999. It will always return '2.0x', where 0x denotes as many zeros as the desired precision.
4

Maybe this way:

def myTrunc(theNumber, theDigits): myDigits = 10 ** theDigits return (int(theNumber * myDigits) / myDigits) 

1 Comment

Heads up, this works on Python 3, but not Python 2, due to changes in how / works.
4

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.

Comments

2

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

1 Comment

You do not explicit help the OP.
2

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) 

Comments

1

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)] 

Comments

1

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) 

Comments

0

You can also use:

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

In Python 3.6 it would work.

Comments

0
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 

Comments

0

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 

Comments

-1
>>> float(1324343032.324325235) * float(1000) / float(1000) 1324343032.3243253 >>> round(float(1324343032.324325235) * float(1000) / float(1000), 3) 1324343032.324 

1 Comment

While this code snippet may solve the question, including an explanation really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion.
-1

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) 

Comments

-1

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 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.