Division by Invariant Integers using Multiplication

在处理器中,整数除法的成本通常是整数乘法的几倍:

  • 流水线式的组合乘法器通常在不到10个周期内完成操作;
  • 而对于整数除法则没有硬件支持,或者使用的迭代除法器比乘法器慢几倍。

表 1.1 比较了一些处理器上乘法和除法的时间。这张表展示了乘法和除法时间差距的增长趋势。
在这里插入图片描述因此, Division by Invariant Integers using Multiplication 中提出了使用整数乘法进行任意非零整数常数和运行时不变量之间除法的算法。

文档 4. Instruction tables 中记录了更广泛的处理指令性能,其中 Intel IceLake 处理器的乘除法指令延迟和吞吐倒数如下表所示:
在这里插入图片描述
可以看出,在现代 CPU 处理器上除法开销大的情况并未发生改变。NVIDIA 和 AMD GPU 均不支持整数除法指令,CUDA C++ Programming Guide 5.4.1. Arithmetic Instructions 中指出整数除法和取模运算可能会编译出多达20条指令,建议开发者在某些情况下使用位运算来替代。很多深度学习框架和加速库中均采用论文所提出的算法来加速常量除法运算。

2 Mathematical notations

x x x 是一个实数。那么

  • ⌊ x ⌋ \lfloor x\rfloor x 表示不超过 x x x 的最大整数,
  • ⌈ x ⌉ \lceil x \rceil x 表示不小于 x x x 的最小整数。

T R U N C ( x ) \mathrm{TRUNC}(x) TRUNC(x) 表示 x x x 的整数部分,向零取整。形式上,

  • 如果 x ≥ 0 x \ge 0 x0,则 T R U N C ( x ) = ⌊ x ⌋ \mathrm{TRUNC}(x) = \lfloor x\rfloor TRUNC(x)=x
  • 如果 x ≤ 0 x \le 0 x0,则 T R U N C ( x ) = ⌈ x ⌉ \mathrm{TRUNC}(x) = \lceil x \rceil TRUNC(x)=x

x x x 的绝对值是 ∣ x ∣ |x| x。对于 x > 0 x > 0 x>0 x x x 以 2 为(实数)底的对数为 log ⁡ 2 x \log_2 x log2x

乘法写为 x ∗ y x ∗ y xy

如果 x x x y y y n n n 是整数且 n ≠ 0 n \neq 0 n=0,则 x ≡ y ( m o d n ) x \equiv y (\mathrm{mod}\, n) xy(modn) 意味着 x − y x − y xy n n n 的倍数。

在语言定义中常见两种余数运算符。有时余数带有被除数的符号,有时带有除数的符号。我们使用 Ada 符号。
n r e m d = n − d ∗ T R U N C ( n / d ) ( sign of dividend ) , n m o d d = n − d ∗ ⌊ n / d ⌋ ( sign of divisor ) . \begin{aligned} n \enspace\mathrm{rem}\enspace d &= n − d ∗ \mathrm{TRUNC}(n/d) \quad &(\text{sign of dividend}),\\ n \enspace mod \enspace d &= n − d ∗ \lfloor n/d \rfloor &(\text{sign of divisor}). \end{aligned} nremdnmodd=ndTRUNC(n/d)=ndn/d(sign of dividend),(sign of divisor).

Fortran 90 中的名称是 MOD 和 MODULO。在 C 语言中,对余数的定义取决于具体的实现(许多 C 实现将有符号商向零舍入并使用 r e m \mathrm{rem} rem 余数)。还有其他一些建议的定义[6, 7]。

如果 n n n 是一个 udwordsdword,那么 H I G H ( n ) \mathrm{HIGH}(n) HIGH(n) L O W ( n ) \mathrm{LOW}(n) LOW(n) 分别表示 n n n 的最高有效半部和最低有效半部:

  • L O W ( n ) \mathrm{LOW}(n) LOW(n) 是一个 udword
  • 如果 n n nudword H I G H ( n ) \mathrm{HIGH}(n) HIGH(n) 是一个 udword ;如果 n n nsdword H I G H ( n ) \mathrm{HIGH}(n) HIGH(n)sword

在这两种情况下, n = 2 N ∗ H I G H ( n ) + L O W ( n ) n = 2^N ∗ \mathrm{HIGH}(n) + \mathrm{LOW}(n) n=2NHIGH(n)+LOW(n)

3 Assumed instructions

建议的代码假设在 N 位机器上执行表 3.1 中的操作。某些原语,如加载常量和操作数,在符号中是隐含的,并且不包含在操作计数中。
在这里插入图片描述

第8节中的算法要求能够对两个双字进行加减运算,得到一个双字结果;这通常会扩展为2-4条指令。

处理常数除数的算法需要在编译时对 udword 进行算术运算。

