Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Simple Routine to get the Average of 5 numbers...? 2

Status
Not open for further replies.

CubeE101

Programmer
Nov 19, 2002
1,492
0
0
US
How can you use ASM to get the average of 5 integer numbers with values up to a BYTE in size... (0-255)

I know you can use Right Shift to Average 2,4,8,... numbers

I never realy grasped how DIV works in ASM, if someone could explain that i would also be greatful... (like what registers to put the Numerator and denominator, and where the results are returned...

Is there a faster way to Average odd sets of numbers than using divide?

sorry for my ignorence... It's been about 3 or 4 years since I coded in ASM and that didn't last too long...

ThnX N AdvnC

Have Fun, Be Young... Code BASIC
-Josh Stribling
cubee101.gif

 
If I understand you correctly, assume that you have 5 integer number
Code:
;*** 16 bit
 xor ax, ax
 xor cx, cx
 xor dx, dx

;*** 32 bit
 xor eax, eax
 xor ecx, ecx
 xor edx, edx

 mov al, val1
 add al, val2
 add al, val3
 add al, val4
 add al, val5
 mov cx, 2
 div cx
The result will be in AX and the remainder will be in DX.
For 32 bit it will be EAX and EDX

Hope that answer your question
Regards
 
OK... So I have 5 numbers... 3,4,5,6,7

--------------
xor ax
xor bx
xor cx

mov al,3
add al,4
add al,5
add al,6
add al,7
mov cx,5
div cx
--------------

AX = 5
DX = 0

and for 4,4,4,4,6
AX = 4
DX = 2

right?

then for multiplying 320 * 200...

mov ax, 320
mov cx, 200
mul cx

if answer is less than a word:
Answer = AX
if answer is greater than a word:
Answer = DX:AX

right?

- - - - - - - -
One last thing...
I noticed you placed the sum of all the values in AL...
can you place another 5 in AH then use 1 divide command to preform 2 operations at once...? and use a left shift with EAX to end up with 4 answers...



xor eax
xor ecx
xor edx

mov ah, val1a
add ah, val2a
add ah, val3a
add ah, val4a
add ah, val5a

mov al, val1b
add al, val2b
add al, val3b
add al, val4b
add al, val5b

lsh eax, FFFF

mov ah, val1c
add ah, val2c
add ah, val3c
add ah, val4c
add ah, val5c

mov al, val1d
add al, val2d
add al, val3d
add al, val4d
add al, val5d

mov ecx, 5
div ecx

*** then to add the answers to the stack...
xor bx
mov bl,al
push bx
mov bl,ah
push bx
rsh eax, FFFF
mov bl,al
push bx
mov bl,ah
push bx

-------well, actually...
if all 5 values = 255 then the sum would be: 1275 dec or 4FB hex...
so AH = 04 and AL = FB ... right...

this is where I usually get confused...

btw... thnx for the help

Have Fun, Be Young... Code BASIC
-Josh Stribling
cubee101.gif

 
First of all, I never saw some of the instruction, like:
xor ax
lsh
rsh
Is that really exist, what Asm are you using ?
Or did you mean this:
xor ax, ax
shl
shr

Ok, this is my answer. This is base on my experienced only. So someone maybe disagree with me ;-)

1. Division, right

2. Multiply, right

3. Yes, you can do it at once, but did you ever try your code ? Or you only think it in your head :)
Look at this:

mov ah, val1a
add ah, val2a
...

mov al, val1b
add al, val2b
...

lsh eax, FFFF

Change the shift value into 16, so it looks like this:

shl eax, 16d

Do the same for
rsh eax, FFFF
change to shr eax, 16d

