【问题标题】:Splitting a number into the integer and decimal parts将数字拆分为整数和小数部分
【发布时间】:2011-10-04 15:14:57
【问题描述】:

有没有一种 Python 的方法可以将 1234.5678 这样的数字分成两部分 (1234, 0.5678),即整数部分和小数部分?

【问题讨论】:

    标签: python


    【解决方案1】:

    这将完成任务,而不会丢失前导零(如 Holydrinker 的答案):

    代码

    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
    

    【讨论】:

    • 我根据我认为您最初的评论所回应的内容进行了编辑。如果我的解释不正确,请更新答案以使其准确。
    • 您的编辑是正确的,谢谢!
    【解决方案2】:

    我想出了两个语句,可以将正数和负数分成整数和分数,而不会影响准确性(位溢出)和速度。

    例如,值100.1323的正值或负值将被划分为:
    100.1323 -> (100, 0.1323)
    -100.1323 -> (@ 987654327@,-0.1323)

    代码

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

    速度测试

    性能测试表明这两条语句比math.modf快,只要不放入自己的函数或方法中即可。

    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
    

    Basics of 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.1323 -> (100, 0.1323)
    -100.1323 -> (@ 987654346@, 0.8677)

    【讨论】:

      【解决方案3】:

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

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

        使用math.modf:

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

        【讨论】:

        • 应用 math.modf(x) 后如何处理结果值?例如,如果我将 1234.0 分配给一个变量,我该怎么做?
        • @Trengot - 如果您必须有一个变量,当大声朗读时,该变量称为“int”,请使用 int_
        • @MarkDickinson 以及如何得到相反的结果,比如从 1234 和 5678 得到 1234.5678?
        • @Ethan:要获得 modf 操作的逆操作,您只需添加两个部分:1234 + 0.5678 = 1234.5678。你从哪里得到12345678?您的问题似乎与此答案无关。
        • @MarkDickinson 我一直在寻找一个从 2 个整数创建浮点数的函数,这就是我来到这里的方式,并在你提到 modf 后问了这个问题。我有 2 个整数:1234 和 5678(不是 0.5678)。所以,可以做到:(1234 - 0.0) + 5678*0.01。由于我必须在数千个这样的数据上运行它,因此正在寻找一些最佳例程(如果存在)。
        【解决方案5】:

        如果你不介意使用 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)
        

        【讨论】:

          【解决方案6】:

          这就是我的做法:

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

          【讨论】:

          • 根据使用情况,这可能不适用于小数点后为零的数字(例如 123.0456)
          • 你是对的:这取决于用例。如果您尝试使用 123.0456 结果是 int_part = 123 和 decimal_part = 456。在我的用例中,我发现“零删除”很有用 :)
          【解决方案7】:
          >>> a = 147.234
          >>> a % 1
          0.23400000000000887
          >>> a // 1
          147.0
          >>>
          

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

          编辑:记住the decimal part of a float number is approximate,所以如果你想像人类一样表示它,你需要使用decimal library

          【讨论】:

          • 负数的结果有点混乱,-2.25 // 1 == -3.0-2.25 % 1 == 0.75。这可能是 OP 想要的,因为 int 部分 + 小数部分仍然等于原始值。相比之下,math.modf(-2.25) == (-0.25, -2.0).
          • @Andrew - 好点!无论如何,我认为@mhyfritz 的答案更好!
          • 很好 - 我认为这将是此处显示的最快方法,同时牢记 Andrew Clark 对负数的警告
          【解决方案8】:

          我们可以使用一个不知名的内置函数; divmod:

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

          【讨论】:

          • 对负数给出可能不直观的结果:divmod(-4.5,1) 给出 -5.0 和 0.5。使用 divmod(-4.5, -1) 给出 4.0 和 -0.5。
          • @Holloway 这不是不直观的,它来自数学规则:en.wikipedia.org/wiki/Floor_and_ceiling_functions :)
          • @SviatoslavV。您提到的那些数学规则特别指出:x 的整数部分或整数部分,通常表示为 [ x ],如果 x 为非负数,则为 floor(x),否则为 ceiling(x)。
          【解决方案9】:
          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 - 请参阅 docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html 以及本网站上有关浮点精度的许多问题。
          • @iMom0 我知道你发表评论已经 9 年多了。但在那段时间里,我找到了一个更好的参考来解释那些浮点怪异:Is floating point math broken?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-01-06
          • 2020-05-18
          • 1970-01-01
          • 2012-05-28
          • 2013-03-21
          • 1970-01-01
          相关资源
          最近更新 更多