News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Adding two 64 bit long numbers in Masm 32

Started by maelirou, March 31, 2016, 09:13:27 AM

Previous topic - Next topic

maelirou

Hi guys.
I don`t know how to calculate two 64 bit long numbers,
"3A2C098FDE6273ED" with "26D371B41CA8B4F6" and that result "60FF7B43FB0B28E3" to show in MessageBox?
I`m using MASM for x86, btw.
Do i have to use the FPU registers and how? I would appreciate really a lot some code example!
Sorry for any mistakes. English is not my native language.


I only know how to calculate 32 bit long number with the FPU.

MyF_ proc
LOCAL P1_:QWORD
LOCAL P2_:QWORD
LOCAL Result_:QWORD
 
    mov dword ptr [_P1],576ED371h
    mov dword ptr [_P2],1AC54331h
    FLD _FP1   
    FLD _FP2   
    FADD ST(0), ST(1)
    fstp _Result   
    mov eax,dword ptr[_Result]                          ; eax = 723416A2

MyF_ endp

:t

raymond

You don't necessarily need to use the fpu for such an operation unless you have some other needs. Simply imagine you have to add 58+25 with paper and pencil.
  5 8
+2 5
____
  8 3

You would first add the lower part, keep the lower result, and carry over (when needed) the one for the addition of the higher part.

You use 32-bit registers for the lower and higher parts of 64-bit numbers.


.data
  num1    qword    3A2C098FDE6273EDh
  num2    qword    26D371B41CA8B4F6h
  result  qword    ?

.code
  mov   eax,dword ptr num1      ;lower 32-bit part of num1
  mov   edx,dword ptr num1[4]   ;higher 32-bit part of num1
  add   eax,dword ptr num2      ;add lower 32-bit part of num2 with lower 32-bit part of num1
  adc   edx,dword ptr num2[4]   ;add with carry the higher 32-bit part of num2 with higher 32-bit part of num1
  mov   dword ptr result,eax    ;mov the lower 32-bit part of the sum to the lower 32-bit part of result
  mov   dword ptr result[4],edx ;mov the higher 32-bit part of the sum to the higher 32-bit part of result


You can either use the result for further computations or convert it to ascii for display; you can use whatever algo you want for conversion but, if needed, you would find functions in the fpulib (umqtoa or smqtoa) to convert qwords to a decimal integers.
Whenever you assume something, you risk being wrong half the time.
http://www.ray.masmcode.com

maelirou