Because AX is only 1 Word = 2 Bytes = 16 Bits. So you only need to shift by 16 (decimal) to fill the HI-WORD. If you shift by 0FFFFh, it means you are shifting the bits by 65536 times. Where the value will go ? (-:
I tried to shift that much and it gave me error / can not compile

> if all 5 values = 255 then the sum would be: 1275 dec or 4FB hex...
> so AH = 04 and AL = FB ... right...

According to your example, all value = 255 (0FFh). If you put it into register:

EAX = FFFFFFFFh

divide by 5
EAX = 33333333h

sum each byte
33h + 33h + 33h + 33h = CCh = 204 dec

That's the real result.
I don't know which value do you sum. Now I'm getting confuse with your calculation. Am I missing something here ?
 
You can put 5 values in al, and 5 in ah, and divide the whole thing by 5 if you want, but it isn't going to give you two neat answers that you can separate out by shifting. The reason is that ah is just counting in 256's. So when you've put your five values there, they contribute 256*(a+b+c+d+e) to the value in ax. If you divide that by 5, you now have 256/5*(a+b+c+d+e) in ax, and a remainder in dx. The numbers we've summed will creep down into al when you divide by 5...
Of course you also have the other 5 numbers from al summed and divided, so actually ax now contains that divided by 5 too.

So to separate the two numbers after division you'd now need to take the upper 256/5, not the upper 256. And since 256/5 isn't even an integer, let alone a power of 2, you can't do this by shifting...

Your idea of getting 2 averages on one division will only work reasonably if you start the 2nd set of numbers at a power of 2 that is also divisible by 5.... And if you think about it, there can be no numbers that fulfil the requirements.



 
aircon,
>>Or did you mean this:
>> xor ax, ax
>> shl
>> shr

thanks, Yes thats what I meant...
like I said it has been a while since I used ASM...
plus it was about 2 am when I wrote it...

and for this part...
>>According to your example, all value = 255 (0FFh). If you put it into register:
>>
>>EAX = FFFFFFFFh


actually no...

FFh + FFh + FFh + FFh + FFh = 4FBh (1275 dec)

EAX = 4FBh

then shift left 2 bytes which would be 16 bits... 10h (I don't know what I was thinking up there, I guess I was thinking 1 byte and crossing that with FF being the max byte value... I really don't know what I was thinking...)

SHL EAX, 10h

EAX = 4FB00h

and when I said 4 numbers... I guess I was thinking about the end Result being FFFFFFFFh But.. that would mean that EAX would have to be able to hold 4FFFFFFFBh, which, I don't think is going to happen ;-) unless you like to have 4's floating around in your pc's memory So lets try this with 3 sets of numbers...

then add the 5 FFh's again...

4FB00h + 4FBh = 4FFFBh

then shift and add again

4FFFB00h + 4FBh = 4FFFFFBh (4FF:FFFB)

so now EAX = 4FFFFFBh

divide this by 5 and you get FFFFFF, so each of the 3 answers is FF (255)

(255 + 255 + 255 + 255 + 255) / 5 = 255

now let me try this again... (a little more awake this time)

Code:
xor eax, eax  ;*** clear the registers
xor ecx, ecx
xor edx, edx
mov al,  FFh  ;*** add the first set of 5 numbers
add al,  FFh
add al,  FFh
add al,  FFh
add al,  FFh
shl eax, 10h  ;*** move the data over 1 byte
mov al,  FFh  ;*** add the second set
add al,  FFh
add al,  FFh
add al,  FFh
add al,  FFh
shl eax, 10h  ;*** move the data over 1 byte
mov al,  FFh  ;*** add the third set
add al,  FFh
add al,  FFh
add al,  FFh
add al,  FFh
mov cl,  5h   ;*** set the divisor (or whatever you call it)
div ecx
push al       ;*** push the third average to the stack
shr eax, 10h
push al       ;*** push the second average to the stack
shr eax, 10h
push al       ;*** push the first average to the stack
retf 06       ;*** return the 3 values


Have Fun, Be Young... Code BASIC
-Josh Stribling
cubee101.gif

 
Cube,

<< it was about 2 am when I wrote it >>
I know it happened often :) It happened to me either. When you said &quot;if all 5 values = 255&quot; I thought &quot;If all the bytes value = 255 or EAX = FFFFFFFFh&quot; ;-)

Ok, back to your code.
First part of your code is
mov al, FFh ;*** add the first set of 5 numbers
add al, FFh
By using AL, it means that you are limiting the register to use 8 bits (1 byte) only. The AL register will not expanded to AH if the summed value more than FFh
AL = FFh + FFh
AL = FEh ( EAX = 000000FEh )

