UFO ET IT

숫자를 정수 및 소수 부분으로 분할

ufoet 2023. 8. 21. 23:12
반응형

숫자를 정수 및 소수 부분으로 분할

다음과 같은 숫자를 나누는 비단조적인 방법이 있습니까?1234.5678두 부분으로 나누어(1234, 0.5678)즉, 정수 부분과 소수 부분?

사용:

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

잘 알려지지 않은 내장 함수인 divmod를 사용할 수 있습니다.

>>> s = 1234.5678
>>> i, d = divmod(s, 1)
>>> i
1234.0
>>> d
0.5678000000000338
>>> a = 147.234
>>> a % 1
0.23400000000000887
>>> a // 1
147.0
>>>

정수 부분을 플로트가 아닌 정수로 사용하려면 다음을 사용합니다.int(a//1)대신.단일 통로에서 튜플을 얻는 방법(int(a//1), a%1)

편집: 플로트 번호의 소수 부분은 근사하므로 사람이 표현하는 것처럼 표현하려면 소수 라이브러리를 사용해야 합니다.

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

양수에 효과가 있습니다.

이 변형을 통해 원하는 정밀도를 얻을 수 있습니다.

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

정확도(비트 오버플로)와 속도를 해치지 않고 양수와 음수를 정수와 분수로 나눌 수 있는 두 가지 문장을 생각해 냈습니다.

코드

# Divide a number (x) into integer and fraction
i = int(x) # Get integer
f = (x*1e17 - i*1e17) / 1e17 # Get fraction

값의 양의 값과 음의 값100.1323다음과 같이 나뉩니다(100,0.1323) 및 (-100,-0.1323) 어디에서math.modf결과는 (0.13230000000000075,100.0) 및 (-0.13230000000000075,-100.0).

속도 테스트

성능 테스트를 통해 두 문이 다음보다 빠름을 알 수 있습니다.math.modfC/C++ 확장은 이를 개선합니다.

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

결과:

         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++ 확장

저는 C/C++ 지원으로 두 개의 진술서를 작성하려고 노력했고 결과는 더 좋았습니다.Python 확장 모듈을 사용하면 보다 빠르고 정확한 방법을 얻을 수 있었습니다.math.modf.

math2.pyx:

def modf(number):
    cdef float num = <float> number
    cdef int i = <int> num
    return i, (num*1e17 - i*1e17) / 1e17

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

결과:

         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}

메모

모듈로는 양수를 나누는 것이 더 빠르지만, 약간의 추가 작업 없이 음수를 처리할 수 없으며, 이것은 음수에 대한 나눗셈을 더 느리게 만들 것입니다.하지만, 이것이 양수를 나누는 가장 빠른 방법입니다.

i, f = int(x), x*1e17%1e17/1e17 # Divide a number (x) into integer and fraction

값의 양의 값100.1323다음과 같이 나뉩니다(100,0.1323) 그러면 음수 값이 잘못 나올 것입니다(-100, 0.8677).

제 방식은 이렇습니다.

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

이렇게 하면 (성스러운 음주자의 대답처럼) 선도 0을 떨어뜨리는 문제 없이 작업을 수행할 수 있습니다.

코드

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

결과

integer part: 1234
decimal part: 0.5678000000000001

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)

언급URL : https://stackoverflow.com/questions/6681743/splitting-a-number-into-the-integer-and-decimal-parts

반응형