我正在研究编程问题的更快的I / O方法,
我发现了这种使用getchar_unlocked()
的方法(虽然有风险但仍然存在)。
我环顾四周但却无法获得扫描整数值的方式
或换句话说,4行是什么意思以及它们如何在scanint()
函数中起作用
定义如下
#include<iostream>
#include<cstdio>
#define gc getchar_unlocked
void scanint(int &x)
{
register int c = gc();
x = 0;
for(;(c<48 || c>57);c = gc());
for(;c>47 && c<58;c = gc())
{x = (x<<1) + (x<<3) + c - 48;}
}
int main()
{
int n,k;
scanint(n);
scanint(k);
int cnt=0;
while(n--)
{
int num;
scanint(num);
if(num%k==0)cnt++;
}
printf("%d",cnt);
return 0;
}
答案 0 :(得分:4)
代码具有字符'0'
和'9'
的硬编码ASCII值,因此它会跳过不在该范围内的任何内容(第四个感兴趣的四行中的循环)你)。
然后,当它看到'0'
- '9'
范围内的字符时,它会将其运行总数乘以10(将其向左移动一次使其加倍,然后将其添加到自身左移三次,其中就像乘以8)并添加当前的char - '0'
的代码。
答案 1 :(得分:1)
该行
for(;(c<48 || c>57);c = gc());
读取不在'0'
到'9'
之间的字符。
该行
for(;c>47 && c<58;c = gc())
逐个读取'0'
到'9'
之间的字符。
该行
{x = (x<<1) + (x<<3) + c - 48;}
简单等同于
x = 10 * x + c - 48;
此功能的简化版本可以改写为:
#define gc getchar_unlocked
int read_int()
{
char c = gc();
while(c<'0' || c>'9')
c = gc();
int ret = 0;
while(c>='0' && c<='9')
{
ret = 10 * ret + c - 48;
c = gc();
}
return ret;
}
答案 2 :(得分:1)
'0'
的ASCII值为48,每个后续数字再增加一个。即'1'
- &gt; 49,'2'
- &gt; 50 ......依此类推。
这样做的一个副作用是,如果你取一个字符数字,意思是'0'
和'9'
之间的某个字符,并从中减去'0'
的ASCII值,那么你得到了该数字的整数值。
因此,在x = (x<<1) + (x<<3) + c - 48;
行中,c-48
部分正在将数字字符(ASCII编码字符)转换为引用该字符的0-9之间的数字。
(x<<1)+(x<<3)
与x * 10
相同,(有关详细信息,请结帐http://en.wikipedia.org/wiki/Multiplication_algorithm#Shift_and_add和How can I multiply and divide using only bit shifting and adding? )实际上这部分代码不必要地进行模糊处理。编译器可以通过多种不同的方式优化乘法,使其尽可能快,因此我们不需要手动实现位移。尽管如此,这也是一个有趣的大学级难题。
for(;(c<48 || c>57);c = gc());
此循环将忽略所有字符,直到收到一个属于'0'
到'9'
范围的字符。因此,如果用户通过键入空格或任何其他字符开始,则只会忽略它。
当代码命中for(;c>47 && c<58;c = gc()) {x = (x<<1) + (x<<3) + c - 48;}
行时,变量c
已初始化为用户键入的第一个数字。此循环使初始化为空,因此控制流将直接进入循环并在键入每个字符时开始计算数字。
只要用户输入数字,循环就会继续,只要用户输入数字以外的内容,循环就会终止,最终确定数字。
在用户继续输入数字之前,行x = (x<<1) + (x<<3) + c - 48;
将一遍又一遍地执行,每次c
都是刚输入的字符。 x
将自己乘以10
并添加新数字。
让我们说用户输入2014.这里有c
和x
中的值如何进展。
c = '2' #ASCII value 50
x = 2
c = '0' #ASCII value 48
x = 20
c = '1' #ASCII value 49
x = 201
c = '4' #ASCII value 52
x = 2014
HTH。