Hi all,

What is the fastest way to multiply four floats by 0.5 ? The floats are in a xmm register.
Posted on 2004-07-08 01:25:49 by Dr. Manhattan
Hello,

I have never worked with floats before, but I imagine the fastest way to multiply them by 0.5 is to divide them by 2.

But this is only a thought of mine.

Regards,
Claus
Posted on 2004-07-08 03:24:42 by ndn4u
This probably won't work for everything and is more than likely misguided but essentially you have to shift right by 1. Since floats are stored as powers of 2, you have only to subract 1 from the power in order to divide by 2.

For example with REAL8:

DATA SECTION

somefp DQ 210.244

CODE SECTION
sub D[somefp+4],00100000h ; divide REAL8 by 2


For REAL4 (MASM format this time):

.DATA

somefp REAL4 210.244

.CODE
sub DWORD PTR somefp,00800000h ; Divide REAL4 by 2
Posted on 2004-07-08 03:40:43 by donkey
He's referring to the Exponent.
FloatingPoint values have a special binary encoding where the top handful of bits are used to keep the Exponent (and Sign bit) while the rest of the bits contain the Mantissa (also known as the Significand).
The fastest way to divide any floatingpoint value by a multiple of 2 would be to modify the Exponent, he's absolutely right, but I get the feeling you were looking for an MMX solution...

For anyone who isn't awake to this stuff,

S EEEEEEEE MMMMMMMMMMMMMMMMMMMMMMM

That's how a 32bit float is encoded under the IEEE standard.

Have a nice day :)
Posted on 2004-07-08 05:48:05 by Homer
Evilhomer2k it is easy to do with SSE. You can copy the data to memory and subtract as Donkey has show below. Or if you have SSE2 you can do it in parallel. You have to have at least SSE2 to do that because you need to treat the data like integer data and SSE doesn't support that.



.data
align 16
sub_exponent dd 00800000h, 00800000h, 00800000h, 00800000h
.code
psubd xmm0,[sub_exponent]



This probably won't work for everything and is more than likely misguided but essentially you have to shift right by 1. Since floats are stored as powers of 2, you have only to subract 1 from the power in order to divide by 2.

For example with REAL8:

DATA SECTION

somefp DQ 210.244

CODE SECTION
sub D[somefp+4],00100000h ; divide REAL8 by 2


For REAL4 (MASM format this time):

.DATA

somefp REAL4 210.244

.CODE
sub DWORD PTR somefp,00800000h ; Divide REAL4 by 2
Posted on 2004-07-08 08:23:20 by mark_larson
Thanks. Too bad it doesn't work for everything, 0.0 for example.
Posted on 2004-07-08 13:37:14 by Dr. Manhattan
Well, you have only to make a special case for 0.0 :

DATA SECTION

somefp DQ 0.0

CODE SECTION
cmp D[somefp+4],0
je >
sub D[somefp+4],00100000h
:


MASM:

.DATA

somefp REAL8 0.0

.CODE
cmp DWORD PTR [somefp+4],0
je @F
sub DWORD PTR [somefp+4],00100000h
@@:


Then it seems to work in all cases.
Posted on 2004-07-08 14:00:02 by donkey

Well, you have only to make a special case for 0.0 :

DATA SECTION

somefp DQ 0.0

CODE SECTION
cmp D[somefp+4],0
je >
sub D[somefp+4],00100000h
:


MASM:

.DATA

somefp REAL8 0.0

.CODE
cmp DWORD PTR [somefp+4],0
je @F
sub DWORD PTR [somefp+4],00100000h
@@:


Then it seems to work in all cases.


Using SSE2 that would be:



.data
align 16
four_0s real4 0.0,0.0,0.0,0.0
sub_value dd 00800000h,00800000h,00800000h,00800000h
.code
;xmm0 holds the 4 real4 values you want to multiply by 0.5
movaps xmm5,[four_0s] ;value to look for.
movaps xmm6,[sub_value] ;value to subtract from the exponentf
movaps xmm1,xmm0 ;get backup copy of data
cmpps xmm1,xmm5,0 ;xmm1 now has an FFFFFFFF in each dword location in XMM1 with a 0.0 all other locations have 0.
pandn xmm1,xmm6 ;NOTs XMM1, and then ANDs it with XMM6. So it will only subtract from the exponent if the value is non-zero
psubd xmm0,xmm1 ;only subtract the sub_value from those fields that aren't 0.0s'.
Posted on 2004-07-08 14:28:33 by mark_larson