在用于竞争性编程的DMOJ在线判断器上,如果问题仅要求读取未签名的整数数据类型,则在执行时间(C ++)上更快的提示之一是在顶部添加此宏。
这是如何工作的,使用它的优缺点是什么?
#define scan(x) do{while((x=getchar())<'0'); for(x-='0'; '0'<=(_=getchar()); x= (x<<3)+(x<<1)+_-'0');}while(0)
char _;
答案 0 :(得分:5)
首先让我们重新格式化一下:
#define scan(dest) \
do { \
while((dest = getchar()) < '0'); \
for(dest -= '0'; '0' <= (temp = getchar()); dest = (dest<<3) + (dest<<1) + temp - '0');
} while(0)
char temp;
首先,外部do{...}while(0)
只是为了确保正确解析宏。有关更多信息,请参见here。
接下来,while((dest = getchar()) < '0');
-可能只是dest = getchar()
,但是它通过丢弃'0'
字符以下(但不是上方)的任何字符来做一些额外的工作。这很有用,因为空格字符都“小于” ascii中的0字符。
宏的实质是for
循环。首先,初始化表达式dest -= '0'
通过利用ascii编码中的0-9字符是相邻且顺序的事实,将dest设置为该字符表示的实际整数值。因此,如果第一个字符为'5'
(值53),则减去'0'
(值48)将得到整数值5
。
条件语句'0' <= (temp = getchar())
做几件事-首先,它获取下一个字符并将其分配给temp
,然后检查其是否大于或等于{{1 }}字符(因此在空白处将失败)。
只要字符是数字(或至少等于'0'
),就对增量表达式进行求值。 '0'
-dest = (dest<<3) + (dest<<1) + temp - '0'
表达式从ascii到数值进行与以前相同的调整,并且移位和加法只是乘以10的一种晦涩的方式。换句话说,它等效于{{ 1}}。乘以10并加上下一位数字的值就是最终值。
最后,temp - '0'
声明临时字符存储,以供程序中的后续宏调用使用。
至于为什么要使用它,我怀疑与temp -= '0'; dest = dest * 10 + temp;
或char temp;
之类的东西相比,它会提供任何可衡量的收益。
答案 1 :(得分:1)
它的作用是通过一系列过早的优化逐个字符地读取数字。有关更多详细信息,请参见@MooseBoys的答案。
关于它的优缺点,我完全看不到使用它的任何好处。像(x<<3)+(x<<1)
这样等于x * 10
的东西是应该由编译器而不是您自己完成的优化。
据我所知,cin
和cout
足够快用于所有竞争性编程目的,尤其是在禁用与stdio同步的情况下。自从开始竞争性编程以来,我一直在使用它,从来没有任何问题。
此外,尽管人们普遍认为,我自己的测试表明cin
和cout
的运行速度并不比C I / O慢。您可以尝试自己测试其性能。确保已启用优化。
显然,当他们的算法最重要时,一些有竞争力的程序员会将过多的精力放在快速I / O之类的东西上。