处理运行时不变除数的算法需要取一个正整数以2为底的对数(有时向上取整,有时向下取整),并需要将一个 udword 除以一个 uword。如果这些算法只针对常数除数,那么这些操作只需要在编译时进行。如果该架构有一个前导零计数(LDZ)指令,那么可以从以下方式中找到这些对数
⌈ log ⁡ 2 x ⌉ = N − L D Z ( x − 1 ) , ⌊ log ⁡ 2 x ⌋ = N − 1 − L D Z ( x ) ( 1 ≤ x ≤ 2 N − 1 ) . \begin{aligned} \lceil \log_2 x \rceil &= N − \mathrm{LDZ}(x − 1), \\ \lfloor \log_2 x \rfloor &= N − 1 − \mathrm{LDZ}(x)\qquad (1 ≤ x ≤ 2N − 1). \end{aligned} log2xlog2x=NLDZ(x1),=N1LDZ(x)(1x2N1).

某些算法可能会产生诸如 S R L ( x , 0 ) \mathrm{SRL}(x, 0) SRL(x,0) − ( x − y ) −(x − y) (xy) 等表达式;优化器应该进行显而易见的简化。一些描述显示了 2 N 2^N 2N 的加法或减法,这实际上是一个无操作(no-op)。

如果一个架构缺少算术右移,则可以根据下面的等式来计算它:

S R A ( x , ℓ ) = S R L ( x + 2 N − 1 , ℓ ) − 2 N − 1 − ℓ whenever  0 ≤ n < 2 N \mathrm{SRA}(x, \ell) = \mathrm{SRL}(x + 2^{N −1}, \ell) − 2^{N −1−\ell} \quad \text{whenever } 0 \le n < 2^N SRA(x,)=SRL(x+2N1,)2N1whenever 0n<2N

如果一个架构只有 M U L S H \mathrm{MULSH} MULSH M U L U H \mathrm{MULUH} MULUH 中的一个,那么另一个可以通过以下方式计算得出:

M U L U H ( x , y ) = M U L S H ( x , y ) + A N D ( x , X S I G N ( y ) ) + A N D ( y , X S I G N ( x ) ) \mathrm{MULUH}(x, y) = \mathrm{MULSH}(x, y) + \mathrm{AND}(x, \mathrm{XSIGN}(y))+ \mathrm{AND}(y, \mathrm{XSIGN}(x)) MULUH(x,y)=MULSH(x,y)+AND(x,XSIGN(y))+AND(y,XSIGN(x))
对于任意 N 位模式的 x x x y y y(在 M U L U H \mathrm{MULUH} MULUH 中被解释为 uword,在 M U L S H \mathrm{MULSH} MULSH 中被解释为 sword)。

4 Unsigned division

假设我们想要编译一个无符号除法 q = ⌊ n / d ⌋ q = \lfloor n/d\rfloor q=n/d,其中 0 < d < 2 N 0 < d < 2^N 0<d<2N 是一个常数或运行时不变量, 0 ≤ n < 2 N 0 \le n < 2^N 0n<2N 是变量。
让我们尝试找到 1 / d 1/d 1/d 的一个有理近似 m / 2 N + ℓ m/2^{N +\ell} m/2N+,使得

⌊ n d ⌋ = ⌊ m ∗ n 2 N + ℓ ⌋ whenever  0 ≤ n < 2 N \lfloor \frac{n}{d}\rfloor = \lfloor \frac{m*n}{2^{N +\ell}}\rfloor \quad \text{whenever } 0 \le n < 2^N dn=2N+mnwhenever 0n<2N

n = d n = d n=d 代入上式中显示我们需要 2 N + ℓ ≤ m ∗ d 2^{N +\ell} \le m * d 2N+md。设置 n = q ∗ d − 1 n = q * d - 1 n=qd1 显示 2 N + ℓ ∗ q > m ∗ ( q ∗ d − 1 ) 2^{N +\ell} * q > m * (q * d - 1) 2N+q>m(qd1)。乘以 d d d 得出 ( m ∗ d − 2 N + ℓ ) ∗ ( q ∗ d − 1 ) < 2 N + ℓ (m * d - 2^{N +\ell}) * (q * d - 1) < 2^{N +\ell} (md2N+)(qd1)<2N+。 如果 m ∗ d − 2 N + ℓ ≤ 2 m * d - 2^{N +\ell} \le 2 md2N+2,则对于所有小于 2 N 2^N 2N q ∗ d − 1 q * d - 1 qd1 的值,这个不等式都成立。下面的定理 4.2 声明这些条件是充分的,因为当 n < 2 N n < 2^N n<2N 时,最大相对误差( 2 N 2^N 2N分之一)太小,不足以影响商。

定理 4.2 假设 m m m d d d ℓ \ell 是非负整数,使得 d ≠ 0 d \neq 0 d=0
2 N + ℓ ≤ m ∗ d ≤ 2 N + ℓ + 2 ℓ (4.3) 2^{N+\ell} \le m * d \le 2^{N+\ell} + 2^\ell \qquad\text{(4.3)} 2N+md2N++2(4.3)

