对于像这样的代码:
int res = 0;
for (int i = 0; i < 32; i++)
{
res += 1 << i;
}
Run Code Online (Sandbox Code Playgroud)
生成此代码(发布模式,未附加调试器,64位):
xor edx,edx
mov r8d,1
_loop:
lea ecx,[r8-1]
and ecx,1Fh ; why?
mov eax,1
shl eax,cl
add edx,eax
mov ecx,r8d
and ecx,1Fh ; why?
mov eax,1
shl eax,cl
add edx,eax
lea ecx,[r8+1]
and ecx,1Fh ; why?
mov eax,1
shl eax,cl
add edx,eax
lea ecx,[r8+2]
and ecx,1Fh ; why?
mov eax,1
shl eax,cl
add edx,eax
add r8d,4
cmp r8d,21h
jl …Run Code Online (Sandbox Code Playgroud) 这个问题出现在一个挑战中,但由于它现在已经关闭,因此可以询问它.
问题(不是这个问题本身,这只是背景信息)可以像这样直观地描述,借用他们自己的图像:

我选择以最佳方式解决它.这可能(对于决策变量)是NP完全问题(它肯定在NP中,它闻起来像一个精确的封面,虽然我还没有证明一般的确切覆盖问题可以减少到它),但是没关系,它只需要在实践中快速,不一定在最坏的情况下.在这个问题的上下文中,我对任何近似算法都不感兴趣,除非它们提供削减.
有一个明显的ILP模型:生成所有可能的正方形(如果它只覆盖存在的网格单元格,则x_i可以使用正方形),为每个正方形引入一个二进制变量,指示我们是否使用它,然后
minimize sum x_i
subject to:
1) x_i is an integer
2) 0 ? x_i ? 1
3) for every cell c
(sum[j | c ? square_j] x_j) = 1
Run Code Online (Sandbox Code Playgroud)
约束3表示每个细胞只被覆盖一次.约束1和2使x_i成为二进制.最小解决方案为原始问题提供了最佳解决方案.
这种线性松弛(即忽略约束1)是不太合适的,但它做了这样的事情(这是一个6x6网格,左上角缺失):

这里有13个方块被选为"一半"(给出一个6.5的目标值),大小(所以你可以更容易找到它们)
此实例的最佳解决方案的目标值为8,例如:

