Average of marks with bytes

88 Views Asked by At

I'm computing the average of 3 marks:

g0  dw  70
g1  dw  100
g2  dw  65  

with

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).

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.

I'm using yasm.

1

There are 1 best solutions below

7
On

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  

Use the MOVZX instruction and indicate the memory reference size 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.

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

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.

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.