dividir un número en partes enteras y decimales


91

¿Existe una forma pitónica de dividir un número 1234.5678en dos partes, (1234, 0.5678)es decir, la parte entera y la parte decimal?

Respuestas:


142

Utilizar math.modf:

import math
x = 1234.5678
math.modf(x) # (0.5678000000000338, 1234.0)

2
¡Perfecto! ¡Funciona muy bien con negativos también! Gracias
Doble AA

1
después de aplicar math.modf (x) ¿cómo puedo manejar los valores de resultado? Por ejemplo, si asigno 1234.0 a una variable, ¿cómo puedo hacerlo?
hakiko

3
dic, int = math.modf (1234.5678)
gbtimmon

17
No lo use intcomo nombre de variable, anulará la intfunción.
Holloway

2
@Trengot - Úselo int_si debe tener una variable que, cuando se lee en voz alta, se llama "int".
ArtOfWarfare

61

Podemos utilizar una función incorporada no famosa; divmod:

>>> s = 1234.5678
>>> i, d = divmod(s, 1)
>>> i
1234.0
>>> d
0.5678000000000338

4
Da resultados posiblemente poco intuitivos para números negativos: divmod(-4.5,1)da -5,0 y 0,5. El uso divmod(-4.5, -1)da 4.0 y -0.5.
Holloway

@Holloway no es poco intuitivo, proviene de las reglas matemáticas: en.wikipedia.org/wiki/Floor_and_ceiling_functions :)
Sviatoslav V.

43
>>> a = 147.234
>>> a % 1
0.23400000000000887
>>> a // 1
147.0
>>>

Si desea que la parte entera sea un número entero y no un flotante, utilice int(a//1)en su lugar. Para obtener la tupla en un solo pasaje:(int(a//1), a%1)

EDITAR: Recuerde que la parte decimal de un número flotante es aproximada , por lo que si desea representarlo como lo haría un humano, debe usar la biblioteca decimal


4
Resultados un poco confusos para números negativos -2.25 // 1 == -3.0y -2.25 % 1 == 0.75. Esto puede ser lo que el OP querría, ya que la parte int + la parte decimal sigue siendo igual al valor original. Por el contrario, math.modf(-2.25) == (-0.25, -2.0).
Andrew Clark

@Andrew - ¡buen punto! ¡Creo que la respuesta de @ mhyfritz es mejor, de todos modos!
mac

Agradable: creo que esta sería la forma más rápida de las que se muestran aquí teniendo en cuenta la advertencia de Andrew Clark para los números negativos
jacanterbury


7

Esta variante permite obtener la precisión deseada:

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

4

Esto también me funciona

>>> val_int = int(a)
>>> val_fract = a - val_int

0

Esta es la forma en que lo hago:

num = 123.456
split_num = str(num).split('.')
int_part = int(split_num[0])
decimal_part = int(split_num[1])

4
Dependiendo del caso de uso, esto probablemente no funcione para números con cero después del lugar decimal (por ejemplo, 123.0456)
Jon

Tienes razón: depende del caso de uso. Si lo intentas con 123.0456, el resultado es int_part = 123 y decimal_part = 456. En mis casos de uso, encontré "la eliminación de cero" útil :)
holydrinker

0

Si no le importa usar NumPy, entonces:

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)

0

Después de mirar varias de las respuestas. Se me han ocurrido estas dos afirmaciones que pueden dividir números positivos y negativos en partes enteras y fraccionarias sin comprometer la precisión. La prueba de rendimiento muestra que las dos nuevas declaraciones son más rápidas que math.modf, siempre que no se incluyan en su propia función o método.

i = int(x) # i contains a positive or negative integer
f = (x*1e17-i*1e17)/1e17 # f contains a positive or negative fraction

Por ejemplo 100.1323-> 100, 0.1323y -100.1323->-100, -0.1323

Guión de prueba:

#!/usr/bin/env python
import math
import cProfile

""" Get the performance of both statements vs math.modf. """

X = -100.1323
LOOPS = range(5*10**6)

def fun_a():
    """ The integer part (i) is an integer, and
        the fraction part (f) is a float.
        NOTE: I think this is the most correct way. """
    for _ in LOOPS:
        i = int(X) # -100
        f = (X*1e17-i*1e17)/1e17 # -0.1323

def fun_b():
    """ The integer (i) and fraction (f) part will
        come out as 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 fun_c():
    """ Performance test of the statements in a function.
        The integer part (i) is an integer, and
        the fraction part (f) is a float. """
    def modf(x):
        i = int(x)
        return i, (x*1e17-i*1e17)/1e17

    for _ in LOOPS:
        i, f = modf(X) # (-100, -0.1323)

def fun_d():
    for _ in LOOPS:
        f, i = math.modf(X) # (-100.0, -0.13230000000000075)

def fun_e():
    """ Convert the integer part to integer. """
    for _ in LOOPS:
        f, i = math.modf(X) # (-100.0, -0.13230000000000075)
        i = int(i) # -100

if __name__ == '__main__':
    cProfile.run('fun_a()')
    cProfile.run('fun_b()')
    cProfile.run('fun_c()')
    cProfile.run('fun_d()')
    cProfile.run('fun_e()')

Salida:

         4 function calls in 1.312 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    1.312    1.312 <string>:1(<module>)
        1    1.312    1.312    1.312    1.312 new1.py:10(fun_a)
        1    0.000    0.000    1.312    1.312 {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.887 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    1.887    1.887 <string>:1(<module>)
        1    1.887    1.887    1.887    1.887 new1.py:17(fun_b)
        1    0.000    0.000    1.887    1.887 {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.797 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    2.797    2.797 <string>:1(<module>)
        1    1.261    1.261    2.797    2.797 new1.py:23(fun_c)
  5000000    1.536    0.000    1.536    0.000 new1.py:27(modf)
        1    0.000    0.000    2.797    2.797 {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.852 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    1.852    1.852 <string>:1(<module>)
        1    1.050    1.050    1.852    1.852 new1.py:34(fun_d)
        1    0.000    0.000    1.852    1.852 {built-in method builtins.exec}
  5000000    0.802    0.000    0.802    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.467 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    2.467    2.467 <string>:1(<module>)
        1    1.652    1.652    2.467    2.467 new1.py:38(fun_e)
        1    0.000    0.000    2.467    2.467 {built-in method builtins.exec}
  5000000    0.815    0.000    0.815    0.000 {built-in method math.modf}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

NOTA:

La instrucción puede ser más rápida con módulo, pero el módulo no se puede utilizar para dividir números negativos en partes enteras y fracciones.

i, f = int(x), x*1e17%1e17/1e17 # x can not be negative
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.