c++中使用% operator和/ operator的替代方法
Alternative to using % operator and / Operator in C++
在嵌入式c++中,模运算符"%"和除法运算符"/"是非常低效的。
如何实现以下表达式:
a = b % c;
我理解这可以使用以下逻辑来实现:
a = b - c;
while (a >= c) {
a = a - c;
}
但是我的问题是,与%操作符相比,这段涉及while循环的代码是否足够有效?
谢谢,医生说
除法和取模确实是代价高昂的硬件操作,无论你做什么(这更多地与硬件架构有关,而不是语言或编译器),可能比加法慢十倍。
然而,在当前的笔记本电脑或服务器上,以及在高端微控制器上,缓存丢失通常比除法慢得多!
当除数为常量时,GCC编译器通常能够优化它们。
初始循环通常比使用硬件除法指令(或库例程,如果不是硬件提供的话)要慢得多。我认为你回避分裂是错误的。用你的循环替换它
你可能会调整你的算法-例如,通过2的幂-但我不建议使用你的代码。请记住,过早的优化是邪恶的,所以首先尝试使您的程序正确,然后分析它以找到问题点。
没有比%
运算符更有效的了。如果有更好的方法,那么任何合理的编译器都会自动转换它。当你被告知%
和/
是低效的,那只是因为它们是困难的操作-如果你需要执行模,那么就这样做。
在特殊情况下可能有更好的方法-例如,mod 2的幂可以写成二进制或-但这些可能是由编译器优化的。
该代码几乎肯定会比处理器/编译器决定执行除法/mod的代码慢。一般来说,对于基本的算术运算符来说,快捷方式是很难找到的,因为mcu/cpu设计人员和编译器程序员非常擅长为几乎所有的应用程序优化快捷方式。
在嵌入式设备(其中每个周期/字节都可以产生差异)中,一个常见的快捷方式是将所有内容保持为基数2,使用位移位运算符执行乘法和除法,使用位和(&)执行模。
例子:
unsigned int x = 100;
unsigned int y1 = x << 4; // same as x * 2^4 = x*16
unsigned int y2 = x >> 6; // same as x / 2^6 = x/64
unsigned int y3 = x & 0x07; // same as x % 8
如果除数在编译时已知,则可以将该操作转换为与倒数相乘,并进行一些移位、加法和其他快速操作。这将在任何现代处理器上更快,即使它在硬件上实现除法。嵌入式目标通常具有高度优化的除/模例程,因为这些操作是标准所要求的。
如果您仔细分析了代码并发现模运算符是内部循环中的主要成本,那么有一个优化可能会有所帮助。您可能已经熟悉了使用算术左移(对于32位值)确定整数符号的技巧:
sign = ( x >> 31 ) | 1;
这将符号位扩展到整个单词,因此负值产生-1,正值产生0。然后设置位0,使正值为1。
如果我们只增加一个小于模数的量,那么同样的技巧可以用来包装结果:
val += inc;
val -= modulo & ( static_cast< int32_t >( ( ( modulo - 1 ) - val ) ) >> 31 );
或者,如果递减的值小于模数,则相关代码为:
int32_t signedVal = static_cast< int32_t >( val - dec );
val = signedVal + ( modulo & ( signedVal >> 31 ) );
我添加了static_cast操作符,因为我在传递uint32_t,但你可能不觉得它们是必要的。
与简单的%操作符相比,这是否更有帮助?这取决于你的编译器和CPU架构。我发现在VS2012下编译时,一个简单的循环在我的i3处理器上运行速度快了60%,但是在树莓派的ARM11芯片上使用GCC编译时,我只得到了20%的改进。
除常数可以通过移位实现,如果是2的幂,或者对于其他的是多加移位组合。
http://masm32.com/board/index.php?topic=9937.0有x86汇编版本以及C源代码从第一篇文章下载。它为您生成了这段代码。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 如何编写 operator= 用于使用虚拟方法与非平凡成员的匿名联合
- "operator()"在重载运算符方法中是什么意思,在priority_queue(STL)中用作C++中的比较器?
- 调用模板方法会导致'operator<'不匹配
- 为什么 std::binary_function<...> 没有 operator() 方法?
- 如果 std::basic_string::operator[] 也是非 const 方法,为什么它是 const 方法?
- c++中使用% operator和/ operator的替代方法
- 是否有一种方法可以重载operator=来为右边的函数提供特定的行为?
- 是否有一种方法可以将可变参数包中的所有类指定为模板的友类,以便使用operator=
- 如何使用 'llvm::ilist_iterator<NodeTy>::operator pointer() const' 方法?