线性放松是一半体面,但我并不完全满意.差距有时超过10%,有时会导致非常缓慢的整数阶段.
那是实际问题的来源,是否有额外的限制,我可以添加(懒惰)作为削减,以改善分数解决方案?
我已经尝试了问题的替代配方来寻找切割,例如,而不是选择正方形,如果我们选择"左上角"和"右下角",然后匹配形成非重叠方块覆盖所有细胞?然后在每个"反斜杠状对角线"上,必须有匹配数量的左上角和右下角.但这没有用,因为如果我们选择正方形,那么无论如何,这种情况总是正确的,也是在分数解决方案中.
我还尝试了一些关于重叠的推理,例如,如果两个正方形明显重叠,它们的总和不得大于1,并且可以通过添加完全包含在重叠区域中的所有正方形来改善.但是这种约束不如所有细胞只被覆盖一次的约束力强.
我已经尝试过关于总面积的推理(例如,总覆盖面积必须等于单元格的数量),但是已经通过约束来保证,每个单元必须覆盖一次,并根据总面积来说明只允许更多的自由.
我也尝试用方形数字(每个方格的面积,正好,正方形)和方形数字的差异做一些事情,但这并没有以任何有用的方式结束.
例如,在:
bool eq = (1 / double.Parse("-0.0")) == (1 / -0.0);
Run Code Online (Sandbox Code Playgroud)
eq会的false.
double.Parse将不得不经历一些麻烦明确忽略零的标志,即使不这样做几乎从来没有导致问题.因为我需要原始表示,所以我必须编写自己的解析函数,其中特殊情况为负零,并double.Parse用于其他所有内容.
这不是一个大问题,但我真的很想知道为什么他们决定忽略零的标志,因为在我看来,不这样做不会是坏事.
在测量某些东西的同时,我测量的吞吐量比我计算的要低得多,我将其缩小到LZCNT指令(它也发生在TZCNT中),如以下基准所示:
xor ecx, ecx
_benchloop:
lzcnt eax, edx
add ecx, 1
jnz _benchloop
Run Code Online (Sandbox Code Playgroud)
和:
xor ecx, ecx
_benchloop:
xor eax, eax ; this shouldn't help, but it does
lzcnt eax, edx
add ecx, 1
jnz _benchloop
Run Code Online (Sandbox Code Playgroud)
第二个版本要快得多.它不应该.LZCNT没有理由对其输出有输入依赖性.与BSR/BSF不同,xZCNT指令总是覆盖其输出.
我在4770K上运行它,所以LZCNT和TZCNT没有被执行为BSR/BSF.
这里发生了什么?
我有一个具有1个引用程序集的应用程序(test.exe,test.dll)
我想要的是在test.exe运行时,它应该将发布者名称显示为"TestCompany".
为此,我对它进行了数字签名,它就是我想做的.如果我改变test.exe发布者名称的一个字节是"未知".这很好.
但是,如果我改变了test.dll,应用程序运行时没有任何反应,并将发布者名称显示为"TestCompany".哪个对我不好.
所以我把强名称放在app.config中test.dll并添加<bypassTrustedAppStrongNames enabled="false" />.
再一次,没有区别.所以我再次搜索并发现bypassTrustedAppStrongNames只检查程序集是否具有强名称.不是验证.这对我来说再好不过了.
我真正想要的是保护用户,而不是我的应用程序.如果用户运行我的应用程序并且它从我这里说出来,它必须来自我的每个字节.如果应用程序被更改,即使是单个字节,它也必须通知用户,而不是来自我.这是数字签名与强名称一起做的,但它们似乎都不是那么好.或者我错过了什么?
我能想到的最后一种可能的方法是手动检查程序集的强名称.
PS:目标.net框架是2.0
最近,为了磨练我的装配技巧,我在C++中为玩具语言编写了一个非常简单的编译器.它运行单次传递,并在解析阶段直接将代码发送到几个字符串流,每个字符串流代表一段代码(即一个代表section .bss,而其他代表.data和.text).然后,这些字符串流被写入文件,我使用NASM和gcc来汇编和链接它们.我知道这种单遍方法效率非常低,但同样,这更像是一种理解代码生成阶段的练习.无论如何,我想修改我的代码直接发出LLVM IL而不是原始程序集,再次作为学习练习.是否有LLVM IL的入门级指南?或者,更好的是,确定装配线的等效IL代码的工具?我看了,我只找到了完整的规格,这比我需要的更多信息.
这三个片段的执行时间:
pageboundary: dq (pageboundary + 8)
...
mov rdx, [rel pageboundary]
.loop:
mov rdx, [rdx - 8]
sub ecx, 1
jnz .loop
Run Code Online (Sandbox Code Playgroud)
还有这个:
pageboundary: dq (pageboundary - 8)
...
mov rdx, [rel pageboundary]
.loop:
mov rdx, [rdx + 8]
sub ecx, 1
jnz .loop
Run Code Online (Sandbox Code Playgroud)
还有这个:
pageboundary: dq (pageboundary - 4096)
...
mov rdx, [rel pageboundary]
.loop:
mov rdx, [rdx + 4096]
sub ecx, 1
jnz .loop
Run Code Online (Sandbox Code Playgroud)
对于第一个片段,在4770K上,每次迭代大约5个周期,对于第二个片段,每次迭代大约9个周期,然后是第三个片段的5个周期.它们都访问完全相同的地址,这是4K对齐的.在第二个片段中,只有地址计算跨越页面边界:rdx并且rdx + 8不属于同一页面,负载仍然是对齐的.如果偏移量很大,则会再次回到5个周期.
这种效果一般如何起作用?
通过ALU指令从加载路由结果,如下所示:
.loop:
mov rdx, …Run Code Online (Sandbox Code Playgroud) 我正在尝试在Windows 8中使用MEF.
为了构建我AssemblyCatalog的容器,我需要一个对程序集的引用.在过去,我会这样做:
var catalog = new AssemblyCatalog(typeof(App).Assembly);
Run Code Online (Sandbox Code Playgroud)
神秘地,物体Assembly不再存在于Type物体上.有人知道好的工作吗?有没有另一种方法来获得组装?我可以使用加载它Assembly.Load,但我需要程序集的名称.我不能从类型中得到那个.
使用DirectoryCatalog可能的备用?我不喜欢这个主意,但我会做我需要的.
以下代码段评估为零:
int result = unchecked((int)double.MaxValue);
Run Code Online (Sandbox Code Playgroud)
然而,如果你这样做:
double x = double.MaxValue
int result = (int)x;
Run Code Online (Sandbox Code Playgroud)
结果是(你会猜到这个吗?)int.MinValue.仅这个事实就足够了[见下文],但我的印象unchecked是强迫编译器发出代码,假装不知道转换肯定会失败和/或发生某些溢出.换句话说,它应该给出与编译器不知道所涉及的值时相同的结果(假设它是在禁用"检查算术溢出"的情况下编译的)
那么,这里发生了什么?我对unchecked错误的理解是什么?
根据C#/ .NET标准,其中一个结果是"错误的"吗?
编辑:int.MinValue很容易解释:cvttsd2si当溢出但异常被屏蔽时给出0x80000000.这是JIT编译器使用的指令,如反汇编窗口中所示.但这并不能解决问题的任何部分.
根据ECMA 334(C#2规范),unchecked关键字应始终截断,因此在这两种情况下结果应为零:
int result1 = unchecked((int)double.MaxValue);
double x = double.MaxValue;
int result2 = unchecked((int)x);
Run Code Online (Sandbox Code Playgroud)
但它不是,第二个给出int.MinValue.这对我来说仍然像编译器错误.
是否有处理器会VPMASKMOVD为屏蔽元素生成故障?
根据英特尔软件开发人员手册,答案显然是“否”:
故障仅由于导致故障的屏蔽位所需的存储器访问而发生。如果该存储器位置的相应掩码位为0,则不会因引用该存储器位置而发生故障。例如,如果掩码位全部为零,则不会检测到故障。
然而,AMD64 架构程序员手册第 4 卷说道:
未选择从内存加载或存储到内存的元素的异常和陷阱行为取决于实现。例如,给定的实现可能会发出数据断点或零屏蔽且未实际写入的双字的页错误信号。
是否有真正做到这一点的处理器?这是假的吗?这是怎么回事。