【问题标题】:determine parity of a bit representation of a number in MIPS确定 MIPS 中数字的位表示的奇偶校验
【发布时间】:2010-04-11 15:17:18
【问题描述】:

MIPS 中是否有一些指令可以确定某个位表示的奇偶校验?我知道确定“数字”是否具有偶校验或奇校验是将二进制表示的各个位异或在一起,但这对于一组 MIPS 指令来说似乎是计算密集型的......我需要这样做尽快。

另外,我正在处理的数字是用格雷码表示的......只是把它扔在那里。那么 MIPS 中是否有一些伪指令来确定“数字”的奇偶性,还是我必须手动完成?

如果没有 MIPS 指令(这似乎不太可能),有什么建议可以手动完成吗?

谢谢, 赫里斯托

跟进:我发现了一个优化,但我的实现不起作用。

unsigned int v; // 32-bit word
v ^= v >> 1;
v ^= v >> 2;
v = (v & 0x11111111U) * 0x11111111U;
return (v >> 28) & 1;

【问题讨论】:

    标签: mips parity


    【解决方案1】:

    我不知道有任何带有奇偶校验指令的 MIPS 变体,但是有一个比依次运行每个 32 位的明显方法更快地计算奇偶校验的技巧。在 C 中:

    result = in ^ (in >> 16);
    result ^= (result >> 8);
    result ^= (result >> 4);
    result ^= (result >> 2);
    result ^= (result >> 1);
    result &= 1;
    
    • 在第一步之后,结果的低 16 位包含输入的第 N 位和 N+16 位的奇偶校验 - 本质上,奇偶校验计算已经一次执行了 16 步。写result{N} 表示“result 的第 N 位”:

      result{0}  =  in{0} ^ in{16}
      result{1}  =  in{1} ^ in{17}
      result{2}  =  in{2} ^ in{18}
      ...
      result{7}  =  in{7} ^ in{23}
      result{8}  =  in{8} ^ in{24}
      ...
      result{15} = in{15} ^ in{31}
      

      (现在可以忽略result 的剩余前 16 位;它们在剩余的计算中没有用处)。

    • 经过第二步,result的低8位包含原始输入的N、N+8、N+16、N+24位的奇偶校验:

      result{0} = result{0} ^ result{8}  =  in{0} ^  in{8} ^ in{16} ^ in{24}
      result{1} = result{1} ^ result{9}  =  in{1} ^  in{9} ^ in{17} ^ in{25}
      ...
      result{7} = result{7} ^ result{15} =  in{7} ^ in{15} ^ in{23} ^ in{31}
      

      (同样,从这里开始可以忽略剩余的位)。

    • ...以此类推,直到原始输入的所有位的奇偶校验最终到达result的底部位:

      result{0} = in{0} ^ in{1} ^ in{2} ^ ... ^ in{30} ^ in{31}
      

    这很容易直接翻译成 MIPS 汇编;这是 11 条指令:

    # input in $a0, output in $v0, $t0 corrupted
    srl $t0, $a0, 16
    xor $v0, $a0, $t0
    srl $t0, $v0, 8
    xor $v0, $v0, $t0
    srl $t0, $v0, 4
    xor $v0, $v0, $t0
    srl $t0, $v0, 2
    xor $v0, $v0, $t0
    srl $t0, $v0, 1
    xor $v0, $v0, $t0
    and $v0, $v0, 1
    

    可能的改进可能是使用查找表。例如,在前两个步骤之后,我们有:

        result{0} =  in{0} ^  in{8} ^ in{16} ^ in{24}
        result{1} =  in{1} ^  in{9} ^ in{17} ^ in{25}
        ...
        result{7} =  in{7} ^ in{15} ^ in{23} ^ in{31}
    

    所以此时我们可以使用 256 字节的查找表。在 C 中:

    result = in ^ (in >> 16);
    result ^= (result >> 8);
    result = lookup_table[result & 0xff];
    

    lookup_table[n] 已预先计算的位置,例如:

    for (i = 0; i < 256; i++) {
        n = i ^ (i >> 4);
        n ^= (n >> 2);
        n ^= (n >> 1);
        lookup_table[i] = n & 1;
    }
    

    这是 7 个 MIPS 指令,不包括将查找表基地址加载到寄存器中:

    # input in $a0, lookup table address in $a1, output in $v0, $t0 corrupted
    srl  $t0, $a0, 16
    xor  $v0, $a0, $t0
    srl  $t0, $v0, 8
    xor  $v0, $v0, $t0
    andi $v0, $v0, 0xff
    addu $t0, $a1, $v0
    lbu  $v0, 0($t0)
    

    但是,这是 7 条指令,其中包括内存访问,而 11 条指令是纯粹的寄存器操作;它可能会也可能不会更快。 (这种微优化总是需要分析!)

    【讨论】:

    • 感谢您的回复。这就是我目前拥有的......但我正在尝试将代码优化为更少的指令,因为这组指令将被多次调用并且它会降低性能。有什么优化想法吗?
    • 第二个xor之后,所有有用的信息都在后8位;最终的答案只是这些位的函数,因此您可以在那时将它们用作 256 字节查找表的索引。这是否会更快取决于内存访问、缓存等的速度 - 你必须尝试并分析它......
    • “所有有用的信息都在底部 8 位”是什么意思?所以你建议移位 16、异或、移位 8、异或,然后最右边的 8 位是重要的?
    • 好的。非常感谢!我已经实现了这个并且它不起作用,但我确定我有一些我看不到的错误。
    • @Hristo:哎呀,不,这将是我搞砸查找表初始化的错。我现在已经更正了。对此感到抱歉。
    猜你喜欢
    • 2015-04-04
    • 2015-06-29
    • 1970-01-01
    • 1970-01-01
    • 2014-03-06
    • 1970-01-01
    • 1970-01-01
    • 2022-11-01
    相关资源
    最近更新 更多