розбиття числа на цілу та десяткову частини


91

Чи існує пітонічний спосіб поділу числа, наприклад, 1234.5678на дві частини, (1234, 0.5678)тобто цілу частину та десяткову частину?

Відповіді:


142

Використання math.modf:

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

2
Ідеально! Також чудово працює з негативами! Подяка
Double AA

1
після застосування math.modf (x), як я можу обробляти значення результатів? Наприклад, якщо я присвоюю змінну 1234.0, як я можу це зробити?
hakiko

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

17
Не використовуйте intяк ім'я змінної, це замінить intфункцію.
Holloway

2
@Trengot - Використовуйте, int_якщо ви повинні мати змінну, яка під час читання вголос називається "int".
ArtOfWarfare

61

Ми можемо використовувати невідому вбудовану функцію; divmod:

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

4
Дає, можливо, неінтуїтивні результати для від’ємних чисел: divmod(-4.5,1)дає -5,0 та 0,5. Використання divmod(-4.5, -1)дає 4.0 і -0.5.
Holloway

@Holloway це не інтуїтивно, це походить від математичних правил: en.wikipedia.org/wiki/Floor_and_ceiling_functions :)
Святослав В.

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

Якщо ви хочете, щоб ціла частина була цілою, а не плаваючою, використовуйте її int(a//1). Щоб отримати кортеж за один прохід:(int(a//1), a%1)

РЕДАГУВАТИ: Пам'ятайте, що десяткова частина числа з плаваючою лінією є приблизною , тому, якщо ви хочете подати її так, як це робить людина, вам потрібно використовувати десяткову бібліотеку


4
Трохи заплутані результати для від'ємних чисел -2.25 // 1 == -3.0і -2.25 % 1 == 0.75. Це може бути те, що хотів би ОП, оскільки int частина + десяткова частина все ще дорівнює вихідному значенню. На відміну від цього math.modf(-2.25) == (-0.25, -2.0).
Ендрю Кларк,

@Andrew - хороший момент! Я думаю, що відповідь @ mhyfritz у будь-якому разі краща!
mac

Приємно - я вважаю, це був би найшвидший спосіб із тих, що показані тут, маючи на увазі застереження Ендрю Кларка щодо від’ємних чисел
jacanterbury

14
intpart,decimalpart = int(value),value-int(value)

Працює для додатних чисел.


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

1
@ iMom0 - Див. docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html та численні запитання на цьому веб-сайті щодо точності з плаваючою комою.
Марк Ренсом

7

Цей варіант дозволяє отримати бажану точність:

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

Це також працює для мене

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

0

Це я так роблю:

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

4
Залежно від випадку використання, це, ймовірно, не спрацює для чисел з нулем після десяткової коми (наприклад, 123.0456)
Джон,

Ви маєте рацію: це залежить від випадку використання. Якщо ви спробуєте з 123.0456, результат буде int_part = 123 і decimal_part = 456. У моїх випадках я знайшов корисне "нульове видалення" :)
Holydrinker

0

Якщо ви не проти використовувати NumPy, тоді:

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

Переглянувши кілька відповідей. Я придумав ці два твердження, які можуть розділити позитивні та від’ємні числа на цілі та дробові частини без шкоди для точності. Тест продуктивності показує, що два нові твердження швидші, ніж до math.modfтих пір, поки вони не вводяться у власну функцію чи метод.

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

Наприклад 100.1323-> 100, 0.1323та -100.1323->-100, -0.1323

Тестовий сценарій:

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

Вихід:

         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}

ПРИМІТКА:

Оператор може бути швидшим за модулем, але модуль не може використовуватися для розділення від’ємних чисел на цілі та дробові частини.

i, f = int(x), x*1e17%1e17/1e17 # x can not be negative
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.