Reputation: 19
In my program I'm trying to calculate the average of two integers, and then round the number. For example if the average is -22.5, it will round to -23. validInputs is the number of valid inputs gathered from the user and will always be a positive integer, while validSum will always be a negative integer as it only adds negative integers. However when comparing the remainder, I am not getting the correctly rounded result, and was wondering why.
Edit: I made the suggested change to -5 but am still experiencing the same error. I believe my error must be a logical problem.
mov eax, validSum
cdq
mov ebx, validInputs
idiv ebx
mov validAverage, eax
mov intRemainder, edx
cmp edx, -5 ; compare the remainder to -5
jg display ; if greater than -5 we know not to round/decrement
dec validAverage
Upvotes: 1
Views: 3402
Reputation: 14409
If you just divide by 2 the solution is easy. IDIV
gives you in this case only three possible remainders: {-1,0.1} which means:
-1: the sum was negative, the number behind the decimal point is -0.5, the average has to be subtracted by 1, i.e. avg = avg + (-1)
.
0: no remainder, the average is already correctly rounded, i.e. avg = avg + 0
.
1: the sum was positiv, the remainder caused 0.5 and has to be added by 1, i.e. avg = avg +1
.
As you can see, there's no need for a long-winded comparison, you can just add the remainder EDX
to EAX
:
; Only valid for EBX=2
mov eax, validSum
cdq ; EAX -> EDX:EAX
mov ebx, validInputs
idiv ebx ; EDX:EAX / EBX -> EAX remainder EDX
mov validAverage, eax ; Save result
add validAverage, edx ; Add -1 or 0 or 1
jmp display ; End of Rounding
Besides that, the remainder has nothing to do with a fractional part of a decimal number. It is simply wrong, to compare it directly with 5 or -5. You must first get the first fractional digit. In a long division you would "add" a 0 at the end and then divide by the divisor. The same here: Multiply by ten (= add 0 at the end) and divide by EBX
. Now you can divide the result by 5 to get the triple as above: {-1,0.1}
...
idiv ebx ; EDX:EAX/EBX
mov validAverage, eax ; Save result
mov eax, edx
add eax, eax ; A quick way to multiply by 10
lea eax, [eax + eax * 4] ; EAX * 10 = EAX * 2 + EAX * 8
cdq ; EAX -> EDX:EAX
idiv ebx ; EDX:EAX / EBX -> EAX remainder EDX
mov ebx, 5
cdq ; EAX -> EDX:EAX
idiv ebx
add validAverage, eax ; Add -1 or 0 or 1
jmp display ; End of Rounding
You can transform EAX*10/EBX/5
into EAX*2/EBX
:
mov eax, validSum
cdq ; EAX -> EDX:EAX
mov ebx, validInputs
idiv ebx ; EDX:EAX / EBX -> EAX remainder EDX
mov validAverage, eax ; Save result
imul eax, edx, 2 ; EAX = EDX * 2
cdq ; EAX -> EDX:EAX
idiv ebx ; EDX:EAX / EBX
add validAverage, eax ; Add -1 or 0 or 1
jmp display ; End of Rounding
Upvotes: 3