在 C++ 中,将正数转换为 1 和将负数转换为 0 的最快方法
in c++, the fastest way to convert a positive number to 1 and negative to 0
我正在编写此代码来制作烛台图,如果当天的开盘价大于收盘价,我想要一个红色框。我还希望如果收盘价高于开盘价,则框为绿色。
if(open > close) {
boxColor = red;
} else {
boxColor = green;
}
为此,伪代码比英语句子更容易。
所以我先写了这段代码,然后尝试对其进行基准测试,但我不知道如何获得有意义的结果。
for(int i = 0; i < history.get().close.size(); i++) {
auto open = history->open[i];
auto close = history->close[i];
int red = ((int)close - (int)open) >> ((int)sizeof(close) * 8);
int green = ((int)open - (int)close) >> ((int)sizeof(close) * 8);
gl::color(red,green,0);
gl::drawSolidRect( Rectf(vec2(i - 1, open), vec2(i + 1, close)) );
}
这就是我试图对它进行基准测试的方式。每次运行仅显示 2ns。我对社区的主要问题是:
我实际上可以通过使用右移位并避免条件分支来使其更快吗?
#include <benchmark/reporter.h>
static void BM_red_noWork(benchmark::State& state) {
double open = (double)rand() / RAND_MAX;
double close = (double)rand() / RAND_MAX;
while (state.KeepRunning()) {
}
}
BENCHMARK(BM_red_noWork);
static void BM_red_fast_work(benchmark::State& state) {
double open = (double)rand() / RAND_MAX;
double close = (double)rand() / RAND_MAX;
while (state.KeepRunning()) {
int red = ((int)open - (int)close) >> sizeof(int) - 1;
}
}
BENCHMARK(BM_red_fast_work);
static void BM_red_slow_work(benchmark::State& state) {
double open = (double)rand() / RAND_MAX;
double close = (double)rand() / RAND_MAX;
while (state.KeepRunning()) {
int red = open > close ? 0 : 1;
}
}
BENCHMARK(BM_red_slow_work);
谢谢!
正如我在评论中所说,编译器将为您进行这些优化。 下面是一个最小的可编译示例:
int main() {
volatile int a = 42;
if (a <= 0) {
return 0;
} else {
return 1;
}
}
volatile
只是为了防止优化"知道"a
的值,而是强制读取它。
这是使用命令g++ -O3 -S test.cpp
编译的,它生成一个名为test.s的文件
Inside test.s 是由编译器生成的程序集(请原谅 AT&T 语法(:
movl $42, -4(%rsp)
movl -4(%rsp), %eax
testl %eax, %eax
setg %al
movzbl %al, %eax
ret
如您所见,它是无分支的。 如果数字<= 0
,它使用testl
设置一个标志,然后使用setg
读取该值,将其移回正确的寄存器,最后返回。
应该注意的是,这是从您的代码改编而来的。 一个更好的写法很简单:
int main() {
volatile int a = 42;
return a > 0;
}
它还生成相同的程序集。
这可能比你直接用C++写的任何可读内容都要好。 例如,您的代码(希望针对位算术错误进行更正(:
int main() {
volatile int a = 42;
return ~(a >> (sizeof(int) * CHAR_BIT - 1)) & 1;
}
编译为:
movl $42, -4(%rsp)
movl -4(%rsp), %eax
notl %eax
shrl $31, %eax
ret
这确实很小。 但它并没有明显快得多。 尤其是当您旁边有一个 GL 呼叫时。 我宁愿花 1-3 个额外的周期来获得可读的代码,而不必挠头想知道我的同事(或 6 个月前的我,本质上是同一件事(做了什么。
编辑:应该指出的是,编译器还优化了我编写的位算术,因为我写得不如我能写的那么好。 程序集实际上是:(~a) >> 31
,它等同于我编写的~(a >> 31) & 1
(至少在大多数带有无符号整数的实现中,有关详细信息,请参阅注释(。
- 有没有一种方法可以通过"typedef"为重新定义的基本类型定义特征和强制转换运算符
- 将方法转换为调用该方法的成员函子对象会导致崩溃
- 是否有内置方法可以强制转换为不同的基础类型,但保留常量限定符?
- 将复杂的非基元C++数据类型转换为 Erlang/Elixir 格式,以使用 NIF 导出方法
- 从长整整转换为uint64_t的推荐方法是什么?
- 将传入的网络"char*"数据转换为"uint8_t"并返回的安全方法是什么?
- 有没有将变量名称转换为双指针的简短方法?
- 在 C++ 中将整数数组转换为位集表示形式的最佳方法?
- 从基类实例调用派生类方法而不进行强制转换
- C++ 将静态方法转换为简单方法
- 将 malloc 转换为新的正确方法
- C++方法转换为 C#
- C ++基础私有方法在将自身转换为派生类后可以访问吗?
- 通过构造函数方法输出的类到类类型转换是 5500 为什么不是 5555
- 为什么这种转换方法不编译?
- 两个具有转换方法的类
- 传递和强制转换方法指针
- CRTP 向下转换方法调用
- Qt4:QGraphicsScene/View和自定义转换方法
- c++中这两种类型转换方法的区别是什么?