Evi*_*ach 5 c string performance
这个简单的解决方案迅速涌入我的脑海.
#include <ctype.h>
int digit_exists_in
(
const char *s
)
{
while (*s)
{
if (isdigit(*s))
{
return 1;
}
else
{
s++;
}
}
return 0;
}
int main(void)
{
int foundDigit = digit_exists_in("abcdefg9ijklmn");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
还有什么其他技术可以提高速度?
被搜索的实际字符串是可变长度,字符本身是ASCII,而不是完整的字符集.字符串是NUL终止的.
Nic*_*oic 18
顺便说一句,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;
}
Run Code Online (Sandbox Code Playgroud)
在他们自己的游戏中击败标准库非常困难......(通常的警告适用 - YMMV)
$ 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
Run Code Online (Sandbox Code Playgroud)
更新:为了好玩,我添加了一个基于Mike Dunlavey答案的位图查找版本:
char bitmap[256] = {
/* 0x00 */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
};
int test_bitmap(char *s) {
while (!bitmap[*(unsigned char *)s]) s++;
return (*s);
}
Run Code Online (Sandbox Code Playgroud)
其中略胜一筹(〜.170s)但仍无法触及strcspn!
小智 12
我将首先使用适当的库函数strcspn,假设库已经被极端偏见优化:
#include <string.h>
#include <stdio.h>
int digit_exists_in(const char *s)
{
return s[strcspn(s, "0123456789")] != '\0';
}
int main(void)
{
printf("%d\n", digit_exists_in("foobar"));
printf("%d\n", digit_exists_in("foobar1"));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果库尚未充分优化,那么将优化放入库中是个好主意,这样每个人都可以从中受益.(你有来源,对吧?)
Chr*_*ith 10
没有更快的算法,但您可以查看每个指令的完整寄存器的字节值或使用SIMD操作来加快速度.如果某个范围内有任何数字,或者如果SIMD操作在足够大的矢量上足够快,您可以使用掩码和零测试来查看它是否可行,您可以迭代测试特定数值的测试.字节向量比做字符比较快.
所以,例如,你可以这样做:
byte buffer[8] = { 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 };
uint64 *mask = (uint64 *) buffer; //this is just for clarity
if (*((uint64 *) s) & *mask) == 0)
//You now don't need to do the < '0' test for the next 8 bytes in s
Run Code Online (Sandbox Code Playgroud)
一些优化器可能足够智能,只需从上面的代码示例中为您完成此操作.
你最好比较一个TON字节来考虑这个级别的优化.