如何使用位运算来代替模和除法运算

How to use bit operations to replace modulu and division operators?

本文关键字:运算 除法 何使用      更新时间:2023-10-16

我有这行代码:

base_num = (arr[j]/base)%256;

这一行在循环中运行,操作"/"answers"%"需要大量的资源和时间来执行。我想更改这一行并应用位操作,以最大限度地提高程序性能。我该怎么做?

谢谢。

如果基数是2的n次方,则可以用向右移位n来代替除以。然后,由于取整数的模256相当于取其最后8位,因此可以将其与0xFF进行"与"运算。或者,如果用256*基数进行"与"运算,然后将n右移,则可以反转运算。

base_num = arr[j] >> n;
base_num &= 0xFF;

当然,任何一个半吊子的编译器都应该能够为您做到这一点。

-O1或更高版本添加到编译器选项中,编译器将为您执行此操作。

在gcc中,-O1打开-ftree-slsr,根据文档,CCD_3是

对树执行直线强度降低。这可以识别涉及乘法的相关表达式,并在可能的情况下用成本较低的计算来替换它们。

这将替换模,如果它是常数,则替换基数。然而,如果您知道基数将是某个非恒定的二次方,那么您可以重构周围的代码,以获得该数字的log2和减去1的>>

您也可以将base_num声明为8位整数:

#include <stdint.h>
uint8_t base_num;
uint16_t crap;
crap = 0xFF00;
base_num = crap;

如果您的编译器是标准的complement,它将把byte(0xFF00)(0x00)的值放入base_num中。

我还没有遇到一个编译器用纯C(既不是C++也不是C#)进行饱和运算,但如果它这样做了,它会把大于0xFFsat_byte(0xFF00)的值放进base_num

请记住,在这种情况下,编译器会警告您精度的损失。在这种情况下,编译器可能会出错(Visual Studio在Treat Warnings as Errors打开时会出错)。如果发生这种情况,你可以做:

base_num = (uint8_t)crap;

但这似乎是你试图避免的。

你试图做的似乎是删除模运算符,因为这需要除法,而除法是最昂贵的基本算术运算。我通常不会认为这是一个瓶颈,因为任何"智能"编译器(即使在调试模式下)都会将其"优化"为:

base_num = crap & 0xFF;

在一个受支持的平台上(我听说过的每一个主流处理器——x86、AMD64、ARM、MIPS),应该是任何一个。如果听到一个处理器没有基本的AND和OR运算指令,我会目瞪口呆。