平均字节数

问题描述:

我正在计算 3 分的平均值:

I'm computing the average of 3 marks:

g0  dw  70
g1  dw  100
g2  dw  65  

xor rax, rax
xor rcx, rcx

mov ax, [g0]
inc rcx

add ax, [g1]
inc rcx 

add ax, [g2]
inc rcx

xor rdx, rdx

idiv rcx

成绩不需要是单词,因为对于平均值来说字节就足够了,但是总和必须是一个单词以避免溢出(使用这个算法,就是这样).

The grades don't need to be words, because bytes would be enough as for the average, but the sum must be a word to avoid overflow (with this algorithm, that is).

如何将成绩转换为字节?使用 db 是不够的,因为那样我必须将 ax 更改为 al,但它最终会导致溢出.我不能指示 mov/add 只从 [g*] 获取一个字节,因为这会导致操作数大小不匹配.

How can I convert the grades to bytes? Using db isn't enough, because then I would have to change ax to al, but it would cause an overflow at the end. I cannot instruct the mov/add to only take a byte from [g*], as it would cause a mismatch in the operand sizes.

我正在使用 yasm.

I'm using yasm.

如果您使用另一个寄存器进行添加,您可以将变量更改为字节.所以以下是可能的:

You can change the variables to bytes if you use another register for the adding. So the following is possible:

g0  db  70
g1  db  100
g2  db  65  

使用MOVZX 指令并指明内存参考大小BYTE:

xor ecx, ecx              ; clear counter register and break dependencies

movzx eax, BYTE [g0]      ; movzx loads g0 and fills the upper bytes with zeroes
inc ecx

movzx edx, BYTE [g1]      ; move byte from g1 to dl and zero-extend
add eax, edx              ; add the widened integers
inc ecx 

movzx edx, BYTE [g2]      ; the upper half of RDX is zeroed automatically by this instruction, but 32-bit is fine.
add eax, edx
inc ecx

xor edx, edx
div ecx                   ; unsigned division of EAX / 3
                          ; quotient in EAX, remainder in EDX
;mov [average], al        ; or do whatever you want with it.

也不需要使用 64 位操作数大小.32 位是标准"对于大多数指令,x86-64 的操作数大小.

There's also no need to use 64-bit operand size. 32-bit is the "standard" operand-size for x86-64 for most instructions.

当然,您可以将 eaxedx 寄存器引用分别更改为 raxrdx,因为这些值已经零扩展到整个寄存器宽度.如果您要添加超过 2^32/100 个成绩,您可以使用它来避免溢出.

Of course, you can change the eax and edx register references to rax and rdx, respectively, because the values have been zero-extended to the full register width. If you had more than 2^32 / 100 grades to add, you could use that to avoid overflow.

如果你重复这个固定次数,mov ecx, count 而不是使用那么多的 inc 指令.inc 如果这是在循环体中并且您正在增加一个指向成绩数组的指针,那么 inc 会有意义,但是完全展开的部分好处是不必 inc任何可以计算交互的东西.

If you're repeating this a fixed number of times, mov ecx, count instead of using that many inc instructions. inc would make sense if this was in a loop body and you were incrementing a pointer to an array of grades, but part of the benefit of fully unrolling is not having to inc anything to count interations.