汇编 IA-32:如何将 64 位有符号数除以奇数(存储在 2 个寄存器中)
Posted
技术标签:
【中文标题】汇编 IA-32:如何将 64 位有符号数除以奇数(存储在 2 个寄存器中)【英文标题】:Assembly IA-32: How to divide 64-bit signed number by odd number (stored in 2 registers) 【发布时间】:2019-03-25 05:24:30 【问题描述】:在 IA-32 架构上,我如何将 有符号 数除以 3(例如)存储在 2 个寄存器中的值 edx:eax( 64 位 值)。我想将整个值(64 位)除以 3,而不仅仅是 32 位,并将其存储在 2 个寄存器中。
我假设这只能使用 shifts 操作来完成,因为imul
仅适用于乘以 32 位数字。但只找到了除以2^n
数字的解决方案。
我怎样才能做到这一点?
【问题讨论】:
您想除以运行时变量数还是除以某个(但任何)常数? @harold 任意常数,可以除以1,2,3,4,5,6... 我修正了我的答案来处理正除数和签名股息。 Divide a number by 3 without using *, /, +, -, % operators 【参考方案1】:您可以通过连续除法将任何长度数除以 32 位数,将前一次除法的余数用作下一次除法的被除数的最高 32 位,类似于长手除法
请注意,我需要修复此代码以处理负除数,但它应该适用于正除数和有符号除数。
请注意,此代码向负无穷大取整:-10/3:商 = -4,余数 = +2。为了处理负除数,代码可以同时取除除数和除数,然后取反余数。
mov ecx,000000003h ;ecx = signed dvsr (must be positive)
mov edi,0fedcba98h ;edi:esi = signed dvnd
mov esi,076543210h
;; inputs
mov eax,edi ;eax = upper 32 bits dvnd
cdq ; sign-extend that into EDX:EAX
idiv ecx
test edx,edx ;br if sign rmdr == sign dvsr
jns short div0
dec eax ;dec quot
add edx,ecx ;rem += dvsr
div0: mov edi,eax ;edi = upper 32 bits quot
mov eax,esi ;eax = lower 32 bits dvnd
div ecx
mov esi,eax ;esi = lower 32 bits quot
; ;edx = remainder
【讨论】:
但这似乎不起作用,想象你正在做 -20306/3... 做同样的事情,但为了简化,我用 16 位(代表 64 位值)来做:10110000 10101110 ---> -20306 10110000 / 00000011 ---> -26 = 11100110 和 10101110 / 00000011 --> -27 = 11100101 所以结果值将是 11100110 11100101 和 1110010110061111 它的结果是 6跨度> 只有第一个分区是idiv,其余的都必须是udiv。 @DiogoSoares - 我错过了签名部分。我更新了处理正除数和签名股息的答案。 @rcgldr 实际上非常有用,谢谢。代码运行良好,但我不明白为什么这行有意义:add edx, ecx
紧跟在dec eax
之后。你能再赐教我一次吗
@DiogoSoares - 使用我回答中的示例,考虑情况 -10 / 3。X86 idiv 指令将返回商 = -3,余数 = -1,因为它将商四舍五入到零。但是,在这种情况下需要向负无穷大取整,因此 -10/3 的商为 -4,余数为 +2,为了得到这个结果,-3 的商递减为 -4,余数为 - 1 加上 3 得到 +2 的余数。以上是关于汇编 IA-32:如何将 64 位有符号数除以奇数(存储在 2 个寄存器中)的主要内容,如果未能解决你的问题,请参考以下文章