【问题标题】:Adding signed numbers in assembly在程序集中添加带符号的数字
【发布时间】:2013-12-16 15:00:15
【问题描述】:

我想对数组元素求和。该数组包含正数和负数。

array db 07, 00, -3, 10, -7, 14, 9, -5, -100


lea ax, data
mov ds, ax
mov es, ax

lea si, array
mov cx, [si] 
mov si, 0002h
xor ax, ax
xor dx, dx 
Addition:
mov bl, [si]
cmp bl, 00h
jl NEGATIVE
xor bh, bh ;
jmp NEXTT
NEGATIVE:
mov bh, 0ffh
NEXTT:
add ax, bx
adc dx, 0
add si, 1
loop Addition

使用此代码的总和 (DX:AX) = 0003 FFAE H,这是错误的。我认为正确的答案是 FFFFFFAE H.

1- 我该如何解决这个问题?

2- 如何知道寄存器中的数字(例如 AX)是正数还是负数?

我用的是emu8086

【问题讨论】:

  • 在我看来,传入的数据被视为 16 位数字 - 在这种情况下,答案(最后 16 位)是正确的。就 CPU 而言,“大无符号正数”和“负”数之间没有区别。只有当您转换为浮点类型、将其打印出来等时,它才会成为一个问题——此时您需要知道您是代表无符号整数还是有符号整数。
  • 我将使用答案来获取这些值的平均值,然后打印平均值。
  • 在这种情况下,您可以简单地设置 DX=0 而无需关心进位。
  • @valplo 如果平均值为负数怎么办?这是关于有符号数字,而不是无符号数字。在这种情况下,将dx 设置为零将始终失败。
  • @Floris 如果答案是存储在ax 中的带符号16 位 值,0xffae 显然是正确答案。但是,如果答案应该是存储在dx:ax 中的有符号32 位 值,如OP 的代码中所示,则3:0xffae 是错误答案(十进制为262062)并且0xffff:0xffae 是正确答案(十进制为 -82)。

标签: assembly x86 signed addition x86-16


【解决方案1】:

您似乎没有正确处理整数溢出。进位标志是 unsigned 加减法,但你想要 signed 加法。溢出标志用于有符号加法,当符号改变时始终设置。

编辑:以前未经测试的代码无法正常工作。这是正确的(和独立的)代码。使用 MASM 6.11 测试。

.model 小 .stack 4096 。数据 数组大小 dw 7 数组分贝 -3、10、-7、14、9、-5、-100 数字数据库'0123456789abcdef' 。代码 开始: mov ax,seg array_size ;斧头,数据 mov ds,ax 移动,斧头 mov cx,[array_size] ; cx = 数组大小(以字节为单位)。 lea si,数组; si 指向数组。 ;数字在 dx:bx 中计算。 xor dx,dx xor bx,bx 添加循环: 移动,[si] ;数字是在 al 中读取的。 体重秤; cbw 符号将 al 扩展到 ax。 测试斧头,斧头;检查加数的符号。 js阴性 积极的: ;加数是正数。 添加 bx,ax ;添加。 adc dx,0 ;携带。 jmp next_number 消极的: ;加数是负数。 否定斧头;斧头 = |斧头|。 子 bx,ax ;减去。 sbb dx,0 ;借。 下一个号码: 公司西;下一个号码。 循环添加循环 ;现在的结果是 dx:bx。 移动斧头,bx;现在的结果是 dx:ax。 ;其余代码仅用于打印。 推 bx ;推低字。 移动 bx,dx ;将上面的单词复制到 bx。 调用 print_word_in_hexadecimal 推 dx ;推上字。 mov 啊,2 移动dl,':' 诠释 21 小时;打印 ':' 流行dx;弹出大字。 弹出 bx ;弹出较低的单词。 调用 print_word_in_hexadecimal mov ah,4ch 整数 21 小时 ;输入: bx:要打印的单词。 ;输出: - print_word_in_hexadecimal: 推bx 推 cx 推dx 移动 cl,4 ;计算角色。 mov ch,4 ;每个单词 4 个半字节。 next_nibble: 角色 bx, cl ;向左旋转 4 位。 推 bx ;推旋转词。 和 bx,0fh mov dl,[bx+数字] mov 啊,2 ;打印字符。 整数 21 小时 弹出 bx ;流行旋转词。 十二月 jnz next_nibble 流行音乐 流行音乐 流行音乐 ret 结束开始

上述代码对 8 位值进行有符号整数加法(8 位值扩展为 16 位值)。寄存器用法已更改,以允许使用 cbw 以获得更清晰的代码。为简单起见,添加负数已转换为减法。数组的硬编码偏移量(mov si, 0002h,仅当数组位于偏移量 2 时才有效)已替换为 lea si,array

size_of_array dw 7 数组分贝 -3、10、-7、14、9、-5、-100

以及相应的代码改动:

lea si, size_of_array ;或者您可以将这两行替换为: mov cx, [si] ; 1. mov cx,size_of_array(TASM/MASM 语法)。 lea si,数组

以及如何检查一个数字是负数还是正数?好吧,你检查最高位。例如,在我的代码中(test 执行逻辑与但不保存结果,它只更新标志):

测试斧头,斧头;对 ax,ax 进行逻辑与,但不保存结果。 js 否定;如果数字为负,则跳转。 积极的: ;这个数字是正数。 jmp my_label 消极的: ;这个数字是负数。 我的标签:

【讨论】:

  • 为什么要减少 dx?我运行您的代码,但结果是 0000 FFB8 H (DX:AX)!添加 07 时,AX 变为 0000 H。
  • @ammarx 对不起,我的错误。请参阅上面经过编辑和测试的代码。
  • 非常感谢@nrz 抽出宝贵时间。但是我们不应该在添加数字时检查是否有溢出。例如,当我们添加 0007H 时,AX 和 DX 变为 0000H。这里没有溢出,但我们不应该检查吗?
  • @ammarx 我不完全理解“当我们添加 0007H 时,AX 和 DX 变为 0000H”的意思。在 x86 汇编中,add 指令在有符号数太小(两个负符号数相加)或太大(正符号数相加)时设置溢出标志 (OF)。此外,对于正符号数,处理进位(使用adc)在这里就足够了,因为数字存储在dx:bx 中,而不是仅在bx 中。
  • 我的意思是 DX:AX = 0000 0000H 将 0007 添加到 DX:AX 后(当 CX=5 时)。你的意思是adcsbb保证不会溢出吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-18
相关资源
最近更新 更多