那么对于每一个整数 n n n 0 ≤ n < 2 N 0 \le n < 2^N 0n<2N ⌊ n d ⌋ = ⌊ m ∗ n / 2 N + ℓ ⌋ \lfloor \frac{n}{d}\rfloor = \lfloor m*n / 2^{N +\ell}\rfloor dn=mn/2N+

证明: 定义 k = m ∗ d − 2 N + ℓ k = m * d - 2^{N +\ell} k=md2N+。那么根据假设有 0 ≤ k ≤ 2 ℓ 0 \le k \le 2^\ell 0k2。给定 0 ≤ n < 2 N 0 \le n < 2^N 0n<2N n n n,写作 n = q ∗ d + r n = q * d + r n=qd+r,其中 q = ⌊ n / d ⌋ q = \lfloor n/d \rfloor q=n/d 0 ≤ r ≤ d − 1 0 \le r \le d - 1 0rd1。我们必须证明 q = ⌊ m ∗ n / 2 N + ℓ ⌋ q = \lfloor m * n/ 2^{N +\ell}\rfloor q=mn/2N+。通过计算得出

m ∗ n 2 N + ℓ − q = m ∗ d d ∗ n 2 N + ℓ − q = k + 2 N + ℓ d ∗ n 2 N + ℓ − q = k ∗ n d ∗ 2 N + ℓ + n d − n − r d = k 2 ℓ ∗ n 2 N ∗ 1 d + r d \begin{aligned} \frac{m ∗ n}{2^{N +\ell}} - q &= \frac{m * d}{d}*\frac{n}{2^{N +\ell}}- q \\ &= \frac{k + 2^{N +\ell}}{d}*\frac{n}{2^{N +\ell}}- q \\ &= \frac{k ∗ n}{d*2^{N +\ell}} + \frac{n}{d} - \frac{n-r}{d}\\ &= \frac{k}{2^\ell}*\frac{n}{2^N}*\frac{1}{d} + \frac{r}{d} \end{aligned} 2N+mnq=dmd2N+nq=dk+2N+2N+nq=d2N+kn+dndnr=2k2Nnd1+dr

因为 0 ≤ k ≤ 2 ℓ 0 \le k \le 2^\ell 0k2 0 ≤ n < 2 N 0 \le n < 2^N 0n<2N 0 ≤ r ≤ d − 1 0 \le r \le d - 1 0rd1
0 2 ℓ ∗ 0 2 N ∗ 1 d + 0 d ≤ k 2 ℓ ∗ n 2 N ∗ 1 d + r d ≤ 2 ℓ 2 ℓ ∗ 2 N − 1 2 N ∗ 1 d + d − 1 d 0 ≤ k 2 ℓ ∗ n 2 N ∗ 1 d + r d ≤ 2 N − 1 2 N ∗ 1 d + d − 1 d 0 ≤ k 2 ℓ ∗ n 2 N ∗ 1 d + r d ≤ 1 − 1 2 N ∗ d 0 ≤ k 2 ℓ ∗ n 2 N ∗ 1 d + r d < 1 \begin{aligned} \frac{0}{2^\ell}*\frac{0}{2^N}*\frac{1}{d} + \frac{0}{d} \le &\frac{k}{2^\ell}*\frac{n}{2^N}*\frac{1}{d} + \frac{r}{d}\le \frac{2^\ell}{2^\ell}*\frac{2^N -1}{2^N}*\frac{1}{d} + \frac{d - 1}{d}\\ 0 \le &\frac{k}{2^\ell}*\frac{n}{2^N}*\frac{1}{d} + \frac{r}{d}\le \frac{2^N -1}{2^N}*\frac{1}{d} + \frac{d - 1}{d}\\ 0 \le &\frac{k}{2^\ell}*\frac{n}{2^N}*\frac{1}{d} + \frac{r}{d}\le 1 − \frac{1}{ 2^N ∗ d} \\ 0 \le &\frac{k}{2^\ell}*\frac{n}{2^N}*\frac{1}{d} + \frac{r}{d} < 1 \end{aligned} 202N0d1+d00002k2Nnd1+dr222N2N1d1+dd12k2Nnd1+dr2N2N1d1+dd12k2Nnd1+dr12Nd12k2Nnd1+dr<1
这个差值是非负的,并且不超过 1。

如果不等式(4.3)成立,定理 4.2 允许用 m ∗ n / 2 N + ℓ m * n/ 2^{N +\ell} mn/2N+ 的乘法来替代除以 d d d。一般来说,我们要求 2 ℓ ≥ d − 1 2^{\ell} \ge d-1 2d1 以确保在区间 [ 2 N + ℓ , 2 N + ℓ + 2 ℓ ] [2^{N +\ell}, 2^{N +\ell} + 2^\ell] [2N+,2N++2] 中存在 d d d 的适当倍数。为了与有符号除法的算法(第5节和第6节)兼容,选择 m ∗ d > 2 N + ℓ m * d > 2^{N +\ell} md>2N+,尽管定理 4.2 允许相等。由于 m m m 几乎可以大到 2 N + 1 2^{N +1} 2N+1,我们不直接乘以 m m m,而是分别乘以 2 N 2^N 2N m − 2 N m - 2^N m2N。这引出了图 4.1 中的代码。在计算仅依赖于除数的常数之后,每个商的成本为1次乘法、2次加法/减法以及2次移位。
在这里插入图片描述

