为什么模运算符很慢?
Why is modulus operator slow?
"Programming Pearls" 书中的释义(关于旧机器上的 c 语言,因为这本书是 90 年代后期的):
整数算术运算(+
、-
、*
)可能需要大约 10 纳秒,而 %
运算符最多需要 100 纳秒。
- 为什么会有这么大的差异?
- 模运算符在内部如何工作?
- 在时间上和除法(
/
)一样吗?
modulus/modulo 运算通常被理解为取余运算的整数等效项 - 副作用或除法的对应物。
除了一些退化的情况(其中除数是运算基数的幂——即大多数数字格式的 2 的幂)这与整数除法一样昂贵!
所以真正的问题是,为什么整数除法如此昂贵?
我没有时间或专业知识来进行数学分析,所以我将求助于小学数学:
考虑笔记本中需要的计算行数(不包括输入):
- 等式:(布尔运算)本质上 none - 在计算机 "big 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 个步骤之一需要 O(1) 步时间的 32 倍,并且 O(N^2)需要 N 乘以 N(N 的平方)它的 N 个步骤的时间(或者对于某个常数 M 可能是 N 乘以 MN)。等等
在上面的工作中,我使用 O(N) 而不是 O(N^2) 进行加法运算,因为第一个输入的 32 位或 64 位是由 CPU 并行计算的。在假设的 1 位机器中,32 位加法运算将是 O(32^2) 并更改。同样的订单减少也适用于其他操作。
"Programming Pearls" 书中的释义(关于旧机器上的 c 语言,因为这本书是 90 年代后期的):
整数算术运算(+
、-
、*
)可能需要大约 10 纳秒,而 %
运算符最多需要 100 纳秒。
- 为什么会有这么大的差异?
- 模运算符在内部如何工作?
- 在时间上和除法(
/
)一样吗?
modulus/modulo 运算通常被理解为取余运算的整数等效项 - 副作用或除法的对应物。
除了一些退化的情况(其中除数是运算基数的幂——即大多数数字格式的 2 的幂)这与整数除法一样昂贵!
所以真正的问题是,为什么整数除法如此昂贵?
我没有时间或专业知识来进行数学分析,所以我将求助于小学数学:
考虑笔记本中需要的计算行数(不包括输入):
- 等式:(布尔运算)本质上 none - 在计算机 "big 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 个步骤之一需要 O(1) 步时间的 32 倍,并且 O(N^2)需要 N 乘以 N(N 的平方)它的 N 个步骤的时间(或者对于某个常数 M 可能是 N 乘以 MN)。等等
在上面的工作中,我使用 O(N) 而不是 O(N^2) 进行加法运算,因为第一个输入的 32 位或 64 位是由 CPU 并行计算的。在假设的 1 位机器中,32 位加法运算将是 O(32^2) 并更改。同样的订单减少也适用于其他操作。