Another one is:
shl eax, 10h ;*** move the data over 1 byte
That instruction will shift eax by 2 Bytes not 1 Byte. I think I explained this on my earlier message.
your example:
EAX = 4FBh -> 00 00 04 FB
SHL EAX, 10h
EAX = 4FB00h -> 00 04 FB 00

That is incorrect. This is the correct one
EAX = 4FBh -> 00 00 04 FB
SHL EAX, 10h
EAX = 4FB0000h -> 04 FB 00 00
Are you still awake ?? :-D

I changed some of your code and for the rest you better try it yourself.
Code:
   mov eax, 0FFh
   add eax, 0FFh
   add eax, 0FFh
   add eax, 0FFh
   add eax, 0FFh
   shl eax, 8

   xor al, al
   add eax, 0FFh
   add eax, 0FFh
   add eax, 0FFh
   add eax, 0FFh
   add eax, 0FFh
   shl eax, 8

   xor al, al
   add eax, 0FFh
   add eax, 0FFh
   add eax, 0FFh
   add eax, 0FFh
   add eax, 0FFh

   mov ecx, 5
   xor edx, edx
   div ecx

That's it I guess
Regards
 
Have you actually tried this to see if it works? I really don't think you should be able to get 3 averages out of the one division. It might work for special cases, so try some general randomish looking numbers.
A few extra comments:
(1) Unfortunately you cannot push al. Push only handles words and multiples thereof
(2) You've got 2 lots of shr 010h. That makes 32 bits, so after the 2nd shift there won't be a number left....
(3) retf 06 doesn't return any values, it simply notes that you had previously used 6 bytes of stack space, and subtracts them from the stack pointer.
(4)After shl'ing eax I don't think you need to clear al. It should already be zero.
 
lol... late night syndrome attacks again...

I was thinking a byte was 16 bits (for some strange reason) when it is really 8 &quot;1111 1111&quot;

either that or I had a pre-senior moment and thought &quot;F&quot; in &quot;FF&quot; was a byte (8 bits), making &quot;FF&quot; = 16 bits, but still trying to call &quot;FF&quot; a byte (containing 16 bits)

or... I was still thinking about the first way I did it, using ah and al which would be 16bits

so it really needs to be SHL/SHR xx, 8

ok then for the last part, dealing with the pushes...

you can still do this, right...
xor bx, bx ;*** clear bx
mov bl, al ;*** mov answer 3 to bx
push bx ;*** then push it
shr eax, 8 ;*** repeat...
mov bl, al
push bx
shr eax, 8
mov bl, al
push bx

Have Fun, Be Young... Code BASIC
-Josh Stribling
cubee101.gif

 

lionel:
To who you replying it ? but I believe that no.4 is for me :)

Yes, I know the al will be zero after shift. If you look at the earlier message, you should know that I know, shift always zero out the bit.
<<
EAX = 4FBh -> 00 00 04 FB
SHL EAX, 10h
EAX = 4FB0000h -> 04 FB 00 00
>>
The reason I XOR'ing the al, because I just found out recently that the things I believed from the first time I used Asm, is actually not true on some Asm compiler (different behaviour). In this case eventhough I believe we don't need xor after shift. But for safety reason I put it there, that's all.

Cube:
For the last part, yes you can do that.
This is the second time I ask this. Did you ever try the code, the whole code ? What are you trying to achieve with that code ? Well, actually is not my bussiness. Just curious ;-)
 
Aircon, you are right to be asking. I'm not sure that this bit of code will ever do what Cube would like it to (achieve 2 lots of averaging in a single divide).

Going back to the original thread, I don't know of a quick way to divide without using divide, but of course multiplication is a different situation. There are possibilities like
lea eax, [eax*4, eax]
which loads eax*4+eax into eax, i.e. multiplies eax by 5 in a single short instruction.

About the shifts, theoretically the assembler you use shouldn't affect how your code runs, because they should all write the same thing. But I'd hate to stick to theory, goodness only knows what really happens in the world.
 
I agree lionel, theoretically any asm we use shouldn't affect how the code runs. Well it's not theoretically I believe. It has to be that way. Actually all asm compiler should compiled the code exactly what we write, nothing more nothing less.

