76

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'
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
SuperString
  • 18,319
  • 34
  • 87
  • 115
  • 4
    There is no such value in the set that are represented by floating-point numbers. – Karl Knechtel Dec 21 '11 at 20:55
  • 2
    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`. – John Y Dec 21 '11 at 23:14
  • The accepted answer below 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). – nullstellensatz Feb 03 '15 at 13:44
  • 1
    @nullstellensatz http://stackoverflow.com/questions/783897/truncating-floats-in-python – Abhranil Das Feb 04 '15 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. – nullstellensatz Feb 05 '15 at 03:59
  • Maybe python changed since this question, `int(1324343032.324325235 * 1000) / 1000.0` seems to work well – blueskin Mar 04 '20 at 20:18

20 Answers20

79

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

%.3f'%(1324343032.324325235)
galoget
  • 529
  • 6
  • 11
Abhranil Das
  • 4,972
  • 6
  • 31
  • 41
  • I dont want to print it...I want to store it – SuperString Dec 21 '11 at 20:33
  • 4
    This is basically the correct answer, just use `val = '%.3f'%(1324343032.324325235)` instead of `print`. – David H. Clements Dec 21 '11 at 20:37
  • Edited. You can print it, save it, whatever. – Abhranil Das Dec 21 '11 at 20:41
  • Except that this is the same value that the OP already had (namely, 1324343032.3239999). – John Y Dec 21 '11 at 22:58
  • I understand. But I think the question here was a simple truncation. Since @SuperString used `str()` in one of his attempts, I assumed he was just looking for a truncated display. – Abhranil Das Dec 22 '11 at 20:35
  • Well, if you understand, then you also know that "preserve it as a float" is not correct. He already has the float. `float('%.3f'%(1324343032.324325235))` is the **exact same thing** as `round(1324343032.324325235, 3)`. Since his first comment here is "I don't want to print it...I want to store it", it is clear he hasn't gained anything at all by doing what you are suggesting. – John Y Dec 23 '11 at 05:48
  • 14
    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). – nullstellensatz Feb 03 '15 at 13:38
  • 4
    '%.2f' % 8866.316 is round but not truncate – Oleg Jan 30 '18 at 13:18
  • 2
    you are rounding; take a look at my answer – matsib.dev Apr 15 '18 at 19:21
  • 3
    This it *not* truncating. – Darkenor May 22 '20 at 15:31
60

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

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

Usage:

>>> truncate(1324343032.324325235, 3)
1324343032.324
wjandrea
  • 16,334
  • 5
  • 30
  • 53
Erwin Mayer
  • 15,942
  • 9
  • 79
  • 117
  • 10
    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. – CatalystNZ Feb 27 '18 at 23:57
  • 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` – eplaut May 07 '19 at 11:02
  • you can just do int(stepper * number) / stepper – Yohan E Jul 17 '20 at 15:50
18

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

solveMe
  • 1,038
  • 1
  • 10
  • 17
  • 1
    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 – greenhouse Jun 28 '19 at 21:54
8

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)

Community
  • 1
  • 1
AlG
  • 13,325
  • 4
  • 39
  • 50
7

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

matsib.dev
  • 1,209
  • 8
  • 11
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'
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Yiqing Lan
  • 81
  • 1
  • 3
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)
primelens
  • 285
  • 3
  • 6
  • 1
    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. – John Y Dec 21 '11 at 22:56
3

Maybe this way:

def myTrunc(theNumber, theDigits):

    myDigits = 10 ** theDigits
    return (int(theNumber * myDigits) / myDigits)
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
OSchubert
  • 31
  • 2
3

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

Spencer Rathbun
  • 13,398
  • 5
  • 46
  • 71
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)
revliscano
  • 2,060
  • 2
  • 10
  • 18
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)]
0

You can also use:

import math

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

In Python 3.6 it would work.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Squid0ne
  • 11
  • 2
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
FFT
  • 561
  • 5
  • 13
0

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.

Vladimir Prudnikov
  • 5,908
  • 4
  • 39
  • 50
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
blueskin
  • 8,713
  • 10
  • 67
  • 100
0

I suggest next solution:

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

my_floor(1.026456,2) # 1.02

ZulusK
  • 123
  • 1
  • 11
0

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)
Amit Baderia
  • 1,172
  • 10
  • 12
0

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
gorandp
  • 108
  • 9
0

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
-1
>>> float(1324343032.324325235) * float(1000) / float(1000)

1324343032.3243253

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

1324343032.324
Donald Duck
  • 6,488
  • 18
  • 59
  • 79
  • 1
    While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) 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. – DimaSan Mar 18 '17 at 01:37