以下代码在调试模式下工作良好,因为_BitScanReverse64被定义为如果未设置位则返回0。引用MSDN:(返回值为)“如果已设置索引,则为非零;如果未找到设置位,则为0。”
如果在发布模式下编译此代码,它仍然可以工作,但是如果启用编译器优化,例如\o1或\o2,则索引不为零,assert()
将失败。
#include <iostream>
#include <cassert>
using namespace std;
int main()
{
unsigned long index = 0;
_BitScanReverse64(&index, 0x0ull);
cout << index << endl;
assert(index == 0);
return 0;
}
这是故意的行为吗?我正在使用Visual Studio Community 2015,版本14.0.25431.01更新3。(我把cout留在了,这样在优化过程中就不会删除变量index)。另外,是否有一个有效的解决办法,或者我应该不直接使用这个编译器?
另外,当输入为零时,本征将垃圾留在index
中,比asm指令的行为弱。这就是它有一个单独的布尔返回值和整数输出操作数的原因。
尽管index
参数是通过引用获得的,但编译器将其视为仅输出。
unsigned char_bitscanreverse64(unsigned__int32*索引,unsigned__int64掩码)
Intel针对同一内部文件的内部文件指南文档似乎比您链接的Microsoft文档更清晰,并对MS文档试图表达的内容提供了一些信息。但仔细阅读,它们似乎都在说同样的话,并且描述了bsr
指令的一个薄包装。
Intel将bsr
指令记录为在输入为0时生成“未定义值”,但在这种情况下设置ZF。但AMD将其记录为保持目标不变:
AMD在AMD64架构程序员手册第3卷:通用和系统说明中的BSF条目
...如果第二个操作数包含0,则指令集将ZF设置为1,并且不改变目标寄存器的内容。...
在Intel(但可能不是AMD)上,这甚至没有将64位寄存器截短为32位。例如mov rax,-1
;BSF eax,ECX
(带有零ECX)保留RAX=-1(64位),而不是从异或eax,0
得到的0x00000000FFFFFFFFF
。但对于非零ECX,bsf eax,ECX
具有通常的效应,即将零扩展为RAX,例如,留下RAX=3。
为什么英特尔还没有记录下来。可能是一个真正老旧的x86 CPU(像原来的386?)以不同的方式实现?Intel和AMD经常超越x86手册中的规定,以避免破坏现有的广泛使用的代码(例如Windows),这可能是开始的原因。
在这一点上,Intel似乎不太可能放弃输出依赖关系,并为Input=0保留实际的垃圾或-1或32,但由于缺乏文档,这一选项仍然是开放的。
Skylake删除了lzcnt
和tzcnt
的false依赖项(后来的一个uarch删除了popcnt
的false dep),同时仍然保留了bsr
/bsf
的依赖项。(为什么打破LZCNT的“输出依赖”很重要?)
当然,由于MSVC优化了index=0
初始化,所以它可能只是使用它想要的任何目标寄存器,而不一定是保存C变量前一个值的寄存器。所以即使你想,我不认为你可以利用DST未修改的行为,即使它是在AMD上保证。
所以用C++的术语来说,intrinsic不依赖于index
。但在asm中,指令对dst寄存器有输入依赖关系,如add dst,src
指令。如果编译器不小心,这可能会导致意外的性能问题。
不幸的是,在Intel硬件上,popcnt/lzcnt/tzcnt
asm指令对它们的目的地也有错误的依赖关系,尽管结果从不依赖于它。编译器可以解决这一问题,因为现在已经知道了,所以在使用本机时不必担心这一点(除非您有一个超过几年的编译器,因为它是最近才发现的)。
您需要检查它以确保index
是有效的,除非您知道输入是非零的。例如。
if(_BitScanReverse64(&idx, input)) {
// idx is valid.
// (MS docs say "Index was set")
} else {
// input was zero, idx holds garbage.
// (MS docs don't say Index was even set)
idx = -1; // might make sense, one lower than the result for bsr(1)
}
如果您想避免这个额外的检查分支,那么如果您针对的是足够新的硬件(例如Intel Haswell或AMD推土机IIRC),您可以通过不同的内部控制使用lzcnt
指令。它“工作”甚至当输入是全零,实际上计数前导零,而不是返回最高设置位的索引。
我试图在函数的管道中使用中的函数,并发现它对我的语法选择非常敏感,这是我没有想到的。这里有一个玩具的例子。 好的,现在让我们假设我想在数据帧中选定列的名称上迭代一个函数(幽默一下)。在这里,我将使用选定列中的值来过滤初始数据集,计算剩余的唯一ID的数量,并将结果作为一行tibble返回,然后将其绑定到新的tibble中。当我在函数中创建一个新的tibble,然后将应用于该tibble中的选定列作为
提前致谢
问题内容: 这就是整个查询… 如果… 和… 有明显的理由吗? 正在服用? 扩展说明 问题答案: 您可以始终使用EXPLAIN或EXPLAIN EXTENDED 来查看MySql对查询所做的操作 您也可以用稍微不同的方式编写查询,是否尝试过以下方法? 看看效果如何会很有趣。我希望它会更快,因为目前,我认为MySql将为您拥有的每个节目运行内部查询1(这样一个查询将运行多次。联接应该更有效。) 如果希
我有一张带有以下原型的桌子: 我想创建一个过程来插入具有特定长度的随机字符串,我写了以下内容: 这样说: 问题是它插入NULL作为NAME字段。 我的怀疑是,当同时循环终止时,对所做的更改超出了范围。 我还尝试使用如下的全局变量: 也在程序之外声明了,但没有发生什么特别的事情 感谢您的帮助<向你问好。
使用Python 3.3,我想循环d.items()并根据if条件返回匹配项。这是代码: 我希望打印“匹配”,但是我得到的是两个语句都相反打印,即, 如何让代码只打印正确的语句?感谢任何帮助。
问题内容: 前一阵子,在使用Class.getMethod和自动装箱时,我遇到了类似的问题,因此在自己的查找算法中实现它很有意义。但是,真正让我感到困惑的是,以下两种方法也不起作用: String.class实现了Serializable接口,我确实希望它包含在lookup方法中。 我也必须在自己的查找算法中考虑这一点吗? 编辑 :我确实读过Javadoc, 所以让我强调一下问题的第二部分 :如果