图 4.1 的解释:

  • 如果 d = 1 d = 1 d=1,那么 ℓ = 0 \ell = 0 =0,所以 m ′ = 1 m' = 1 m=1 s h 1 = s h 2 = 0 sh_1 = sh_2 = 0 sh1=sh2=0。代码计算 t 1 = ⌊ 1 ∗ n / 2 N ⌋ = 0 t_1 = \lfloor 1 ∗ n/2^N \rfloor = 0 t1=1n/2N=0 q = n q = n q=n
  • d > 1 d > 1 d>1,则 ℓ ≥ 1 \ell≥1 1,故 s h 1 = 1 sh_1 = 1 sh1=1 s h 2 = ℓ − 1 sh_2 =\ell −1 sh2=1。由于 m ′ ≤ 2 N ∗ ( 2 ℓ − d ) d + 1 ≤ 2 N ∗ ( d − 1 ) d + 1 < 2 N m' \le \frac{2^N ∗ (2^\ell − d)}{d} + 1 \le \frac{2^N ∗ (d − 1)}{d} + 1 < 2^N md2N(2d)+1d2N(d1)+1<2N m ′ m' m 的值可以置于一个 uword 中。由于 0 ≤ t 1 ≤ n 0 \le t_1 \le n 0t1n q q q 的公式简化为
    q = S R L ( t 1 + S R L ( n − t 1 , 1 ) , ℓ − 1 ) = ⌊ t 1 + ⌊ ( n − t 1 ) 2 ⌋ 2 ℓ − 1 ⌋ = ⌊ ⌊ 2 ∗ t 1 2 + ( n − t 1 ) 2 ⌋ 2 ℓ − 1 ⌋ (4.5) = ⌊ ⌊ ( t 1 + n ) / 2 ⌋ 2 ℓ − 1 ⌋ = ⌊ t 1 + n 2 ℓ ⌋ \begin{aligned} q &= \mathrm{SRL}(t_1 + \mathrm{SRL}(n − t_1, 1), \ell− 1)\\ &=\lfloor \frac{t_1 + \lfloor \frac{(n − t_1)}{2} \rfloor}{2^{\ell− 1}}\rfloor\\ &=\lfloor \frac{\lfloor \frac{2*t_1}{2} + \frac{(n − t_1)}{2} \rfloor}{2^{\ell− 1}}\rfloor \qquad\text{(4.5)}\\ &=\lfloor \frac{\lfloor(t_1 + n)/2\rfloor}{2^{\ell− 1}} \rfloor\\ &=\lfloor \frac{t_1 + n}{2^{\ell}} \rfloor \end{aligned} q=SRL(t1+SRL(nt1,1),1)=21t1+2(nt1)=2122t1+2(nt1)(4.5)=21⌊(t1+n)/2=2t1+n

t 1 + n = ⌊ m ′ ∗ n / 2 N ⌋ + n = ⌊ ( m ′ + 2 N ) ∗ n / 2 N ⌋ t_1 + n = \lfloor m' ∗ n/2^N \rfloor + n = \lfloor (m' + 2^N)∗ n/2^N \rfloor t1+n=mn/2N+n=⌊(m+2N)n/2N。设 m = m ′ + 2 N = ⌊ 2 N + ℓ / d ⌋ + 1 m = m' + 2^N = \lfloor 2^{N+\ell}/d\rfloor + 1 m=m+2N=2N+/d+1。由于 2 N + ℓ < m ∗ d ≤ 2 N + ℓ + 2 ℓ 2^{N +\ell} < m ∗ d ≤ 2^{N +\ell} + 2^\ell 2N+<md2N++2,且 d ≤ 2 ℓ d \le 2^{\ell} d2
2 N + ℓ / d − 1 ≤ m − 1 ≤ 2 N + ℓ / d 2 N + ℓ − d ≤ m ∗ d − d ≤ 2 N + ℓ 2 N + ℓ ≤ m ∗ d ≤ 2 N + ℓ + d 2 N + ℓ ≤ m ∗ d ≤ 2 N + ℓ + 2 ℓ \begin{aligned} 2^{N+\ell}/d -1 &\le m - 1 \le 2^{N+\ell}/d\\ 2^{N+\ell} -d &\le m*d - d \le 2^{N+\ell}\\ 2^{N+\ell} &\le m*d \le 2^{N+\ell} + d\\ 2^{N+\ell} &\le m*d \le 2^{N+\ell} + 2^{\ell} \end{aligned} 2N+/d12N+d2N+2N+m12N+/dmdd2N+md2N++dmd2N++2
因此满足定理 4.2 的假设。

