2

使用具有复杂索引的多维数组是很常见的情况。当所有索引都是整数时,这确实令人困惑且容易出错,因为您可以轻松地混淆列和行(或您拥有的任何内容)并且编译器无法识别问题。实际上应该有两种类型的索引:行和列,但它不是在类型级别上表示的。

这是我想要的一个小例子:

var table = new int[RowsCount,ColumnsCount];
Row row = 5;
Column col = 10;
int value = table[row, col];

public void CalcSum(int[,] table, Column col)
{
    int sum = 0;
    for (Row r = 0; r < table.GetLength(0); r++)
    {
        sum += table[row, col];
    }
    return sum;
}

CalcSum(table, col); // OK
CalcSum(table, row); // Compile time error

加起来:

  • 应静态检查索引是否混淆(类型检查)
  • 重要的!它们应该是运行时高效的,因为将整数包装到包含索引的自定义对象然后将它们解包回来对性能来说是不合适的
  • 它们应该可以隐式转换为整数,以便用作本机多维数组中的索引

有什么办法可以做到这一点?完美的解决方案类似于typedef仅编译成平面整数的编译时检查。

4

1 回答 1

1

x64 抖动只会使您减速 2 倍。它生成有趣的优化代码。使用该结构的循环如下所示:

00000040  mov         ecx,1 
00000045  nop         word ptr [rax+rax+00000000h] 
00000050  lea         eax,[rcx-1] 
                s.Idx = j;
00000053  mov         dword ptr [rsp+30h],eax 
00000057  mov         dword ptr [rsp+30h],ecx 
0000005b  add         ecx,2 
            for (int j = 0; j < 100000000; j++) {
0000005e  cmp         ecx,5F5E101h 
00000064  jl          0000000000000050 

这需要一些注释,因为代码不寻常。首先,偏移 45 处的奇怪 NOP 用于在循环开始时对齐指令。这使得偏移 64 处的分支更快。53 处的指令看起来完全没有必要。您在这里看到的是循环展开,请注意 5b 处的指令如何将循环计数器增加 2。但是优化器不够聪明,因此也无法看到存储是不必要的。

最重要的是,没有看到 ADD 指令。换句话说,代码实际上并没有计算“sum”的值。这是因为你没有在循环之后的任何地方使用它,优化器可以看到计算是无用的并完全删除它。

它在第二个循环中做得更好:

000000af  xor         eax,eax 
000000b1  add         eax,4 
            for (int j = 0; j < 100000000; j++) {
000000b4  cmp         eax,5F5E100h 
000000b9  jl          00000000000000B1 

它现在完全删除了“sum”计算和“i”变量赋值。它也可以删除整个 for() 循环,但抖动优化器从未这样做过,它假定延迟是故意的。

希望现在信息很清楚:避免从人为的基准中做出假设,只分析真实代码。您可以通过实际显示“sum”的值来使其更加真实,这样优化器就不会丢弃计算。在循环之后添加这行代码:

        Console.Write("Sum = {0} ", sum);

现在你会发现没有什么不同了。

于 2012-11-09T12:18:05.583 回答