This is also one of the reason people use asm. We take full control for the code and how the machine should run. And if some asm compiler (Low Level Asm compiler) can add something into the code (except for alignment) or act differently, It really turns me upside down. But... who knows

And to Cube, I suggest next time you give more detail and give some explanation about what you want, not just posting the code, not knowing the error, etc. And I think you should do that not just in this forum but any forum. Cause if people knows exactly what you want to achieve, maybe they're not just corrected your code, probably they might come with a better code or a much smarter solution that you never think of. You can gain more knowledge, but it's all up to you
 
ok...

No I have not tried the code...

It will most likely be for a blending routine in QuickBasic.

to get the average of 5 pixels in screen mode 13...
Code:
+-+-+-+
| |1| |
+-+-+-+
|2|3|4|
+-+-+-+
| |5| |
+-+-+-+

the max value of any given color is 255...

I will most likely use TASM / BASM / A86 / or DEBUG to compile/assemble the code...

the reason I list debug is because you can dump the hex codes, then use the hex codes in QB via CALL ABSOLUTE w/o using a library...

I know that as far as multiplication goes... it is faster to..

mov bx, ax
shl ax, 6
shl bx, 8
add ax, bx

than to...

mov cx, 320
mul ax, cx

or, if you want to multiply by 5

mov bx, ax
shl ax, 2
add ax, bx

A visual method of this is decimal 1 is 0001 in binary
decimal 320 is 0001 0100 0000 in binary
since there are two 1's in 320 you can not use a simple shift.
so you split it into:
64 : 0100 0000 (or Shl xx, 6)
-and-
256 : 0001 0000 0000 (or Shl, xx, 8)

the same applies for 5 (0101)
split this into 4(0100) and 1(0001)
then add together

I was just wondering if there was a similar method to use for dividing... (I did not think there was... But I figured it would be worth a shot...)

now for dividing it is a bit more complicated to seperate the 5 into 4 and 1 with out dividing by 5 in the first place to see what the 1 would be... then figure the 4 from the 1... which would defeat the whole purpose...

I have been to busy working on a program in VB and VC++ to try this with asm yet... (Business B4 Pleasure) for one thing, I have not yet installed my assemblers back on this (new)PC, since I got it... and the QB/ASM thing is just for fun... just so I don't forget everything that I used to use... (Like I almost did..)

Thnx for the help though, There were quite a few things I did not realize I forgot over the years... (spoiled by VB)

I will give you each a star for helping me and spending so much time replying...

Thanks Again,
-Josh

Have Fun, Be Young... Code BASIC
-Josh Stribling
cubee101.gif

 
You right. Using shift is faster than the multiply.
I will leave the calculation to you or lionel or anyone, cause I'm not good in math :-D

Good luck and thanks for the star :)
Regards
 
Ah, so you're doing it for graphic purposes!
Since you really only need up to 5*256 it might be worth creating a look-up table, particularly if your images are big.
The other thing to think about with graphics is that there are lots of tasks that look at first sight as though they need division, but actually can be done entirely on addition. The obvious one is drawing a straight line at between any two points on the screen (Bressenham...), but less obviously, making that line antialiassed doesn't need much extra work at all (Wu), and scaling an image to any smaller size is much the same. Any good graphics text book (NOT the sort that simply describes someone's graphics library and its syntax) will be helpful.

A good algorithm will save you far more time than hand-coding a less appropriate method.

If you're doing this for pictures of a known sort, you might be able to save yourself a lot of time. For instance, if you work with cartoon-type pictures with big blocks of single colours, you will spend most of your time adding a number to itself five times and dividing the result by 5...

Have fun!

 
I am playing around with the idea of speeding up my Ghost Cube program that I made in QB a few years ago... using a little in-line ASM... I had a few routines worked out, BUT... I bought a new PC, let my friend borrow my old one and, well, I guess he didn't exactly know what he was deleting, If you know what I mean :-(

Anyways... Thankfully I Uploaded my program to my web site B4 i let him borrow the pc...

check it out at ...

under projects or qbasic

it's pretty fast for pure QB ;-)