注意: 从概念上讲, q q q S R L ( n + t 1 , ℓ ) \mathrm{SRL}(n + t_1, \ell) SRL(n+t1,),就像在 (4.5) 中一样。不要这样计算 q q q,因为 n + t 1 n+t_1 n+t1 可能会溢出 N N N 位,且移位计数可能会越界。

改进: 如果 d d d 是常数且为2的幂,则用移位替换除法。

改进: 如果 d d d 是常数且 m = m ′ + 2 N m = m' + 2^N m=m+2N 是偶数,则将 m / 2 ℓ m/2^\ell m/2 约简到最低项。原始乘数约简后在 N N N 位内。在极少数情况下(例如,在 32 位机器上 d = 641 d = 641 d=641,在 64 位机器上 d = 274177 d = 274177 d=274177),最终的移位为零。

改进。 如果 d d d 是常数且为偶数,则对某个 e > 0 e > 0 e>0 重写 ⌊ n d ⌋ = ⌊ ⌊ n / 2 e ⌋ d / 2 e ⌋ \lfloor \frac{n}{d}\rfloor=\lfloor \frac{\lfloor n/2^e\rfloor}{d/2^e}\rfloor dn=d/2en/2e。然后可以使用 S R L \mathrm{SRL} SRL 计算 ⌊ n / 2 e ⌋ \lfloor n/2^e\rfloor n/2e。由于 n / 2 e < 2 N − e n/2^e < 2^{N−e} n/2e<2Ne,乘数所需的精度比之前少。

这些思想体现在图 4.2 中,它生成了 n / d n/d n/d 的代码,其中 n n n 是无符号的, d d d 是常数。
在这里插入图片描述

以下三个示例阐述了图 4.2 中的情况。所有示例都采用无符号 32 位算术。

示例 q = ⌊ n / 10 ⌋ q = \lfloor n/10 \rfloor q=n/10CHOOSE MULTIPLIER 找到 m l o w = ( 2 36 − 6 ) / 10 m_\mathrm{low} = (2^{36} − 6)/10 mlow=(2366)/10 m h i g h = ( 2 36 + 14 ) / 10 m_\mathrm{high} = (2^{36} + 14)/10 mhigh=(236+14)/10。 经过一轮除以2的操作后,它返回 ( m , 3 , 4 ) (m, 3, 4) (m,3,4),其中 m = ( 2 34 + 1 ) / 5 m = (2^{34} + 1)/5 m=(234+1)/5。推荐的代码 q = S R L ( M U L U H ( ( 2 34 + 1 ) / 5 , n ) , 3 ) q = \mathrm{SRL}(\mathrm{MULUH}((2^{34} + 1)/5, n), 3) q=SRL(MULUH((234+1)/5,n),3) 消除了预先的0位移。见表 11.1。
在这里插入图片描述
示例 q = ⌊ n / 7 ⌋ q = \lfloor n/7 \rfloor q=n/7。这里 m = ( 2 35 + 3 ) / 7 > 2 32 m = (2^{35} + 3)/7 > 2^{32} m=(235+3)/7>232。本示例使用图 4.1 中较长的序列。

示例 q = ⌊ n / 14 ⌋ q = \lfloor n/14\rfloor q=n/14CHOOSE MULTIPLIER 首先返回当 d = 7 d = 7 d=7 时相同的乘数。 推荐的代码使用2和7的独立除法:

q = S R L ( M U L U H ( ( 2 34 + 5 ) / 7 , S R L ( n , 1 ) ) , 2 ) . q = \mathrm{SRL}(\mathrm{MULUH}((2^{34} + 5)/7, \mathrm{SRL}(n, 1)), 2). q=SRL(MULUH((234+5)/7,SRL(n,1)),2).

本算法和后续算法共享的程序 CHOOSE MULTIPLIER 如图 6.2 所示。

在这里插入图片描述

因为 N + s h p o s t ≤ ℓ + p r e c N + sh_{post} ≤ \ell + prec N+shpost+prec,所以 N + s h p o s t − p r e c ≤ ℓ N + sh_{post}-prec ≤ \ell N+shpostprec
2 N + s h p o s t ∗ ( 1 + 2 − p r e c ) ≤ 2 N + s h p o s t + 2 ℓ 2^{N +sh_{post}} ∗ (1 + 2^{−prec}) \le 2^{N +sh_{post}} + 2^\ell 2N+shpost(1+2prec)2N+shpost+2
又因为 0 ≤ s h p o s t ≤ ℓ 0 \le sh_{post} ≤ \ell 0shpost,所以
2 N + s h p o s t ∗ ( 1 + 2 − p r e c ) ≤ 2 N + ℓ + 2 ℓ 2^{N +sh_{post}} ∗ (1 + 2^{−prec}) \le 2^{N +\ell} + 2^\ell 2N+shpost(1+2prec)2N++2
不等式(4.3)的上界成立。

