diviser un nombre en parties entières et décimales


91

Existe-t-il une manière pythonique de diviser un nombre comme 1234.5678en deux parties, à (1234, 0.5678)savoir la partie entière et la partie décimale?

Réponses:


142

Utilisez math.modf:

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

2
Parfait! Fonctionne très bien avec les négatifs aussi! Merci
Double AA

1
après appliquer math.modf (x) comment puis-je gérer les valeurs de résultat? Par exemple, si j'assing 1234.0 à une variable, comment puis-je faire cela?
hakiko

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

17
Ne l'utilisez pas intcomme nom de variable, cela remplacera la intfonction.
Holloway

2
@Trengot - À utiliser int_si vous devez avoir une variable qui, lorsqu'elle est lue à voix haute, s'appelle "int".
ArtOfWarfare

61

Nous pouvons utiliser une fonction intégrée pas célèbre; divmod:

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

4
Donne des résultats éventuellement peu intuitifs pour les nombres négatifs: divmod(-4.5,1)donne -5,0 et 0,5. Utiliser divmod(-4.5, -1)donne 4,0 et -0,5.
Holloway

@Holloway ce n'est pas peu intuitif, cela vient des règles mathématiques: en.wikipedia.org/wiki/Floor_and_ceiling_functions :)
Sviatoslav V.

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

Si vous voulez que la partie entière soit un entier et non un flottant, utilisez à la int(a//1)place. Pour obtenir le tuple en un seul passage:(int(a//1), a%1)

EDIT: N'oubliez pas que la partie décimale d'un nombre flottant est approximative , donc si vous voulez le représenter comme le ferait un humain, vous devez utiliser la bibliothèque décimale


4
Résultats légèrement déroutants pour les nombres négatifs, -2.25 // 1 == -3.0et -2.25 % 1 == 0.75. Cela peut être ce que l'OP souhaiterait, car la partie int + la partie décimale est toujours égale à la valeur d'origine. En revanche, math.modf(-2.25) == (-0.25, -2.0).
Andrew Clark

@Andrew - bon point! Je pense que la réponse de @ mhyfritz est meilleure, de toute façon!
mac

Nice - Je pense que ce serait le moyen le plus rapide de ceux présentés ici en gardant à l'esprit la mise en garde d'Andrew Clark pour les nombres négatifs
jacanterbury


7

Cette variante permet d'obtenir la précision souhaitée:

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

Cela fonctionne aussi pour moi

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

0

Voici comment je le fais:

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

4
Selon le cas d'utilisation, cela ne fonctionnera probablement pas pour les nombres avec zéro après la décimale (par exemple 123,0456)
Jon

Vous avez raison: cela dépend du cas d'utilisation. Si vous l'essayez avec 123,0456, le résultat est int_part = 123 et decimal_part = 456. Dans mes cas d'utilisation, j'ai trouvé "la suppression du zéro" utile :)
holydrinker

0

Si cela ne vous dérange pas d'utiliser NumPy, alors:

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

Après avoir examiné plusieurs des réponses. J'ai trouvé ces deux déclarations qui peuvent diviser les nombres positifs et négatifs en parties entières et fractionnaires sans compromettre la précision. Le test de performance montre que les deux nouvelles instructions sont plus rapides que math.modf, tant qu'elles ne sont pas placées dans leur propre fonction ou méthode.

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

Par exemple 100.1323-> 100, 0.1323et -100.1323->-100, -0.1323

Script de test:

#!/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()')

Production:

         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}

REMARQUE:

L'instruction peut être plus rapide avec modulo, mais modulo ne peut pas être utilisé pour diviser des nombres négatifs en parties entières et fractionnaires.

i, f = int(x), x*1e17%1e17/1e17 # x can not be negative
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.