Is there a pythonic way of splitting a number such as 1234.5678
into two parts (1234, 0.5678)
i.e. the integer part and the decimal part?
9 Answers
Use math.modf
:
import math
x = 1234.5678
math.modf(x) # (0.5678000000000338, 1234.0)

- 29,088
- 9
- 83
- 120

- 8,342
- 2
- 29
- 29
-
1after apply math.modf(x) how can I handle result values? For example if I assing 1234.0 to a variable, how I can do that? – hakki Dec 30 '13 at 00:31
-
2@Trengot - Use `int_` if you must have a variable that, when read aloud, is called "int". – ArtOfWarfare Jun 23 '15 at 18:24
-
@MarkDickinson And how to get the reverse of this, say from 1234 and 5678 to get 1234.5678? – Ethan Aug 31 '18 at 04:43
-
@Ethan: To get the reverse of the `modf` operation you'd just add the two pieces: `1234 + 0.5678 = 1234.5678`. Where are you getting `1234` and `5678` from? Your question doesn't seem related to this answer. – Mark Dickinson Aug 31 '18 at 18:11
-
@MarkDickinson I was looking for a function to create a float from 2 integers, that's how I landed here, and asked since you mentioned of `modf`. I have 2 ints: 1234 and 5678 (not 0.5678). So, can do: (1234 - 0.0) + 5678*0.01. Since I have to run this on thousands of such data, hence was looking for some optimal routine, if exists. – Ethan Aug 31 '18 at 18:22
-
Also see [`numpy.modf`](https://numpy.org/doc/stable/reference/generated/numpy.modf.html#numpy-modf), which can handle arrays. – djvg Jan 24 '23 at 10:31
We can use a not famous built-in function; divmod:
>>> s = 1234.5678
>>> i, d = divmod(s, 1)
>>> i
1234.0
>>> d
0.5678000000000338

- 26,532
- 10
- 62
- 81
-
6Gives possibly unintuitive results for negative numbers: `divmod(-4.5,1)` gives -5.0 and 0.5. Using `divmod(-4.5, -1)` gives 4.0 and -0.5. – Holloway Jul 29 '14 at 11:26
-
@Holloway it is not unintuitive, it comes from math rules: https://en.wikipedia.org/wiki/Floor_and_ceiling_functions :) – Sviatoslav V. Nov 07 '20 at 11:08
-
@SviatoslavV. Those math rules you mentioned specifically state: The integral part or integer part of x, often denoted [ x ] , is floor(x) if x is nonnegative, and ceiling(x) otherwise. – Bhuvanesh Jan 26 '21 at 06:40
-
>>> a = 147.234
>>> a % 1
0.23400000000000887
>>> a // 1
147.0
>>>
If you want the integer part as an integer and not a float, use int(a//1)
instead. To obtain the tuple in a single passage: (int(a//1), a%1)
EDIT: Remember that the decimal part of a float number is approximate, so if you want to represent it as a human would do, you need to use the decimal library
-
7Slightly confusing results for negative numbers, `-2.25 // 1 == -3.0` and `-2.25 % 1 == 0.75`. This may be what the OP would want, as int part + decimal part is still equal to the original value. By contrast, `math.modf(-2.25) == (-0.25, -2.0)`. – Andrew Clark Jul 13 '11 at 15:57
-
-
Nice - I reckon this would be the fastest way of those shown here bearing in mind Andrew Clark's caveat for negative numbers – jacanterbury Jan 08 '18 at 18:52
intpart,decimalpart = int(value),value-int(value)
Works for positive numbers.

- 299,747
- 42
- 398
- 622
-
`In [1]: value = 1.89` `In [2]: intpart,decimalpart = int(value),value-int(value)` `In [3]: intpart` `Out [3]: 1` `In [4]: decimalpart` `Out [4]: 0.8899999999999999` – iMom0 Mar 09 '12 at 04:44
-
1@iMom0 - See http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html and numerous questions on this site regarding floating point accuracy. – Mark Ransom Mar 09 '12 at 04:51
-
@iMom0 I realize it's been over 9 years since you made your comment. But in that time I've found a better reference to explain those floating point oddities: [Is floating point math broken?](https://stackoverflow.com/q/588004/5987) – Mark Ransom Dec 04 '21 at 00:42
This variant allows getting desired precision:
>>> a = 1234.5678
>>> (lambda x, y: (int(x), int(x*y) % y/y))(a, 1e0)
(1234, 0.0)
>>> (lambda x, y: (int(x), int(x*y) % y/y))(a, 1e1)
(1234, 0.5)
>>> (lambda x, y: (int(x), int(x*y) % y/y))(a, 1e15)
(1234, 0.5678)

- 35,405
- 10
- 55
- 80

- 119
- 1
- 3
I have come up with two statements that can divide positive and negative numbers into integer and fraction without compromising accuracy (bit overflow) and speed.
Code
# Divide a number (x) into integer and fraction
i = int(x) # Get integer
f = (x*1e17 - i*1e17) / 1e17 # Get fraction
A positive and negative value of the value 100.1323
will be divided as follows (100
, 0.1323
) and (-100
, -0.1323
) where the math.modf
result will be (0.13230000000000075
, 100.0
) and (-0.13230000000000075
, -100.0
).
Speedtest
The performance test shows that the two statements are faster than math.modf
, as long as they are not put into their own function or method (C/C++ extension improve this).
test.py
:
#!/usr/bin/env python
import math
import cProfile
""" Get the performance of both statements and math.modf """
X = -100.1323 # The number to be divided into integer and fraction
LOOPS = range(5 * 10 ** 6) # Number of loops
def scenario_a():
""" Get the performance of the statements """
for _ in LOOPS:
i = int(X) # -100
f = (X*1e17-i*1e17)/1e17 # -0.1323
def scenario_b():
""" Tests the speed of the statements when integer need to be float.
NOTE: The only difference between this and math.modf is the accuracy """
for _ in LOOPS:
i = int(X) # -100
i, f = float(i), (X*1e17-i*1e17)/1e17 # (-100.0, -0.1323)
def scenario_c():
""" Tests the speed of the statements in a function """
def modf(x):
i = int(x)
return i, (x*1e17-i*1e17)/1e17
for _ in LOOPS:
i, f = modf(X) # (-100, -0.1323)
def scenario_d():
""" Tests the speed of math.modf """
for _ in LOOPS:
f, i = math.modf(X) # (-0.13230000000000075, -100.0)
def scenario_e():
""" Tests the speed of math.modf when the integer part should be integer """
for _ in LOOPS:
f, i = math.modf(X) # (-0.13230000000000075, -100.0)
i = int(i) # -100
if __name__ == '__main__':
cProfile.run('scenario_a()')
cProfile.run('scenario_b()')
cProfile.run('scenario_c()')
cProfile.run('scenario_d()')
cProfile.run('scenario_e()')
Result:
4 function calls in 1.357 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 1.357 1.357 <string>:1(<module>)
1 1.357 1.357 1.357 1.357 test.py:11(scenario_a)
1 0.000 0.000 1.357 1.357 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
4 function calls in 1.858 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 1.858 1.858 <string>:1(<module>)
1 1.858 1.858 1.858 1.858 test.py:18(scenario_b)
1 0.000 0.000 1.858 1.858 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
5000004 function calls in 2.744 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 2.744 2.744 <string>:1(<module>)
1 1.245 1.245 2.744 2.744 test.py:26(scenario_c)
5000000 1.499 0.000 1.499 0.000 test.py:29(modf)
1 0.000 0.000 2.744 2.744 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
5000004 function calls in 1.904 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 1.904 1.904 <string>:1(<module>)
1 1.073 1.073 1.904 1.904 test.py:37(scenario_d)
1 0.000 0.000 1.904 1.904 {built-in method builtins.exec}
5000000 0.831 0.000 0.831 0.000 {built-in method math.modf}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
5000004 function calls in 2.547 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 2.547 2.547 <string>:1(<module>)
1 1.696 1.696 2.547 2.547 test.py:43(scenario_e)
1 0.000 0.000 2.547 2.547 {built-in method builtins.exec}
5000000 0.851 0.000 0.851 0.000 {built-in method math.modf}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
C/C++ extension
I have tried to compile the two statements with C/C++ support and the result was even better. With Python extension module it was possible to get a method that was faster and more accurate than math.modf
.
math2.pyx
:
def modf(number):
cdef float num = <float> number
cdef int i = <int> num
return i, (num*1e17 - i*1e17) / 1e17
See Basics of Cython
test.py
:
#!/usr/bin/env python
import math
import cProfile
import math2
""" Get the performance of both statements and math.modf """
X = -100.1323 # The number to be divided into integers and fractions
LOOPS = range(5 * 10 ** 6) # Number of loops
def scenario_a():
""" Tests the speed of the statements in a function using C/C++ support """
for _ in LOOPS:
i, f = math2.modf(X) # (-100, -0.1323)
def scenario_b():
""" Tests the speed of math.modf """
for _ in LOOPS:
f, i = math.modf(X) # (-0.13230000000000075, -100.0)
if __name__ == '__main__':
cProfile.run('scenario_a()')
cProfile.run('scenario_b()')
Result:
5000004 function calls in 1.629 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 1.629 1.629 <string>:1(<module>)
1 1.100 1.100 1.629 1.629 test.py:10(scenario_a)
1 0.000 0.000 1.629 1.629 {built-in method builtins.exec}
5000000 0.529 0.000 0.529 0.000 {math2.modf}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
5000004 function calls in 1.802 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 1.802 1.802 <string>:1(<module>)
1 1.010 1.010 1.802 1.802 test.py:16(scenario_b)
1 0.000 0.000 1.802 1.802 {built-in method builtins.exec}
5000000 0.791 0.000 0.791 0.000 {built-in method math.modf}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
NOTE
modulo is faster to divide positive numbers, but cannot handle negative numbers without some extra work, which will make division slower for negative numbers. However, this is the fastest way to divide positive numbers.
i, f = int(x), x*1e17%1e17/1e17 # Divide a number (x) into integer and fraction
A positive value of the value 100.1323
will be divided as follows (100
, 0.1323
) and negative value will come out wrong (-100
, 0.8677
).

- 585
- 10
- 26
This is the way I do it:
num = 123.456
split_num = str(num).split('.')
int_part = int(split_num[0])
decimal_part = int(split_num[1])

- 39
- 5
-
5Depending on the use case, this probably won't work for numbers with zero after the decimal place (e.g. 123.0456) – Jon Oct 04 '16 at 08:24
-
You're right: it depends on the use case. If you try it with 123.0456 result is int_part = 123 and decimal_part = 456. In my use cases I found "the zero removal" usefull :) – holydrinker Jan 31 '18 at 08:17
This will accomplish the task without the issue of dropping leading zeroes (like holydrinker's answer):
Code
def extract_int_decimal():
'''get the integer and decimal parts of a given number
by converting it to string and using split method
'''
num = 1234.5678
split_num = str(num).split('.')
int_part = int(split_num[0])
decimal_part = int(split_num[1]) * 10 ** -len(split_num[1])
print("integer part:",int_part)
print("decimal part:",decimal_part)
extract_int_decimal()
Result
integer part: 1234
decimal part: 0.5678000000000001

- 20,799
- 66
- 75
- 101

- 43
- 6
If you don't mind using NumPy, then:
In [319]: real = np.array([1234.5678])
In [327]: integ, deci = int(np.floor(real)), np.asscalar(real % 1)
In [328]: integ, deci
Out[328]: (1234, 0.5678000000000338)

- 57,311
- 13
- 161
- 150