因为 2 ℓ − 1 < d 2^{\ell−1} < d 21<d d ≤ 2 p r e c d \le 2^{prec} d2prec, 所以 ℓ − 1 < p r e c \ell-1 < prec 1<prec,所以 2 − p r e c < 2 1 − ℓ 2^{−prec}< 2^{1−\ell} 2prec<21
m < 2 N + s h p o s t ∗ ( 1 + 2 1 − ℓ ) / d m < 2^{N +sh_{post}} ∗ (1 + 2^{1−\ell})/d m<2N+shpost(1+21)/d
因为 2 ℓ − 1 < d ≤ 2 ℓ 2^{\ell−1} < d \le 2^\ell 21<d2 2 1 − ℓ ≤ 1 2^{1−\ell} \le 1 211,所以 1 + 2 1 − ℓ ≤ 2 1 + 2^{1−\ell} \le 2 1+212。可得
2 N + s h p o s t ∗ ( 1 + 2 1 − ℓ ) / d ≤ 2 N + s h p o s t ∗ 2 / d 2^{N +sh_{post}} ∗ (1 + 2^{1−\ell})/d \le 2^{N +sh_{post}} ∗ 2/d 2N+shpost(1+21)/d2N+shpost2/d
又因为 d ≤ 2 ℓ d \le 2^{\ell} d2,所以
2 N + s h p o s t + 1 / d ≤ 2 N + s h p o s t − ℓ + 1 2^{N +sh_{post}+1}/d \le 2^{N +sh_{post}−\ell+1} 2N+shpost+1/d2N+shpost+1
因此, 2 N + s h p o s t ∗ ( 1 + 2 1 − ℓ ) / d ≤ 2 N + s h p o s t − ℓ + 1 2^{N +sh_{post}} ∗ (1 + 2^{1−\ell})/d \le 2^{N +sh_{post}−\ell+1} 2N+shpost(1+21)/d2N+shpost+1

注意:略去5到9节中商向零取整的有符号除法、商向负无穷大取整的有符号除法、udword 除以运行时不变的 uword,以及先验已知余数为零的除法。

10 Implementation in GCC

作者在可自由使用的 GCC 编译器[21]中实现了常数除数的算法,扩展了其与机器和语言无关的内部代码生成。 并且还对一些机器描述符或 md 文件进行了轻微的机器依赖的修改,以获得最优的代码。GCC 支持的所有语言和几乎所有处理器都将受益。 相关更改计划包含在 GCC 2.6中。

为了生成 N 位数除法的代码,CHOOSE MULTIPLIER 函数需要执行 ( 2 N 2N 2N) 位算术运算。这使得该程序比图 6.2中显示的更复杂。

根据操作的位大小选择最佳指令是一个棘手的问题,作者花了相当长的时间:

  • 对于某些架构,选择具有最小可用精度的乘法指令很重要。
  • 在其他架构上,可以通过一系列加法、减法和移位更快地执行乘法。

作者还没有实现任何针对运行时不变除数的算法。只有少数架构(AMD 29050、英特尔 x86、摩托罗拉 68k 和88110,以及在某种程度上的 IBM POWER)具有足够的硬件支持来使这种实现可行,即可以用于整数对数计算的指令,以及 ( 2 N 2N 2N) 位/ N N N 位除法指令。即使有硬件支持,也必须小心,确保转换真正改进了代码;例如,可能需要执行很多次循环才能确保较快的循环体超过循环头中乘数的计算成本。

11 Results

图 11.1 提供了一个编译时间常数除法器的例子,它在所有最新的处理器实现上都获得了显著的加速。该程序将二进制数转换为十进制字符串。它为每个输出数字计算一个商和一个余数。
在这里插入图片描述

表 11.1 展示了为 Alpha、MIPS、POWER 和 SPARC 生成的汇编代码。这里没有显式的除法。尽管最初是单独计算的,但商和余数计算已合并(通过 GCC 的公共子表达式消除过程)。

unsigned int 数据类型在所有四种架构上均为32位,但 Alpha 是一种64位架构。Alpha 的代码比其他的长,因为它使用
4 ∗ [ ( 2 16 + 1 ) ∗ ( 2 8 + 1 ) ∗ ( 4 ∗ [ 4 ∗ ( 4 ∗ x − x ) + x ] − x ) ] + x 4 * [(2^{16} + 1) * (2^8 + 1) * (4 * [4 * (4 * x - x) + x] - x)] + x 4[(216+1)(28+1)(4[4(4xx)+x]x)]+x
( 2 34 + 1 ) / 5 (2^{34} + 1)/5 (234+1)/5 乘以 x x x,而不是更慢的、需要 23 个周期的mulq。这说明这些算法所需的乘法有时可以通过一系列的移位、加法和减法快速计算[5],因为小常数除数的乘数在二进制模式上有规律。

表 11.2 比较了有除法消除算法和没有除法消除算法的基转换例程在一些处理器实现上的时间。转换的数字是一个完整的32位数,足以隐藏测量中的程序调用开销。
在这里插入图片描述

作者还运行了 SPEC’92 的整数基准测试。对于大多数程序来说,改进微不足道;观察到的最佳改进仅为3%左右。一些涉及哈希的基准测试显示出高达约30%的提升。作者预计在一些数论代码上会有显著的提升。

