将数字拆分为整数和小数部分

Dou*_* AA 73 python floating-point split

是否存在将数字1234.5678分成两部分的pythonic方法,(1234, 0.5678)即整数部分和小数部分?

mhy*_*itz 121

用途math.modf:

import math
x = 1234.5678
math.modf(x) # (0.5678000000000338, 1234.0)
Run Code Online (Sandbox Code Playgroud)

  • 不要使用`int`作为变量名,它将覆盖`int`函数. (16认同)
  • 完善!与否定也很好用!谢谢 (2认同)
  • dec,int = math.modf(1234.5678) (2认同)
  • @Trengot - 使用`int_`如果你必须有一个变量,当大声朗读时,它被称为"int". (2认同)

utd*_*mir 55

我们可以使用一个不着名的内置功能; divmod:

>>> s = 1234.5678
>>> i, d = divmod(s, 1)
>>> i
1234.0
>>> d
0.5678000000000338
Run Code Online (Sandbox Code Playgroud)

  • 给负数提供可能不直观的结果:`divmod(-4.5,1)`给出-5.0和0.5.使用`divmod(-4.5,-1)`给出4.0和-0.5. (4认同)

mac*_*mac 36

>>> a = 147.234
>>> a % 1
0.23400000000000887
>>> a // 1
147.0
>>>
Run Code Online (Sandbox Code Playgroud)

如果您希望整数部分为整数而不是浮点数,请int(a//1)改用.要在单个段落中获取元组:(int(a//1), a%1)

编辑:请记住,浮点数的小数部分是近似值,所以如果你想像人类那样表示它,你需要使用小数库

  • 负数稍微混淆的结果,`-2.25 // 1 == -3.0`和`-2.25%1 == 0.75`.这可能是OP想要的,因为int part + decimal部分仍然等于原始值.相比之下,`math.modf(-2.25)==( - 0.25,-2.0)`. (3认同)

Mar*_*som 13

intpart,decimalpart = int(value),value-int(value)
Run Code Online (Sandbox Code Playgroud)

适用于正数.


dan*_*ann 6

此变体允许获得所需的精度:

>>> 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)
Run Code Online (Sandbox Code Playgroud)


Dib*_* Dk 6

我提出了两个语句,可以将正数和负数分为整数和分数,而不影响精度(位溢出)和速度。

代码

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

该值的正值和负值100.1323将按如下方式除法 ( 100, 0.1323) 和 ( -100, -0.1323) ,其中math.modf结果将为 ( 0.13230000000000075, 100.0) 和 ( -0.13230000000000075,-100.0 )。

速度测试

性能测试表明这两条语句的速度比math.modf只要不将这两个语句放入自己的函数或方法中(C/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()')
Run Code Online (Sandbox Code Playgroud)

结果:

         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}
Run Code Online (Sandbox Code Playgroud)

C/C++ 扩展

我尝试用 C/C++ 支持来编译这两个语句,结果更好。使用Python扩展模块,可以获得比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
Run Code Online (Sandbox Code Playgroud)

请参阅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()')
Run Code Online (Sandbox Code Playgroud)

结果:

         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}
Run Code Online (Sandbox Code Playgroud)

笔记

模除正数的速度更快,但如果没有一些额外的工作就无法处理负数,这将使负数的除法速度变慢。然而,这是除正数最快的方法。

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

正值的除法100.1323如下(100, 0.1323),负值的除法错误(-100, 0.8677)。