liw.fi是对的,顺便说一句。我有点惊讶,因为strcspn要解决比isdigit()更一般的问题,但似乎是这样的:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#define NTESTS 10000
#define TESTSIZE 10000
char stest1[TESTSIZE];
char stest2[TESTSIZE];
int test_isdigit(char *s) {
while (*s) {
if (isdigit(*s)) return 1;
s++;
}
return 0;
}
int test_range(char *s) {
while (*s) {
if ((*s >= '0') && (*s <= '9')) return 1;
s++;
}
return 0;
}
int test_strcspn(char *s) {
return s[strcspn(s, "0123456789")] != '\0';
}
int main(int argc, char **argv) {
long int i;
for (i=0; i<TESTSIZE; i++) {
stest1[i] = stest2[i] = 'A' + i % 26;
}
stest2[TESTSIZE-1] = '5';
int alg = atoi(argv[1]);
switch (alg) {
case 0:
printf("Testing strcspn\n");
for (i=0; i<NTESTS; i++) {
assert(test_strcspn(stest1) == 0);
assert(test_strcspn(stest2) != 0);
}
break;
case 1:
printf("Testing isdigit() loop\n");
for (i=0; i<NTESTS; i++) {
assert(test_isdigit(stest1) == 0);
assert(test_isdigit(stest2) != 0);
}
break;
case 2:
printf("Testing <= => loop\n");
for (i=0; i<NTESTS; i++) {
assert(test_range(stest1) == 0);
assert(test_range(stest2) != 0);
}
break;
default:
printf("eh?\n");
exit(1);
}
return 0;
}
想要在标准库所擅长的领域中超越它们实在是非常困难...(通常的附带条件适用——个人体验可能有所不同)
$ gcc -O6 -Wall -o strcspn strcspn.c
$ time ./strcspn 0
Testing strcspn
real 0m0.085s
user 0m0.090s
sys 0m0.000s
$ time ./strcspn 1
Testing isdigit() loop
real 0m0.753s
user 0m0.750s
sys 0m0.000s
$ time ./strcspn 2
Testing <= => loop
real 0m0.247s
user 0m0.250s
sys 0m0.000s
更新:只是为了好玩,我根据Mike Dunlavey的答案添加了一个基于位图查找的版本:
char bitmap[256] = {
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
};
int test_bitmap(char *s) {
while (!bitmap[*(unsigned char *)s]) s++;
return (*s);
}
这个方法略微优于其它方法(大约0.170秒),但仍然无法与strcspn相比。
strcspn
函数只是使用相同的查找表,循环展开4次。(并且负载之间存在虚假依赖,导致额外的ALU uops...) https://code.woboq.org/userspace/glibc/sysdeps/x86_64/strcspn.S.html。显然,POWER8具有SIMD指令,可以有效地使用256位位图进行操作,即使对于`strcspn`的一般情况,构建后扫描速度更快。 - Peter Cordesc > ('0'-1)
和非(c > '9')
,或者可能是c - '0' <= (unsigned)'9'
范围检查:将C++中的字符串转换为大写展示了如何通过范围移位无符号->有符号以及减法高效地完成。 (用于c-'a' <= (unsigned)25
ascii_islower检查的SIMD是具有不同常量的相同问题:_mm_sub_epi8
和_mm_cmpgt_epi8
->_mm_movemask_epi8(v)!= 0
) - Peter Cordes