Omg, I'm embarrassed now.
Thank you so much for your answer, code example and fast reply!
It`s perfect and simple for asm.   :t

jj2007

Hi maelirou, welcome to the forum :icon14:

Quote from: raymond on March 31, 2016, 10:11:06 AM
You don't necessarily need to use the fpu for such an operation

Raymond is our FPU guru - don't take his advice too seriously:

  fild num1
  fild num2
  fadd
  fistp result


Much simpler, right?

Quoteyou can use whatever algo you want for conversion

If you are coming from a C/C++ background, you might be tempted to use fprintf(). Here is an example:
include \masm32\include\masm32rt.inc

.data
num1    qword    3A2C098FDE6273EDh
num2    qword    26D371B41CA8B4F6h
result  qword    ?

.code
start:
  fild num1
  fild num2
  fadd
  fistp result
  printf("The calculated sum is \t%I64X\n", result)
  printf("The expected sum is\t%s\n", "60ff7b43fb0b28e3")
  inkey "--- that was uncool, right? ---"
  exit
end start


Output:
The calculated sum is   60FF7B43FB0B2800
The expected sum is     60ff7b43fb0b28e3
--- that was uncool, right? ---


Hex$() does it properly but requires an extra library:

include \masm32\MasmBasic\MasmBasic.inc      ; download
.data
num1    qword    3A2C098FDE6273EDh
num2    qword    26D371B41CA8B4F6h
result  qword    ?
  Init

  fild num1
  fild num2
  fadd
  fistp result
  PrintLine "The calculated sum is", Tb$, Hex$(result)
  printf("The expected sum is\t%s\n", "60FF7B43 FB0B28E3")
  inkey "--- that was cool, right? ---"
EndOfCode


Output:
The calculated sum is   60FF7B43 FB0B28E3
The expected sum is     60FF7B43 FB0B28E3


But there is a shorter method to convince printf() to display result correctly: finit as first instruction after the start label ;-)

MichaelW

I verified the correct result with the Windows calculator, and included an integer calculation.


include \masm32\include\masm32rt.inc

.data
num1    qword    3A2C098FDE6273EDh
num2    qword    26D371B41CA8B4F6h
result  qword    ?

.code
start:

    fild num1
    fild num2
    fadd
    fistp result
    printf("The calculated sum is \t%I64X\n\n", result)

    ; Init FPU for full 64-bit precision, instead of the
    ; 56-bit precision that Windows sets up.
   
    finit
   
    fild num1
    fild num2
    fadd
    fistp result
    printf("The calculated sum is \t%I64X\n\n", result)
   
    mov     eax, DWORD PTR num1[0]
    mov     ebx, DWORD PTR num2[0]
    mov     ecx, DWORD PTR num1[4]
    mov     edx, DWORD PTR num2[4]
     
    ; Add low-order DWORDs.       
   
    add     eax, ebx
   
    ; Add high-order DWORDs with any carry from low-order addition.
   
    adc     ecx, edx

    ; Store results.
   
    mov     DWORD PTR result[0], eax
    mov     DWORD PTR result[4], ecx   
   
    printf("The calculated sum is \t%I64X\n\n", result)
    printf("The expected sum is\t%s\n\n", "60ff7b43fb0b28e3")
    inkey
    exit
end start


The calculated sum is   60FF7B43FB0B2800

The calculated sum is   60FF7B43FB0B28E3

The calculated sum is   60FF7B43FB0B28E3

The expected sum is     60ff7b43fb0b28e3
Well Microsoft, here's another nice mess you've gotten us into.

jj2007

Quote from: MichaelW on April 03, 2016, 04:28:04 PM
    ; Init FPU for full 64-bit precision, instead of the
    ; 56-bit precision that Windows sets up.
    finit

That was indeed the point. Interesting that Raymond's example prints fine when using
printf("The result is %llx", result)

It seems printf() doesn't use the FPU at all, precision is still 53 bits when returning.

Mikl__

lea esi,x
lea ebx,y
lea edi,result
mov ecx,8
clc
@@: lodsb
adc al,[ebx]
stosb
inc ebx
loop @b
adc byte ptr [edi],0

qWord

Quote from: Mikl__ on April 25, 2016, 07:11:47 PM
lea esi,x
lea ebx,y
lea edi,result
mov ecx,8
clc
@@: lodsb
adc al,[ebx]
stosb
inc ebx
loop @b
adc byte ptr [edi],0

Inconvenient and buggy solution (Byte result[8] is modified).
See Raymond's post for compare:
Quote from: raymond on March 31, 2016, 10:11:06 AM

  mov   eax,dword ptr num1      ;lower 32-bit part of num1
  mov   edx,dword ptr num1[4]   ;higher 32-bit part of num1
  add   eax,dword ptr num2      ;add lower 32-bit part of num2 with lower 32-bit part of num1
  adc   edx,dword ptr num2[4]   ;add with carry the higher 32-bit part of num2 with higher 32-bit part of num1
  mov   dword ptr result,eax    ;mov the lower 32-bit part of the sum to the lower 32-bit part of result
  mov   dword ptr result[4],edx ;mov the higher 32-bit part of the sum to the higher 32-bit part of result

MREAL macros - when you need floating point arithmetic while assembling!

Mikl__

#8
Quote from: qWordInconvenient and buggy solution (Byte result[8] is modified)
Really? And it seemed to me is suitable both for 8-and for 64-bit microprocessors and doesn't depend on length of composed.
And if you add some 64-bit values (for example 0FFFFFFFFFFFFFFFFh and 1) the result can be 65-bit

raymond

QuoteReally?

You are correct that the addition of two 64-bit numbers could overflow and such a possibility must be incorporated in the code.

I think qWord's comment pertained to the fact that your "result" label was not defined in the code you provided. In many of the previous posts, it was defined as a qword (which does not have a 65th bit). Moreover, depending where your '8 bytes' would be reserved for storing the 64-bit result (such as on the stack), the next byte may not have been a '0' and adding 0 with carry to that next byte could be buggy to use qWord's description.
Whenever you assume something, you risk being wrong half the time.
http://www.ray.masmcode.com

mabdelouahab

Quoteinclude \masm32\include\masm32rt.inc
.686
.XMM
.data
    q1  dq  03A2C098FDE6273EDh
    q2  dq  026D371B41CA8B4F6h
    qr  dq  0
.code
start:

    movq    mm0, q1
    movq    mm1, q2
    paddq   mm0, mm1
    movq    qr, mm0
    printf("   %I64Xh\n",q1)
    printf("+   %I64Xh\n",q2)
    printf("=   %I64Xh\n\n",qr)

    inkey
    exit
   
end start
Quote3A2C098FDE6273EDh
+       26D371B41CA8B4F6h
=       60FF7B43FB0B28E3h

Press any key to continue ...

Mikl__

Hi, raymond!
Quote from: raymondI think qWord's comment pertained to the fact that your "result" label was not defined in the code you provided
I thought that it is obvious without explanations
.data
x dq 0F897654FDE6273EDh
y dq 26D371B41CA8B4F6h
result db 9 dup (0)

jj2007

Quote from: Mikl__ on April 26, 2016, 05:18:03 PMresult db 9 dup (0)

When the result needs 9 bytes, the debate becomes a bit "academic". In practice, you should be aware of your limits, and if your program really needs 9 bytes, you'd better go for a REAL8. Or you go for Dave's Ling Long Kai Fang ;)

Mikl__

QuoteWhen the result needs 9 bytes, the debate becomes a bit "academic". In practice, you should be aware of your limits, and if your program really needs 9 bytes, you'd better go for a REAL8
Hi, jj2007!
I don't understand what about we argue. If you add two N-byte unsigned integer numbers, then you reserve N+1-bytes for result. If you multiply  two N-byte unsigned integer numbers, then you reserve 2*N bytes for result. Isn't it?

jj2007

Sure, your logic is correct. But in real life, how would you handle (e.g. print) a "Q+1-WORD" variable, and why would you use one? A REAL8 has no such problems, and is only 0.0000000000000000001% less precise than the QWORD. That is why I consider the problem "academic". We argue about it because we like arguing...