Hi Lenin,
The last bit (the most significant bit) in a floating point number determines the number's sign (bit 31 for single-precision and bit 63 for double-precision). It is set if the number is negative and clear if the number is positive. to get absolute value of a given operand we need to perfrom a logocal AND on the number to clear its most significant bit.

something like:

mov eax, 0x7FFFFFFF
movd xmm2, eax
pand xmm1, xmm2


pand operates on MMX registers and on XMM1 and XMM2 registers (no other XMM registers are supported). the above assumes that the number to AND is held inside the xmm1 register.


Hi roticv,
Where? :| If it's helpful to anyone then you're free to use it wherever you wish :) This is a 'community' after all ;)
Posted on 2005-12-06 15:05:25 by ti_mo_n
Hey, there's no need to clear the bit in the xmm0 register, since it's already stored in ecx, so is the sign bit the same in 32bit regiters (bit 31)?

I tried doing:
    cvttss2si ecx, xmm1
    and      ecx, 7FFFFFFEh


But got -1.2146493648 instead of -1.99
Posted on 2005-12-06 16:18:18 by Lenin
well yes - if you have a FP-value in a GP register, so you can simply AND it.

as for your problem: you're trying to AND an integer. integers are stored in 2's-complement arithmetic. use a "neg eax" instruction to make a negative value positive and a positive value negative. you can first check the value's most significant bit to see if it's negative

or eax, eax
jns notneg
neg eax
notneg:

no need for SSE here, but you can avoid using branches if you AND it while it's still FP inside a XMM reg ;)

the above changes a negative value to positive and does nothing with a positive one. ask if you don't know how it works ;)
Posted on 2005-12-06 16:30:33 by ti_mo_n
Thanks :)
Posted on 2005-12-06 16:53:20 by Lenin
I spent almost an hour thinking on how to solve that problem (1.900000) without having to convert the number into a string, but just then I realised "hey, I'm already converting the number into a string :P", then it got a lot easyer... I came up with this:

FloatToAscii proc float:DWORD, lpOut:DWORD
.data
    format  db "%d.%d",0
    million REAL4 1000000.0
.code
    movss    xmm0, float  ;xmm0 = float
    cvttss2si eax, float    ;eax = integral part of 'float' stored as integer
    cvtsi2ss  xmm1, eax    ;xmm1 = integral part of float stored as 'float'
    subss    xmm0, xmm1    ;xmm1 = fractional part of 'float'   
    mulss    xmm0, million
    cvttss2si ecx, xmm0
    or        ecx, ecx
    jns      @F
    neg      ecx
@@: invoke    wsprintf, lpOut, addr format, eax, ecx

    add      eax, offset buffer - 1
@@: cmp      byte ptr , "." ; to avoid numbers like 1.
    jz        @F
    cmp      byte ptr , "0"
    jnz      @F
    mov      byte ptr , 0
    dec eax
    jmp @B
@@:

    mov      eax, lpOut
    ret
FloatToAscii endp


Most results are pretty sactisfatory (sp?) but with numbers like 1.01 I get some weird results... 1.01 returns me 1.9999
Posted on 2005-12-06 20:25:39 by Lenin
wsprintf returns the number of copied characters NOT including the terminating NULL, so try

add       eax, offset buffer


instead of

add       eax, offset buffer - 1
Posted on 2005-12-06 20:34:16 by ti_mo_n
Now that part of the function seems to not be working anymore...

I enter 1.99 and get 1.990000
-1.1 - 1.100000
1.0123 - 1.12300
Posted on 2005-12-06 20:42:58 by Lenin
    add       eax, offset buffer - 1
@@: cmp      byte ptr , "."
    jz        @F
    cmp      byte ptr , "0"
    jnz      label2
    mov      byte ptr , 0
    dec eax
    jmp @B
@@:
    mov byte ptr , 0
label2:

It's 3:55 now, so my brain is in shutdown for 2 hours already :P if this diesn't work, then I can think of something after getting  some sleep :)
Posted on 2005-12-06 21:02:52 by ti_mo_n
Hey Ti_mo_n,

It's here. http://win.asmcommunity.net/x86book/ It is better you add it for the good of the community.  ;)
Posted on 2005-12-06 21:57:42 by roticv
It works :) I beleive the function is complete now so I'll just leave it here for future reference:

ftoa proc float:DWORD, lpOut:DWORD
.data
    format  db "%d.%d",0
    million REAL4 1000000.0
.code
    movss    xmm0, float  ;xmm0 = float
    cvttss2si eax, float    ;eax = integral part of 'float' stored as integer
    cvtsi2ss  xmm1, eax    ;xmm1 = integral part of float stored as 'float'
    subss    xmm0, xmm1    ;xmm0 = fractional part of 'float'
    mulss    xmm0, million
    cvttss2si ecx, xmm0
    or        ecx, ecx
    jns      @F
    neg      ecx
@@: invoke    wsprintf, lpOut, addr format, eax, ecx

    add      eax, lpOut
    dec      eax
@@: cmp      byte ptr , "."
    jz        @F
    cmp      byte ptr , "0"
    jnz      label2
    mov      byte ptr , 0
    dec eax
    jmp @B
@@:
    mov byte ptr , 0
label2:

    mov      eax, lpOut
    ret
ftoa endp


Thanks ti_mo_n :)
Posted on 2005-12-07 09:32:09 by Lenin
Hi Lenin,
No problem ;)

Hi roticv,
I'll learn the wikiwiki and then add the MMX, SSE, SSE2 stuff :)

/edit
Done :) I've added few things to the 'glossary'.
Posted on 2005-12-07 09:41:17 by ti_mo_n
That's very nice of you.  ;)
Posted on 2005-12-07 12:51:16 by roticv
thanx roticv ;)

Lenin,

Oh  :P Still I don't know how to link to msvcrt.dl ... I searched trough masm32's include and lib folders but couldn't find anything....

You can use LoadLibrary, GetProcAddress, FreeLibrary


libhandle dd ?
sprintf_ dd ?
buffer db 64 dup (?)

fmt db "%f",0
funcname db "sprintf", 0
libname1 db "msvcrt70.dll", 0
libname2 db "msvcrt.dll", 0

call LoadLibrary, offset libname1
or eax, eax
jnz continue
call LoadLibrary, offset libname2
or eax, eax
jz error
continue:
mov , eax
call GetProcAddress, eax, offset funcname
or eax, eax
jnz noerror
call FreeLibrary,
jmp error
noerror:


(...)

call , offset buffer, offset fmt, 
add esp, 3 * 4  ; you have to balance the stack because sprintf uses _cdecl


don't forget to call "freelibrary" when you no longer need it (usually during WM_CLOSE).

this code tries to link to msvcrt70 first and then to msvcrt. it's because not every windows has msvcrt70.
Posted on 2005-12-11 16:59:44 by ti_mo_n