参考资料:

  • Division by Invariant Integers using Multiplication
  • Improved division by invariant integers
  • C++干货系列——从编译期常量谈到constexpr(二)
  • Integer Division by Constants: Optimal Bounds
  • lemire/fast_division
  • Thorius/fast_division
  • Why doesn’t gcc or clang on ARM use “Division by Invariant Integers using Multiplication” trick?
  • Perform integer division using multiplication [duplicate]
  • paddle/phi/kernels/funcs/fast_divmod.h
  • paddle/phi/kernels/primitive/datamover_primitives.h
  • onnxruntime/core/providers/cuda/shared_inc/fast_divmod.h
  • intel/xetla/include/common/utils/fastmath.hpp
  • How to find magic multipliers for divisions by constant on a GPU?
  • [原创]加减乘除反汇编笔记与MagicNumber探究记录
  • Java 源码 - java.lang.Integer
  • 除以二
  • C/C++除数为整数常量(但不是2的幂次)时,优化得div指令都没了是什么原理?
  • 编译技术-除常数优化
  • 即,令,当,这些数学用语在英文论文中如何表示?
  • 英语分数的表达,特别是分母比较大的怎么表达 比如: 2/37 2/115 3/1112
  • What has a better performance: multiplication or division?
  • 4. Instruction tables
  • 『扩展欧几里得算法 Extended Euclid』
  • 擴展歐基里德算法 (Extended Euclidean algorithm)
  • The integer division algorithm of Intel’s x86 processors
  • x86汇编_MUL/IMUL乘法指令_笔记52
  • integer division and modulo
  • Quick ALU Performance multiply/division investigation
  • Most efficient way of dividing by power of two
  • Fast integer division and modulo with a const runtime divisor
  • Floating Point and Integer Arithmetic Benchmark
  • Achieved IOPs
  • Integer division problem
  • 5.4.1. Arithmetic Instructions

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/755937.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php 页面中下载文件|图片

