【问题标题】:Big-O of division师大O
【发布时间】:2013-01-18 09:18:48
【问题描述】:

在大多数现代 ISA 中,Big-O 是什么?是否有某种优化或者是天真的O(分子/分母)?我正在编写严重依赖模数运算的代码。

例如,执行 10/5 和 20/5 和 40/5 所需的相对时间是多少? Intel、nVidia、Qualcomm 等的现代处理器是否具有相同的 Big-O 划分?

注意:假设除法是 O(分子的大小),我在这里可能是错的,这个问题可能根本没有任何意义。如果是这样,请纠正我。

【问题讨论】:

  • 对于整数除法,它通常是恒定的,但延迟成本很高。
  • 我认为所有数学运算的大 O 为 1。
  • 不也依赖于所使用的除法算法吗? en.wikipedia.org/wiki/Division_%28electronics%29
  • @mamdouhalramadan 只是因为输入是固定大小的,但这是作弊。您不妨说“井指针是固定大小的,因此遍历链表(没有循环)是 O(1),因为它可以处理的最大节点数是恒定的”。除法的步数也取决于输入的值,具体取决于所使用的算法。
  • @Sibi:如果您认为它是位大小的函数:是的。但是由于 cpus 总是在一定的字长上工作,通常总是 O(1),不管你使用哪种算法。这是因为不同算法的运行时间取决于数据的位大小。只需将常量 32- 或 64 放入运行时公式中,您将获得算法的恒定运行时间(但请注意:它们可能差异很大 - 但这仅与实际性能/运行时相关,与 Big O 无关!)。

标签: algorithm architecture big-o division integer-division


【解决方案1】:

这个问题不太好。但这也不是那么“愚蠢”,所以我尝试回答/澄清一些观点:

几乎所有现代 CPU/GPU 都有除法指令。由于它适用于默认字长,它的速度有多快并不重要,就 Big-O 而言它是恒定的,所以它总是 O(1)。即使对于没有除法指令的嵌入式处理器、微控制器和类似物,这也是正确的,因为它是在软件中模拟的,并且软件模拟受字大小的限制,因此执行除法指令的时间总是恒定的操作(这意味着它也是 O(1))。

在谈到对非字长数据执行的操作时例外。发生这种情况,例如在谈论 BigInt 库时。但在这种情况下,所有运算(加法、乘法...)不再是 O(1),而是取决于数字的大小。

但请注意:Big-O 并未说明实际计算时间。它只是忽略常数因素的渐近行为。这意味着,即使您有两种采用 O(n) 的算法,时间差也可能是 1000 倍(或一百万或任何您想要的)。最好的例子:它是一个例如加法都是 O(1),但通常除法比加法需要更多的周期/时间来执行。

【讨论】:

  • java 中的 long 怎么样?在 32 位机器上,它将是字长的两倍。它还有 O(1) 运行时间吗?
  • 即使机器没有 64 位 div 指令,它也是 O(1),因为执行/模拟 32 位 64 位 div 的操作数总是恒定的指示。但同样:O 类是相同的,但实际执行时间的差异大约是 3-6 倍(只是猜测,可能更高或更低,很大程度上取决于所使用的平台/系统)。
  • 您还应该提到摊销复杂性。我不知道其他操作,但加法是摊销 O(1)。
【解决方案2】:

虽然您可以使用二进制除法创建自己的实现; https://www.youtube.com/watch?v=TPVFYoxna98

根据上一篇文章,我认为大多数处理器优化实际上会快得多。您需要查看您创建的字节码才能确定,但​​这可能涉及将内容放入处理器缓存中,因此您坚持将其作为最佳解决方案;

int a = ... int b = ...

int 商 = a / b; int 余数 = a - (商 * b);

即a=5, b=2 商:2 余数:1

从这里开始(虽然它有错误:)-); Java - get the quotient and remainder in the same step?

【讨论】:

    【解决方案3】:

    但是,如果您使用 2 的基数并且您知道这一点,则可以使用它进行优化;

    public class Foo {
      public static void println(String s) {
        System.out.println(s);
      }
      
      public static void main(String [] args) {
        int size = 100;
        int[] randoms = new int[size];
        for (int i = 0; i < randoms.length; i++) {
          randoms[i] = (int) (Math.random() * 1000);
        }
        
        for (int i = 0; i < randoms.length; i++) {
          int j = randoms[i];
          int k = j >> 3;
          int l = j - (k << 3);
          println("value " + i + " " + j );
          println(" " + j + " / 8 =  " + k + " remainder " + l );
        }
        //println("hey got " + c + " from " + a + " >> " + b);
        
      }
    }
    

    【讨论】:

    • 您应该清楚地说,除以 2 的幂的除法或模数可以通过二进制移位进行优化,而不是发布一个很长的示例。 (顺便说一句,Java 并不是处理器指令速度最底层的语言)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    相关资源
    最近更新 更多