【问题标题】:Multiplication algorithm in SPARCSPARC 中的乘法算法
【发布时间】:2012-10-13 20:00:26
【问题描述】:

在 SPARC 的这种乘法算法上已经工作了几天(连续)... 真的不知道出了什么问题。我已经逐步完成了代码的几次迭代。它正在做提议的 C 算法想要它做的事情。这里是C

negative = multiplier >= 0 ? 0 : 1;
product = 0;
for (i = 0; i < 32; i++) {
    if (multiplier & 1)
        product += multiplicand;
(product and multiplier registers combined as a unit) >> 1;
}
if (negative)
    product -= multiplicand;

这里是 SPARC 程序集,注意我还没有实现负数的功能。该程序运行建议的次数。所以循环不是问题。我认为我的问题可能是我如何计算两个 32 位寄存器之间的右移,目前只是(在伪代码中)

sra 小寄存器 1 if(大寄存器的最右边位 = 1) 将小寄存器的最左边位更改为 1 sra 更大的寄存器

但它似乎并没有按计划进行,因为我得到的数字真的很不稳定

这是 SPARC 中的整个程序...如果你们能提供任何帮助,我们将不胜感激。

 fmt:   .asciz "Multiplicand: %d, Product: %8.8X%8.8X Counter: %d\n"            !output statement
.align 4                !align formatting

.global main
main:   save     %sp, -96, %sp
set     82732983, %l0       !move multiplicand into register %l0
set     120490892, %l1      !move multiplier into register %l1
set     0, %l2          !initialize product variable at 0
set     1, %l3          !initialize counter variable to 1
ba  test
mov     32, %l5         !put max loop value in a register

loop:
set     fmt, %o0        !setup the format string for the print statement
mov     %l0, %o1        !moving variables for printing
mov     %l1, %o2
mov     %l2, %o3
mov %l3, %o4
call    printf
nop
postprint:
    and     %l1, 1, %l6     !bitwise and between multiplier and 1, store result in %l6
cmp     %l6, 0          !comparison statement comparing the above to 1
be  else            !skip the addition if rightmost bit of multiplier is 0
nop

add     %l0, %l2, %l2       !adding multiplicand and product
sra     %l1, 1, %l1     !shifting multiplier right
and     1, %l2, %l6     !checking if rightmost bit of product is a 1
cmp     %l6, 1          !conditional statement to check this
bl  endif           !if it's not a one, branch to zero
nop             !non op

clr     %o4
set 0x40000000, %o4     !put 0x40000000 in a register
or      %l1,    %o4,    %l1 !if it is a one, bitwise do or with 0x40000000 to make a one in the leftmost bit of the multiplier
    sra     %l2,    1,  %l2     !shift product to the right by 1
    inc     %l3         !increment counter variable
    ba      test            !and branch to the testing statement
    nop

endif:
clr     %o5
sra     %l2, 1, %l2     !arithmetic shift product right by one (first line of endif)
inc     %l3         !increment counter variable
ba  test            
nop
else:
    sra     %l1, 1, %l1     !shift multiplier to the right
    and     %l2, 1, %l6     !check if rightmost bit of product is 1
    cmp     %l6, 1          !conditional statement to check this
    bl      endif           !branch to endif if it's not
    nop             !nop
clr     %o4
set 0x40000000, %o4     !put 0x40000000 in a register
    or      %l1, %o4, %l1       !if the rightmost bit is one, we use a bitwise or to place a 1 in the leftmost bit of the multiplier
    sra     %l2, 1, %l2     !then right arithmetic shift the product
    inc     %l3         !and increment the counter
    ba      test
    nop

test:   cmp     %l3, %l5
    bl      loop


done:   mov 1,  %g1             !Exit the program
    ta  0

【问题讨论】:

  • 如果想成为日常常见的乘法,那么即使是 C/伪代码也不对。您可以针对 x*1 的简单情况对其进行测试,它将返回 x/2。

标签: assembly multiplication sparc


【解决方案1】:

将功能拆分为:Add()Multiply()

SPARC Assembly manual

Addition Algorithm

unsigned int Add(unsigned int num1, unsigned int num2)
{
    /* Iterate till there is no carry  */
    while (num2 != 0)
    {
        /* carry now contains common set bits of num1 and num2  */
        unsigned int carry = num1 & num2;  

        /* Sum of bits of numbers where at least one of the bits is not set */
        num1 = num1 ^ num2; 

        /* Carry is shifted by one so that adding it to x gives the required sum */
        num2 = carry << 1;
    }
    return num1;
}

Multiplication Algorithm

unsigned int Multiply(unsigned int multiplicand, unsigned int multiplier)
{
    unsigned int result = 0;

    while(multiplier != 0) /* Use while instead of for */
    {
        if (multiplier & 0x01) 
        {
            result = Add(result, multiplicand);
        }

        multiplicand <<= 1; /* Left shifting the value contained in 'multiplicand' by 1 */
        multiplier >>=1;    /* Right shifting the value contained in 'multiplier' by 1. */
   }

   return result;
}

请注意:int 在此假定为 32 位整数。 (您可以根据typedefs 的存在替换函数签名)。此外,您可以添加溢出检查并相应地处理错误。

【讨论】:

  • SPARC 有一个 add 指令,问题已经在使用它。你不需要模仿add,只需要乘法。
  • 不,整数add %l0, %l2, %l2。 FPADD32 显然是浮点数,在这种情况下该算法不起作用。 (除非乘数 float 并且乘数是 int)。此外,您的算法仅适用于无符号或非负符号int。负乘数永远不会从算术右移变成0
  • 同意,multiplicand 可以为负数,但multiplier 并非如此。唯一的方法是重复添加n 次?例如:
  • 您的 C 函数将其声明为已签名 int。这就是问题所在。
  • 惊讶的是,即使明确使用 `-Wconversion` 标志,编译器也没有收到转换警告。
猜你喜欢
  • 1970-01-01
  • 2011-07-08
  • 2013-03-10
  • 1970-01-01
  • 2015-03-02
  • 2021-12-03
  • 2010-12-27
  • 2017-09-12
  • 1970-01-01
相关资源
最近更新 更多