【问题标题】:How to calculate division remainder in SPARC Assembly?如何在 SPARC 程序集中计算除法余数?
【发布时间】:2011-10-10 04:10:00
【问题描述】:

这是计算两个正整数相除的伪代码。
HR寄存器保存余数,LR寄存器保存被除数。 (并最终保存root)

但是我认为这个算法有一些问题。
因为这个算法有时不能恢复减法。(除法是减法的继续。)

例如6 / 3 (0110 / 011)
该算法再减去一次-3。 (当我们手动计算这个除法时,这种情况永远不会发生)
所以我觉得这个算法有问题。
你不同意我的看法吗? 如何在Assembly中计算除法余数?

for i = 1 to num_of_bits do
(HR LR) << 1
if (HR >= 0) then
   HR = HR - DIVISOR
else
   HR = HR + DIVISOR
endif
if (HR > 0) then LR(lsb) = 1 endif
endfor

【问题讨论】:

  • 这是汇编?!用什么芯片?
  • 在 SPARC 中。我一定写过什么是架构……
  • stackoverflow.com/questions/5189631/…。正如最初提出的那样,问题是关于 6800,但答案同样适用于任何没有除法指令的处理器。
  • @JerryCoffin 哇,太棒了!

标签: algorithm assembly division integer-division sparc


【解决方案1】:

除法算法的几个实现(也计算余数)可以在SPARC architecture manual 的附录 E 中找到。

较新版本的 SPARC 体系结构包括除法运算符 UDIV 和 SDIV。

可以在here 找到进一步的实现。

【讨论】:

    【解决方案2】:

    我不会说 SPARC asm,但我会说 C。下面是 16/8=8,8 除法算法的示例实现:

    #include <stdio.h>
    
    typedef unsigned char uint8;
    typedef unsigned int uint;
    
    int u8div(uint8* dividendh, uint8* dividendl, uint8 divisor)
    {
      int i;
    
      if (*dividendh >= divisor)
        return 0; // overflow
    
      for (i = 0; i < 8; i++)
      {
        if (*dividendh >= 0x80)
        {
          *dividendh = (*dividendh << 1) | (*dividendl >> (8 - 1));
          *dividendl <<= 1;
    
          *dividendh -= divisor;
          *dividendl |= 1;
        }
        else
        {
          *dividendh = (*dividendh << 1) | (*dividendl >> (8 - 1));
          *dividendl <<= 1;
    
          if (*dividendh >= divisor)
          {
            *dividendh -= divisor;
            *dividendl |= 1;
          }
        }
      }
    
      return 1;
    }
    
    int u8div2(uint8* dividendh, uint8* dividendl, uint8 divisor)
    {
      uint dividend = (*dividendh << 8) | *dividendl;
    
      if (*dividendh >= divisor)
        return 0; // overflow
    
      *dividendl = dividend / divisor;
      *dividendh = dividend % divisor;
    
      return 1;
    }
    
    int main(void)
    {
      uint dividendh, dividendl, divisor;
    
      for (dividendh = 0; dividendh <= 0xFF; dividendh++)
        for (dividendl = 0; dividendl <= 0xFF; dividendl++)
          for (divisor = 0; divisor <= 0xFF; divisor++)
          {
            uint8 divh = dividendh, divl = dividendl, divr = divisor;
            uint8 divh2 = dividendh, divl2 = dividendl;
    
            printf("0x%04X/0x%02X=", (divh << 8) | divl, divr);
    
            if (u8div(&divh, &divl, divr))
              printf("0x%02X.0x%02X", divl, divh);
            else
              printf("ovf");
    
            printf(" ");
    
            if (u8div2(&divh2, &divl2, divr))
              printf("0x%02X.0x%02X", divl2, divh2);
            else
              printf("ovf");
    
            if ((divl != divl2) || (divh != divh2))
              printf(" err"); // "err" will be printed if u8div() computes incorrect result
    
            printf("\n");
          }
    
      return 0;
    }
    

    【讨论】:

    • 我认为if (*dividendh &gt;= 0x80) { *dividendh = (*dividendh &lt;&lt; 1) | (*dividendl &gt;&gt; (8 - 1)); *dividendl &lt;&lt;= 1; *dividendh -= divisor; *dividendl |= 1; }是没有必要的
    • @manutd:如果您删除该部分,代码将无法始终正常工作。我将使用更多代码来更新答案以进行演示。
    • 我同意你的观点,如果股息有一些初始值(!= 0)但是如果股息的初始值为0,两个函数的结果是相同的。
    • 你能告诉我为什么你把非零值放在股息中吗?不是提醒吗?如果是提醒,将股息的初始值设置为零不是更好吗?
    • @manutd:许多 CPU 的除法指令将 2N 位除以 N 位(并返回 N 位商和 N 位余数)基本上与乘法相反,即 N 位乘以 N 位并得到2N 位。这就是我所做的。计算是就地完成的(余数出现在被除数中,商出现在被除数中),这也是那些除法指令和除法子程序的典型特征。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多