一、需求 页面中点击下载图片 二、实现 protected function pageLoad(){$filePath $_GET[file];$host $_SERVER[HTTP_HOST];$file http://.$host.$filePath;$fileName basename($filePath);$content file_get_contents($file);ob_clean();$suffixArr explode(., $file…

数据库系统概论-练手题集合【期末复习|考研复习】

前言 总结整理不易&#xff0c;希望大家点赞收藏。 给大家整理了一下数据库系统概论中的练手题&#xff0c;以供大家期末复习和考研复习的时候使用。 数据库系统概论系列文章传送门&#xff1a; 第一章 绪论 第二/三章 关系数据库和标准语言SQL 第四/五章 数据库安全性和完整性…

服务器硬件基础知识和云服务器的选购技巧

概述 服务器硬件基础知识涵盖了构成服务器的关键硬件组件和技术&#xff0c;这些组件和技术对于服务器的性能、稳定性和可用性起着至关重要的作用。其中包括中央处理器&#xff08;CPU&#xff09;作为服务器的计算引擎&#xff0c;内存&#xff08;RAM&#xff09;用于数据临…

zookeeper快速入门(合集)

zookeeper作为一个分布式协调框架&#xff0c;它的创建就是为了方便或者简化分布式应用的开发。除了服务注册与发现之外&#xff0c;它还能够提供更多的功能&#xff0c;但是对于入门来说&#xff0c;看这一篇就够了。后续会讲zookeeper的架构设计与原理&#xff0c;比如zookee…

【学习】软件测试中的二八定理是什么?如何提高测试的效率和质量

软件测试领域的二八定理&#xff0c;是指在软件测试过程中&#xff0c;通常只有20%的测试用例能够发现软件中80%的错误。这一现象表明&#xff0c;软件测试的效率和效果并不成正比&#xff0c;测试用例的数量并不等于发现错误的能力。因此&#xff0c;在软件测试过程中&#xf…

<Linux> 生产者消费者模型

目录 前言&#xff1a; 一、什么是生产者消费者模型 &#xff08;一&#xff09;概念 &#xff08;二&#xff09;生产者消费者之间的关系 &#xff08;三&#xff09;生产者消费者模型特点 &#xff08;四&#xff09;生产者消费者模型的优点 二、基于阻塞队列实现生产…

前端标准 JsDoc 代码片段注释 ( 快速生成代码片段网站 )

{ "快速单行注释": {"prefix": "z","body": [" /**"," * $1"," * param { }"," * return { }"," */"],"description": "快速注释" } } 配置之后…

嵌入式科普(12)西门子PROFINET ERTECH 200P-3路演

目录 一、路演观后感/总结 二、分享两个公众号 2.1 HMS工业网络 2.2 Omdia 三、ERTECH 200P-3资料 四、ERTECH 200P-3路演分享 嵌入式科普(12)西门子PROFINET ERTECH 200P-3路演 一、路演观后感/总结 老罗砸西门子冰箱时候的傲慢 -> 路演的谦逊 国外工程师包吃住差旅…

Linux(openEuler)部署SpringBoot前后端分离项目(Nginx负载均衡)

假如数据库在本地&#xff0c;没有放在Linux中 1.先把数据库中root的主机改成% 2.项目中的数据库链接配置换成本机ip 3.打包 4.把打包好的jar包放到Linux中 一般把jar包放到opt下 5.把前端部分拷贝到Linux的nginx中 5.1在package.json中修改build的值为图中这样 5.2同时由于在…

动态规划(算法竞赛、蓝桥杯)--单调队列优化修建草坪

1、B站视频链接&#xff1a;E44 单调队列优化DP 修剪草坪_哔哩哔哩_bilibili #include <bits/stdc.h> using namespace std; typedef long long LL; const int N1e510; int n,k,q[N]; LL w[N],f[N],sum;int main(){cin>>n>>k; k; //for(int i1;i<n;i){ci…

Vue多文件学习项目综合案例——小兔鲜,黑马vue教程

文章目录 一、项目截图二、主要知识点三、Main.js四、App.vue五、componentsXtxBanner.vueXtxFooter.vueXtxHeaderNav.vueXtxHotBrand.vueXtxNewGoods.vueXtxShortCut.vueXtxTopic.vue 六、stylesbase.csscommon.css 一、项目截图 二、主要知识点 把静态页面拆分成一个个vue组…

数据库简介与MySQL编译安装

1数据库基础 什么是数据库 数据库&#xff08;Database&#xff09;是一个有组织的数据存储系统&#xff0c;用于有效地存储、检索、管理和维护数据。数据库系统允许用户以结构化的方式存储和操作大量数据&#xff0c;并提供了一种可靠的方法来管理和维护这些数据&#xff0c…

数据库的基本概念与安装MySQL

一、数据库的基本概念 1、什么是数据&#xff1f; 描述事物的符合记录包括数字、文字、图形、图像、声音、档案记录等以“记录”形式按统一的格式进行存储 2、什么是表&#xff1f; 将不同的记录组织在一起用来存储具体数据 3、什么是数据库 表的集合&#xff0c;是存储数…

2023年中国电商市场研究报告

研究范畴界定为中国国内2C电商市场 ⚠️ 关键点&#xff1a; 流量红利减少&#xff0c;电商市场进入存量增量 竞争的发展阶段&#xff1b;新兴电商平台不断挑战现有头部电商平台行业地位&#xff1b;消费者更加趋于理性&#xff0c;更加关注低价和服务&#xff1b;市场趋势&…

嵌入式和 Java选哪个?

今日话题&#xff0c;嵌入式和 Java 走哪个?对于嵌入式领域有浓厚兴趣的人&#xff0c;并不会比Java行业薪资低&#xff0c;处于上中游水平。特别是从2020年开始&#xff0c;嵌入式领域受益于芯片产业的兴起&#xff0c;表现出了强劲的增长势头。薪资水平受多方面因素影响。嵌…

AndroidLinux GPIO控制方法

目录 1 GPIO整体架构 2 user space 层 gpio使用方法 2.1 sysfs控制方法 2.1.1 kernel版本区别 2.1.2 /sys/class/gpio 2.1.3 /sys/bug/gpio/devices 2.2 chardev控制方法 2.2.1 chardev 示例代码 2.2.2 示例代码主要步骤描述 2.2.3 include/linux/gpio.h 全部代码 2.3…

mmz批量多页抓取数据-AES.CBC算法-爬虫

目标&#xff1a;mmz多页下载 方法&#xff1a;加一个for循环实现多页的下载 问题&#xff1a;浏览器传输服务器时对页码参数做了加密处理 解决方法&#xff1a; 1、判断加密算法模式&#xff08;mmz是AES-CBC算法&#xff09; 2、找到加密的key和iv 代码&#xff1a; i…

数据可信流通,从运维信任到技术信任

信任 共同观点&#xff1a; 信任是涉及交易或交换关系的基础 身份可确认利益可依赖能力有预期行为有后果 数据流通中的不可信风险 内循环&#xff1a;数据持有方在自己的运维安全域内对自己的额数据使用和安全拥有全责外循环&#xff1a;数据要素在离开持有方安全域后&#…

使用 git 先提交后拉取的时候远程分支不允许问题

问题场景 修改本地代码使用 git 先提交后拉取的时候远程分支不允许的问题 修改本地代码时&#xff0c;远程分支存在其他新提交先执行了 git commit -m xxx update然后再执行 git pull 拉取远程分支代码&#xff0c;出现如下提示 hint: You have divergent branches and need…

基于python 变配电室运行状态评估与预警系统flask-django-nodejs-php

变配电室电气设备运行状态和环境信息缺乏必要的监测评估预警手段&#xff0c;如有一日遭遇突发情况&#xff0c;将危及电气设备安全稳定运行,易造成设备损坏和电力供应中断[2]。 目前&#xff0c;我国变配电室常采用无人管理的室内站设计方案&#xff0c;长期以来变配电室运维工…