【问题标题】:Write a program to compute factorial of an integer in ARM assembly language用ARM汇编语言编写一个计算整数阶乘的程序
【发布时间】:2016-10-11 03:07:58
【问题描述】:

给定一个整数,我必须编写一个返回其阶乘值的函数。

这是我的阶乘函数代码:

bl getnum

move r3, r0

mov r1, #1   -- counter

mov r4, r0


loop:
   sub r0, r0, #1

   mul r3, r0, r3

   add r1, r1, #1  

   subs r1, r4  -- check if counter = the initial r0
beg loop

mov r0, r3

bl printnum

但是,此代码会产生不正确的结果。例如,当我输入 5 时,它会给出 20 而不是 120。有人可以帮我找出问题所在吗?我的逻辑推理似乎有效,但我不知道我是否犯了导致程序以不同方式运行的语法错误

【问题讨论】:

  • 发布代码时,您应该复制粘贴而不是输入代码,以避免拼写错误。我怀疑您的实际代码中是否包含beg

标签: assembly arm


【解决方案1】:

sub 将减法的结果写回到目标操作数。这不是你想要的——你只是想做一个比较,所以你应该使用cmp

cmp r1, r4  -- cmp always updates the flags, so you don't need to write cmps
bne loop    

但是,您的代码无法处理 n 为 0 或 1 的情况。此外,当您在 r0 中已经有一个非常合适的计数器时,没有必要使用额外的计数器 (r1) .所以你可以把它改写成这样:

mov r3, #1  -- default value
loop:
  cmp r0, #1
  -- if (n > 1) { r3 *= n; n--; goto loop; }
  mulgt r3, r0, r3
  subgt r0, r0, #1
  bgt loop

【讨论】:

  • 我正要发布相同的代码。这是了解所有条件指令以减少代码大小的好方法。
  • @InfinitelyManic:它在 thumb2 中的效果稍差(在这种情况下,像这样的条件块需要 IT 指令,即使汇编程序自动发出它),并且在 AArch64 中根本不可用。对于 Thumb2,我认为循环前的 cbz r0, after_loop 将具有相同的总代码大小,但循环内的代码较小。
【解决方案2】:

请阅读这篇精彩的post

附带说明,请注意,您没有遵循 ARM 调用 convention of ARM 来确保正确的上下文切换。

我认为您使用的寄存器太多,请尝试减少它们的数量。将更容易跟踪您的代码流和调试。

这是我的最终建议:

mov r3, #1
cmp r0, #0
beq end

factorial:
    mul r3, r3, r0
    sub r0, r0, #1 
    beg factorial 
end:              
    mov r0, r3

我认为在你的解决方案中你应该改变

subs r1, r4  -- check if counter = the initial r0

进入

cmp r1, r4  -- check if counter = the initial r0

所以你会检查r1 > r4是否不改变r1,否则你会在一个循环后退出。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-15
    • 2013-10-07
    • 1970-01-01
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多