- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一些执行位操作的性能密集型代码。它可以简化为以下明确定义的问题:
给定一个 13 位位图,构造一个 26 位位图,其中包含在偶数位置间隔的原始位。
举例说明:
0000000000000000000abcdefghijklm (input, 32 bits)
0000000a0b0c0d0e0f0g0h0i0j0k0l0m (output, 32 bits)
我目前在 C 中以下列方式实现它:
if (input & (1 << 12))
output |= 1 << 24;
if (input & (1 << 11))
output |= 1 << 22;
if (input & (1 << 10))
output |= 1 << 20;
...
我的编译器 (MS Visual Studio) 将其转换为以下内容:
test eax,1000h
jne 0064F5EC
or edx,1000000h
... (repeated 13 times with minor differences in constants)
我想知道我是否可以让它更快。我想用 C 语言编写代码,但可以切换到汇编语言。
最佳答案
有一个聪明的方法可以做到这一点,在这里可能会有帮助。它实际上解决了一个稍微更一般的位改组问题。你的问题有一个输入:
+---------------+---------------+---------------+---------------+
|0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 0|0 0 0 a b c d e|f g h i j k l m|
+---------------+---------------+---------------+---------------+
....但是让我们考虑所有的位:
+---------------+---------------+---------------+---------------+
|A B C D E F G H|I J K L M N O P|Q R S a b c d e|f g h i j k l m|
+---------------+---------------+---------------+---------------+
并尝试像这样交错它们:
+---------------+---------------+---------------+---------------+
|A Q B R C S D a|E b F c G d H e|I f J g K h L i|M j N k O l P m|
+---------------+---------------+---------------+---------------+
第一步,考虑输入的中间一半:
bit 31 24 16 8 0
v v v v v
+---------------+---------------+---------------+---------------+
| |I J K L M N O P|Q R S a b c d e| |
+---------------+---------------+---------------+---------------+
构造8位值:{ I^Q
, J^R
, K^S
, L^a
, M^b
, N^c
, O^d
, P^e
}。
如果我们将这个 8 位值与 [15:8] 位进行异或,并且还进行异或与位 [23:16] 相同的 8 位值,我们将交换中间的两个字节:对于例如,第 23 位(最初是 I
)将变为 I ^ (I^Q) = Q
和第 15 位(原本 Q
) 会变成 Q ^ (I^Q) = I
。
为此:tmp = (input ^ (input >> 8)) & 0x0000ff00;
:
+---------------+---------------+---------------+---------------+
|A B C D E F G H|I J K L M N O P|Q R S a b c d e|f g h i j k l m| input
+---------------+---------------+---------------+---------------+
exclusive-OR with:
+---------------+---------------+---------------+---------------+
|0 0 0 0 0 0 0 0|A B C D E F G H|I J K L M N O P|Q R S a b c d e| input >> 8
+---------------+---------------+---------------+---------------+
-->|want these bits|<--
mask (bitwise AND) with 0x0000ff00:
+---------------+---------------+---------------+---------------+
|0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 0|1 1 1 1 1 1 1 1|0 0 0 0 0 0 0 0| 0x0000ff00
+---------------+---------------+---------------+---------------+
现在我们需要的 8 位值在位 [15:8] 中,所有其他位都为 0。现在我们可以用
input ^= (tmp ^ (tmp << 8));
导致:
+---------------+---------------+---------------+---------------+
|A B C D E F G H|Q R S a b c d e|I J K L M N O P|f g h i j k l m| input
+---------------+---------------+---------------+---------------+
下一步,分而治之...进行类似的中间交换左手一半的位:
+---------------+---------------+---------------+---------------+
|A B C D E F G H|Q R S a b c d e| | |
+---------------+---------------+---------------+---------------+
becomes
+---------------+---------------+---------------+---------------+
|A B C D Q R S a|E F G H b c d e| | |
+---------------+---------------+---------------+---------------+
...和右半边:
+---------------+---------------+---------------+---------------+
| | |I J K L M N O P|f g h i j k l m|
+---------------+---------------+---------------+---------------+
becomes
+---------------+---------------+---------------+---------------+
| | |I J K L f g h i|M N O P j k l m|
+---------------+---------------+---------------+---------------+
我们可以使用与第一步完全相同的技巧,因为我们想要对 32 位字的两个 16 位半部分执行完全相同的操作,我们可以并行进行:
tmp = (input ^ (input >> 4)) & 0x00f000f0;
构造我们将用于交换的两对 4 位,然后
input ^= (tmp ^ (tmp << 4));
实际进行交换。
我们可以继续应用相同的原则,直到交换完成。每个点参与交换的比特用#
标记:
+---------------+---------------+---------------+---------------+
|A B C D E F G H|I J K L M N O P|Q R S a b c d e|f g h i j k l m|
+---------------+---------------+---------------+---------------+
###############/###############
+---------------+---------------+---------------+---------------+
|A B C D E F G H|Q R S a b c d e|I J K L M N O P|f g h i j k l m|
+---------------+---------------+---------------+---------------+
#######/####### #######/#######
+---------------+---------------+---------------+---------------+
|A B C D Q R S a|E F G H b c d e|I J K L f g h i|M N O P j k l m|
+---------------+---------------+---------------+---------------+
###/### ###/### ###/### ###/###
+---------------+---------------+---------------+---------------+
|A B Q R C D S a|E F b c G H d e|I J f g K L h i|M N j k O P l m|
+---------------+---------------+---------------+---------------+
#/# #/# #/# #/# #/# #/# #/# #/#
+---------------+---------------+---------------+---------------+
|A Q B R C S D a|E b F c G d G e|I f J g K h L i|M j N k O l P m|
+---------------+---------------+---------------+---------------+
代码:
tmp = (input ^ (input >> 8)) & 0x0000ff00;
input ^= (tmp ^ (tmp << 8));
tmp = (input ^ (input >> 4)) & 0x00f000f0;
input ^= (tmp ^ (tmp << 4));
tmp = (input ^ (input >> 2)) & 0x0c0c0c0c;
input ^= (tmp ^ (tmp << 2));
tmp = (input ^ (input >> 1)) & 0x22222222;
input ^= (tmp ^ (tmp << 1)); /* = output */
可以通过向后运行4个步骤来执行反向操作:
tmp = (input ^ (input >> 1)) & 0x22222222;
input ^= (tmp ^ (tmp << 1)); /* = output */
tmp = (input ^ (input >> 2)) & 0x0c0c0c0c;
input ^= (tmp ^ (tmp << 2));
tmp = (input ^ (input >> 4)) & 0x00f000f0;
input ^= (tmp ^ (tmp << 4));
tmp = (input ^ (input >> 8)) & 0x0000ff00;
input ^= (tmp ^ (tmp << 8));
尽管您可以针对您的特定应用对此进行改进,如果已知所有其他位都为零:请参阅我对另一个的回答问题 here .
最后一点,不要相信任何人关于相对性能的任何说法此处建议的任何方法都没有在您的中对其进行基准测试申请。 (特别是,大型查找表看起来会好得多在简单的微基准测试中,它们实际上在给定的真实环境中应用程序,由于从缓存中逐出大量其他数据,这会对外部循环产生负面影响。)
关于c - 如何在位图中的位之间插入零?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4597940/
我需要修复 getLineNumberFor 方法,以便如果 lastName 的第一个字符位于 A 和 M 之间,则返回 1;如果它位于 N 和 Z 之间,则返回 2。 在我看来听起来很简单,但我不
您好,感谢您的帮助!我有这个: 0 我必须在每次点击后增加“pinli
Javascript 中是否有一种方法可以在不使用 if 语句的情况下通过 switch case 结构将一个整数与另一个整数进行比较? 例如。 switch(integer) { case
我有一列是“日期”类型的。如何在自定义选项中使用“之间”选项? 最佳答案 请注意,您有2个盒子。 between(在SQL中)包含所有内容,因此将框1设置为:DATE >= startdate,将框2
我有一个表,其中包含年、月和一些数字列 Year Month Total 2011 10 100 2011 11 150 2011 12 100 20
这个问题已经有答案了: Extract a substring between double quotes with regular expression in Java (2 个回答) how to
我有一个带有类别的边栏。正如你在这里看到的:http://kees.een-site-bouwen.nl/ url 中类别的 ID。带有 uri 段(3)当您单击其中一个类别时,例如网页设计。显示了一
这个问题在这里已经有了答案: My regex is matching too much. How do I make it stop? [duplicate] (5 个答案) 关闭 4 年前。 我
我很不会写正则表达式。 我正在尝试获取括号“()”之间的值。像下面这样的东西...... $a = "POLYGON((1 1,2 2,3 3,1 1))"; preg_match_all("/\((
我必须添加一个叠加层 (ImageView),以便它稍微移动到包含布局的左边界的左侧。 执行此操作的最佳方法是什么? 尝试了一些简单的方法,比如将 ImageView 放在布局中并使用负边距 andr
Rx 中是否有一些扩展方法来完成下面的场景? 我有一个开始泵送的值(绿色圆圈)和其他停止泵送的值(簧片圆圈),蓝色圆圈应该是预期值,我不希望这个命令被取消并重新创建(即“TakeUntil”和“Ski
我有一个看起来像这样的数据框(Dataframe X): id number found 1 5225 NA 2 2222 NA 3 3121 NA 我有另一个看起来
所以,我正在尝试制作正则表达式,它将解析存储在对象中的所有全局函数声明,例如,像这样 const a = () => {} 我做了这样的事情: /(?:const|let|var)\s*([A-z0-
我正在尝试从 Intellivision 重新创建 Astro-Smash,我想让桶保持在两个 Angular 之间。我只是想不出在哪里以及如何让这个东西停留在两者之间。 我已经以各种方式交换了函数,
到处检查但找不到答案。 我有这个页面,我使用 INNER JOIN 将两个表连接在一起,获取它们的值并显示它们。我有这个表格,用来获取变量(例如开始日期、结束日期和卡号),这些变量将作为从表中调用值的
我陷入了两个不同的问题/错误之间,无法想出一个合适的解决方案。任何帮助将不胜感激 上下文、FFI 和调用大量 C 函数,并将 C 类型包装在 rust 结构中。 第一个问题是ICE: this pat
我在 MySQL 中有一个用户列表,在订阅时,时间戳是使用 CURRENT_TIMESTAMP 在数据库中设置的。 现在我想从此表中选择订阅日期介于第 X 天和第 Y 天之间的表我尝试了几个查询,但不
我的输入是开始日期和结束日期。我想检查它是在 12 月 1 日到 3 月 31 日之间。(年份可以更改,并且只有在此期间内或之外的日期)。 到目前为止,我还没有找到任何关于 Joda-time 的解决
我正在努力了解线程与 CPU 使用率的关系。有很多关于线程与多处理的讨论(一个很好的概述是 this answer )所以我决定通过在运行 Windows 10、Python 3.4 的 8 CPU
我正在尝试编写 PHP 代码来循环遍历数组以创建 HTML 表格。我一直在尝试做类似的事情: fetchAll(PDO::FETCH_ASSOC); ?>
我是一名优秀的程序员,十分优秀!