为啥模数运算符很慢?

Posted

技术标签:

【中文标题】为啥模数运算符很慢?【英文标题】:Why is modulus operator slow?为什么模数运算符很慢? 【发布时间】:2015-03-14 16:42:41 【问题描述】:

从“Programming Pearls”一书中转述(关于旧机器上的 c 语言,因为这本书是 90 年代后期的):

整数算术运算(+-*)可能需要大约 10 纳秒,而 % 运算符最多需要 100 纳秒。

为什么会有这么大的区别? 模数运算符在内部是如何工作的? 在时间上和除法(/)一样吗?

【问题讨论】:

作为一个练习,写出最简单的版本,比如除法,然后是模数。计算优化之前需要的每个指令。显然会有更高效的方法来做到这一点(甚至在您进行 CPU 级别优化之前),但它会让您了解其中的区别。 我很惊讶除法据报道与 *,-,+ 大致相同。即使在新的处理器上,划分也慢很多倍。 什么语言?除数是什么?您将模数称为 in-int 或 double 或 float 的类型是什么? @AlexBrown ..Language:C,通过模数运算符,我的意思是“%”操作符。例如:23413%34 啊哈!重新格式化您的问题,以便我可以用这些术语来理解它。 【参考方案1】:

模数/模运算通常被理解为取余运算的整数等价物——除法的副作用或对应物。

除了一些退化的情况(除数是运算基数的幂 - 即大多数数字格式的 2 的幂)之外,这与整数除法一样昂贵!

所以问题是,为什么整数除法如此昂贵?

我没有时间或专业知识来对此进行数学分析,所以我将求助于小学数学:

考虑以下所需的笔记本中的锻炼行数(不包括输入):

平等:(布尔运算)基本上没有 - 在计算机“大 O”术语中,这称为 O(1) 补充:二,从左到右,一行输出,一行进位。这是一个 O(N) 操作 长乘法:n*(n+1) + 2:每个数字乘积两行(总计一个,进位一个)加上最终总计和进位。所以 O(N^2) 但具有固定的 N(32 或 64),它可以在硅中流水线化到小于这个值 长除法:未知,取决于参数大小 - 它是递归下降,有些实例下降速度比其他实例快(1,000,000 / 500,000 需要的行数少于 1,000 / 7)。此外,每个步骤本质上都是一系列乘法,以隔离最接近的因素。 (尽管存在多种算法)。感觉就像一个带有变量 N 的 O(N^3)

因此,简单来说,这应该让您了解为什么除法和模数会变慢:计算机仍然必须以与您在小学时一样的逐步方式进行长除法。

如果这对您没有意义;你的学校数学教育可能比我的更现代(30 多年前)。


上面用作 O(something) 的 Order/Big O 表示法根据其输入的大小表示计算的复杂性,并表示有关其执行时间的事实。 http://en.m.wikipedia.org/wiki/Big_O_notation

O(1) 以恒定(但可能很长)时间执行。 O(N) 花费的时间与其数据的大小一样多——因此,如果数据是 32 位,则计算其 N 个步骤中的一个步骤需要 32 倍的 O(1) 时间,并且 O(N^2)需要 N 乘以 N(N 平方)其 N 步的时间(或者对于某个常数 M,可能需要 N 乘以 MN)。等等。


在上述工作中,我使用 O(N) 而不是 O(N^2) 进行加法,因为第一个输入的 32 或 64 位是由 CPU 并行计算的。在假设的 1 位机器中,32 位加法运算将是 O(32^2) 并且会发生变化。同样的订单减少也适用于其他操作。

【讨论】:

实际上,如果您要在笔记本中计算乘法,您可能会考虑使用 Karatsuba 的方法,或者如果您有点疯狂 - FFT。见here。

以上是关于为啥模数运算符很慢?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 C++ 使用模数时输出负数?

在批处理脚本中执行模数运算

Java基本语法--运算符

在 css calc 函数中使用模数

如何在 C# 中计算整数的除法和模数?

java如何用负数进行模数计算?