News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Negating a QWORD

Started by jj2007, February 04, 2012, 02:16:42 PM

Previous topic - Next topic

jj2007

Hi all,
I was looking for a simple trick to negate a quadword, and this seems to work, according to Olly:
include \masm32\include\masm32rt.inc

.data
qw1 QWORD 12345678901234h
qw2 QWORD -12345678901234h

.code
start:
mov edx, offset qw1
movlps xmm0, [edx]
movlps xmm1, [edx+8]
mov eax, [edx]
int 3 ; for Olly
neg eax ; not yields something else
mov ecx, [edx+4]
not ecx ; neg yields something else
paddq xmm0, xmm1 ; result is null, ok
inkey "ok2
exit

end start


Question: Does it work "by accident", or is there some theoretical reason why neg lodword, not hidword works??

qWord

commonly you negate a two's complement by:
A = (NOT A) + 1 ; this what NEG does

EDIT: negating the low and high DWORD can't work correctly, because you lost a possible carry between the low and the high DWORD ((NOT A)+1)
FPU in a trice: SmplMath
It's that simple!

dedndave

        not     eax
        not     edx
        add     eax,1
        adc     edx,0

;you want to test for 80000000_00000000h, because it cannot be negated without overflowing a qword
;it will be the same value before and after the conversion and the carry flag will be clear
;0 will also be the same before and after, but carry will be set

dedndave

you might do something like this...
        mov     ecx,eax
        push    edx
        not     eax
        not     edx
        add     eax,1
        adc     edx,0
        cmp     eax,ecx
        pop     ecx
        jnz     @F

        cmp     edx,ecx
        jnz     @F

        or      edx,edx
        js      overflow

@@:

qWord

dedndave,
a possible overflow doesn't matter - the code from your first post is correct.
FPU in a trice: SmplMath
It's that simple!

dedndave

a possible overflow doesn't matter ???
that depends on the situation   :P
the overflow flag will not be valid

if you do want to capture overflow, this code is probably a little better...
        not     eax
        not     edx
        add     eax,1
        jnz     no_overflow

        adc     edx,0
        jns     continue

        shl     edx,1
        jz      overflow

        rcr     edx,1
        jmp short continue

no_overflow:
        adc     edx,0

continue:

dedndave

my mistake   :U
the overflow flag is valid
        not     eax
        not     edx
        add     eax,1
        adc     edx,0
        jo      overflow

jj2007

Quote from: qWord on February 04, 2012, 02:28:34 PM
commonly you negate a two's complement by:
A = (NOT A) + 1 ; this what NEG does

I don't want to negate you, qWord, on the contrary, this might actually explain why my example worked...
I have tried to treat it empirically, by comparing the values obtained with the neg loDword, not hiDword sequence, and it seems to work for a wide range, see attached executable. Here is the source - sorry it looks a bit basic :red

include \masm32\MasmBasic\MasmBasic.inc   ; download
.data
Mul15   real10 1.01
qwSeed   QWORD -100000000
qwPos   QWORD ?
qwNeg   QWORD ?

   Init
   mov esi, offset qwPos
   mov ebx, 2539
   fld Mul15
   fild qword ptr [esi-8]
   .Repeat
      fld st
      fistp qwPos
      mov eax, [esi]
      neg eax
      mov [esi+8], eax
      mov eax, [esi+4]
      not eax
      mov [esi+8+4], eax
      Let edi="-"+Str$(qwNeg)
      mov ecx, Str$(qwPos)
      .if StringsDiffer(edi, ecx)
         deb 1, "diff", $edi, $ecx
      .endif
      PrintLine Str$(ebx), Str$("\t%i  \t", qwPos), Str$(qwNeg)
      fmul st, st(1)
      dec ebx
   .Until Zero?
   Inkey
   Exit
end start

dedndave

see what happens if you negate qword's where the initial value of the low dword is 0   :P
that is a very small percentage of all possible qword values but, without the carry bit, it should fail

dedndave

NEG instruction:
If the operand is zero, its sign does not change, although this clears the carry flag
Negating any other value sets the carry flag

that may be handy   :P
        mov     eax,[esi]
        mov     edx,[esi+4]
        neg     eax
        jc      @F

        dec     edx

@@:     not     edx
        mov     [esi+8],eax
        mov     [esi+12],edx


the only problem i see there is that NOT does not set the overflow flag for you
however, the carry flag may be used to indicate no overflow (no overflow > CF=1)
the DEC and NOT instructions do not affect the carry flag

dedndave

even better:
        mov     eax,[esi]
        mov     edx,[esi+4]
        neg     eax
        adc     edx,-1
        not     edx
        mov     [esi+8],eax
        mov     [esi+12],edx


and the overflow flag is valid   :P

jj2007

Dave,
carry is always set except for lodword=0. So
fistp qwNeg
neg dword ptr qwNeg
not dword ptr qwNeg[4]
is sufficient except that we need a test for zero. Even the 80000000h case works, by the way.

dedndave

8000000000000000h can't work
that is -9223372036854775808
if you negate that, it becomes +9223372036854775808
the range for signed qwords is -9223372036854775808 to +9223372036854775807

dedndave

here we go...
        mov     eax,dword ptr qwNeg+4
        neg dword ptr qwNeg
        not     eax
        sbb     eax,-1
        mov dword ptr qwNeg+4,eax
        jo      overflow


that seems to work   :P

qWord

nice one, but doesn't set the OF:
pxor xmm0,xmm0
movq xmm1,q
psubq xmm0,xmm1
movq q,xmm0
FPU in a trice: SmplMath
It's that simple!