【问题标题】:Python 3 integer division. How to make math operators consistent with CPython 3 整数除法。如何使数学运算符与 C 一致
【发布时间】:2011-03-19 23:32:28
【问题描述】:

我需要将很多公式从 C 移植到 Python,反之亦然。确保过程中没有中断的最佳方法是什么?

我主要担心自动 int/int = float 转换。

【问题讨论】:

    标签: python-3.x


    【解决方案1】:

    您可以使用// 运算符。它执行整数除法,但与您对 C 的期望不同:

    引用here:

    // 运算符执行一种古怪的整数除法。当。。。的时候 结果是肯定的,你可以想到 它截断(不四舍五入)为 0 小数位,但要小心 那个。

    当整数除负数时, // 运算符“向上”四舍五入 到最接近的整数。数学上 说起来,它是四舍五入的,因为 -6 小于 -5,但它可能会跳闸 如果你期待它,你就起来 截断为 -5。

    例如,Python 中的-11 // 2 返回-6,而C 中的-11 / 2 返回-5。 我建议编写一个“模拟”C 行为的自定义整数除法函数并对其进行彻底的单元测试。

    我在上面链接的页面也有一个指向PEP 238 的链接,其中包含一些关于除法的有趣背景信息以及从 Python 2 到 3 的变化。关于整数除法的使用方法有一些建议,例如 divmod(x, y)[0]int(x/y) 为正数,也许你会在那里找到更多有用的东西。

    【讨论】:

    • 好一个。不知道//和C的地板事业部不一样。
    • 需要// 的“古怪”定义才能使%古怪。
    【解决方案2】:

    在 C 中:

    -11/2 = -5
    

    在 Python 中:

    -11/2 = -5.5
    

    在 Python 中也是如此:

    -11//2 = -6
    

    要实现类似 C 的行为,请在 Python 中编写 int(-11/2)。这将评估为-5

    【讨论】:

      【解决方案3】:

      反方向:

      由于 Python 3 divmod(或 //)整数除法要求余数在非零余数情况下与除数具有相同的符号,因此它与许多其他语言不一致(引用自 1.4. Integer Arithmetic )。

      为了让你的“C-like”结果与 Python 相同,你应该将余数结果与除数进行比较(建议:通过 xor 对符号位等于 1,或乘以负结果),如果不同,添加余数的除数,商减1。

              // Python Divmod requires a remainder with the same sign as the divisor for
              // a non-zero remainder
      
              // Assuming isPyCompatible is a flag to distinguish C/Python mode
              isPyCompatible *= (int)remainder;
              if (isPyCompatible)
              {
                  int32_t xorRes = remainder ^ divisor;
                  int32_t andRes = xorRes & ((int32_t)((uint32_t)1<<31));
                  if (andRes)
                  {
                      remainder += divisor;
                      quotient -= 1;
                  }
              }
      

      (感谢 Gawarkiewicz M. 指出这一点。)

      【讨论】:

        【解决方案4】:

        用 C 语义计算整数除法的一些方法如下:

        def div_c0(a, b):
            if (a >= 0) != (b >= 0) and a % b:
                return a // b + 1
            else:
                return a // b
        
        def div_c1(a, b):
            q, r = a // b, a % b
            if (a >= 0) != (b >= 0) and a % b:
                return q + 1
            else:
                return q
        
        def div_c2(a, b):
            q, r = divmod(a, b)
            if (a >= 0) != (b >= 0) and a % b:
                return q + 1
            else:
                return q
        
        def mod_c(a, b):
            return (a % b if b >= 0 else a % -b) if a >= 0 else (-(-a % b) if b >= 0 else a % b)
        
        
        def div_c3(a, b):
            r = mod_c(a, b)
            return (a - r) // b
        

        有时间安排:

        n = 100
        l = [x for x in range(-n, n + 1)]
        ll = [(a, b) for a, b in itertools.product(l, repeat=2) if b]
        
        
        funcs = div_c0, div_c1, div_c2, div_c3
        for func in funcs:
            correct = all(func(a, b) == funcs[0](a, b) for a, b in ll)
            print(func.__name__, 'correct:', correct)
            %timeit [func(a, b) for a, b in ll]
            print()
        
        div_c0 correct: True
        100 loops, best of 3: 8.42 ms per loop
        
        div_c1 correct: True
        100 loops, best of 3: 10 ms per loop
        
        div_c2 correct: True
        100 loops, best of 3: 12.3 ms per loop
        
        div_c3 correct: True
        100 loops, best of 3: 13.1 ms per loop
        

        表示第一种方法最快。


        要使用 Python 实现 C 的 %,请参阅 here

        【讨论】:

          【解决方案5】:

          您需要知道公式的作用,并了解 C 实现以及如何在 Python 中实现它。但除非你在做整数数学,否则它应该非常相似,如果你正在在做整数数学,问题就是为什么。 :)

          整数数学要么是出于某些特定目的(通常与计算机相关),要么是因为在进行大量计算时它比浮点数更快,就像 Fractint 对分形所做的那样,在这种情况下,Python 通常不是正确的选择。 ;)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-09-19
            • 1970-01-01
            相关资源
            最近更新 更多