C++ 检查 char 是元音还是辅音的最快方法
c++ fastest way to check if char is vowel or consonant
我有一个问题,涉及使用回溯来查找具有各种规则的许多"单词"(它们不一定是真实的)。一些规则涉及我可以彼此之后的元音数量。
我知道我可以使用一个开关,或者一个带有元音数组的 for 循环,然后说所有不是元音的字母字符都是辅音,但由于这个函数可能会被调用几千次,我希望它尽可能快。
检查字符是元音还是辅音的最快方法是什么?
如果您有 ASCII 字符,并且您知道该字符是一个字母(其 ASCII 代码大于或等于 64),那么您可以这样做:
// pre-condition: v is alphabetic ASCII, upper or lower case
bool isvowel(char v) {
return (0x208222>>(v&0x1f))&1;
}
如果你在x86上,那么你甚至可以删除&0x1f
部分(注意:根据标准,这是未定义的行为,但>>
编译为SHR/SAR
,为此v
将被屏蔽以自动0x1f):
bool isvowel_UB_for_dumb_compilers(char v) {
return (0x208222>>v)&1;
}
注意:这是一个"脏"的解决方案,但如果真的需要速度,有时脏的解决方案是最快的(基本上这个解决方案在魔术常数中存储了一个 32 元素表0x208222:位是为 wovels 设置的。此外,利用小写和大写字符具有相同的 5 个最低位)。
如果你的编译器足够新,它知道sar
是如何工作的,并将优化&0x1f
。 例如,gcc8 和更新版本省略了任何and edi,31
指令。 (Godbolt编译器资源管理器,包括一个天真的if(v == 'a' || v == 'e' ...)
GCC编译成一些分支,但也有一个位图检查。
注意2:仅当表指针不在时,此版本才比表版本快。如果执行大量检查,并且表指针已在寄存器中,并且表在缓存中,则表版本会更快。
(编者注:在解压缩为 32 位 SIMD 元素后,位图可以自动矢量化以一次检查多个字符。 表查找不能。
我没有其他想法。
这个答案只是为了提供其他人的一些基准。
bool undef_sarx_and(char v) {
return (0x208222>>v) // sarx %edi, %eax, %eax
&1; // andl $1, %eax
}
bool unsafe_one_load(char in) {
return bool_table[in]; // movsbq %dil, %rdi
} // movb table(%rdi), %al
bool safe_one_load(char in) {
auto index = static_cast<unsigned char>(in); // movzbl %dil, %edi
return bool_table[index]; // movb table(%rdi), %al
}
(iterate on data 1 MB for 800 times)
undef_sarx_and 209976800 2.71313 sec 309.185 MB/s
unsafe_one_load 209976800 2.4514 sec 342.197 MB/s
safe_one_load 209976800 2.18231 sec 384.391 MB/s
(iterate on data 100 MB for 8 times)
undef_sarx_and 209704768 3.76998 sec 222.511 MB/s
unsafe_one_load 209704768 3.72898 sec 224.957 MB/s
safe_one_load 209704768 3.72719 sec 225.065 MB/s
all with vectorization disabled (-fno-tree-vectorize)
我想没有什么能比得上@pete-贝克尔的表格查找 但是@geza的黑客非常引人注目,因为表查找分配了 256 个字节,而内联函数都是免费的!
godbolt.org/g/FajFXb
wandbox.org/permlink/Lf1mioQG8yanZtZn
最快的方法是创建一个bool
数组并使用字符值作为索引:
bool is_vowel[CHAR_MAX] = { false }; // initializes all values to false
void init() {
is_vowel['A'] = true;
is_vowel['a'] = true;
// etc.
}
现在,对于任何非负char
值ch
,如果是元音,则is_vowel[ch]
为真,否则为假。
- C++:正在检查LinkedList中的回文-递归方法-错误
- 检查哪个对象调用了另一个对象的对象方法
- 检查两个节点在子节点上是否具有相同状态的更优雅的方法
- 检查类是否在方法中实例化
- 检查类方法中是否(此 == nullptr)
- 检查子类型时的专用方法模板
- 检查两个向量是否并行的最有效方法
- 如何检查在编译时是否调用了模板化方法?
- 尝试编译SFINAE检查中使用的方法体时发生编译错误
- 有没有一种简单的方法来检查C++中的不安全表达式
- 是否有更有效的方法来检查元素是否在给定的区间内
- 检查特定目录中是否存在与文件匹配的 abc* 的最佳方法
- 检查数组是否等于的最快方法?
- 替换枚举以最大化编译时间检查的最佳方法
- 双重检查创建单例问题的方法
- 如果方法不进行类型检查,为什么C++模板匹配?
- C++:检查向量中的元素是否大于另一个具有相同索引的元素的有效方法?
- 检查子类是否执行了方法重写
- 最快/最小方法检查字符串是否包含多个单词
- SFINAE c++方法检查