and while you're there, if you like tetris (at all) check out my ludatris game... the first level is a breeze, the *fun* starts at level 2 ;-)

I used a look up table in my QB program... but I was attempting to move all of the time consuming tasks into ASM...

this is how I setup the Table
FOR X = 0 TO 1275
Div5Map(X) = X / 5
NEXT

How can you use that with asm?

I suppose you could pass the address of Div5Map to ASM... but how do you set up the pointers in ASM to use the address and return the answer...

is it some where in DS ?

OK...

I finally found some good documentation...
Now this stuff is starting to come back to me...
check out Chapter 1 - 13
The stuff I was looking for was in Ch 2

I still can't remember how to use qb arrays in asm...

Have Fun, Be Young... Code BASIC
-Josh Stribling
cubee101.gif

 
I think you need a QB expert for how to find your lookup table. I tend to be a C-and-Pascal person. In both of these you can put your look up table in heap memory and keep a pointer to it. The pointer can be loaded using lds or les, and then the offset to the answer is put in any register you want. Remember to save any vital registers that the compiler of your main programme expects to remain unchanged. For instance it is almost never safe to tinker with ds unless you restore it at the end of your code before returning to C/pascal/whatever.

There are things you need to think about. All of your answers are less than 256, so you can store them in a single byte if you want - but remember you'll have to have done the creation of the table using words since the thing you are dividing by 5 is greater than a byte. If you've got it down to a single byte, then you don't need to worry about indexing into the table. The number you are looking for can be used as the offset directly.
If you use a table in words, then you need to think about whether you are in 16 bit old fashioned stuff, or (more likely) in 32 bit. In 32 bit, words are BAD because they are not the native size the processor is expecting. Therefore any word instruction will have to be preceded by a size prefix, which will slow things down. You don't have to think about this: whatever is doing the assembling will handle it for you. But you will get better speed if you actually use 32 bit numbers, or 8 bit, but NOT 16. If you want to use 32 bit, then you can also (in protected mode 32 bit stuff) address directly without first shifting the number you want to look up (to multiply it by 4) because there is a scaled index system. You can write something like:
mov eax, es:[esi*4]
This does NOT work in 16 bit stuff though, so in the very unlikely event that you are using 16 bit code, you can use 16-bit numbers without penalty (but not 32 bit!), but you would have to shift the index one bit.
shl si, 1
mov ax, es:[si]
But of course the byte option has to be the nicest.

Another point, if you are actually drawing graphics as you calculate, you may find that drawing etc. takes such a huge proportion of the time that there is no saving to be made by streamlining a fairly straightforward bit of arithmetic.

Good luck!
 
is it possible to make a temp array in asm...

like in ES or DS or something...

like:
Code:
mov cx, 1
mov bx, 5
mov [ds], ??
back:
mov ax, cx
div bx
mov ds:[cx], ax
add cx, 1
cmp cx, 1025d
jle (or) jbe back

the above was intended to be a bit abstract...

If you get the idea, could you tell me if it would work or how to make it work...

I don't think you can say
mov ds:[cx] ,xx
but at least something to that extent...
what is it, ds:[di] or something...

N E Wayz thankz 4 ur help thus far...
H;-)PPY C:)DING [hammer]

Have Fun, Be Young... Code BASIC
-Josh Stribling
cubee101.gif

 
I think you can use cx that way.
I would build the look-up table in the high-level language, because it is less time-critical than the processing bit, and also because it saves you thinking about how to reserve memory for the job...
 
is it possible to make a temp array in asm...
Of course :)
i.e. :
MyArray db 10 dup (0)
- declare variable MyArray as array of byte and fill each byte with 0

First of all, I don't know what you are trying here so I only change the code to make it work or at least a valid code. But does it work as expected or how it is working, I really don't know.

mov cx, 1
mov bx, 5
; mov [ds], ?? -> cannot use segment for pointer
; -> only index or register
mov ax, ds
mov di, ax
mov word ptr [di], ??
mov di, cx

back:
mov ax, cx
div bx
mov word ptr [di], ax
add cx, 1
add di, 2
cmp cx, 1025d
jle (or) jbe back

Cheers
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top