The MASM Forum

General => The Campus => Topic started by: clamicun on August 30, 2021, 03:33:55 AM

Title: Large numbers
Post by: clamicun on August 30, 2021, 03:33:55 AM
To get the total folder size I count the bytes of each folder in it.
The proc, which counts, returns the bytes of each subfolder in eax, which is added to the "TotalSize:DWORD".

TotalSize should be a QWORD, but I can't add eax to a QWORD.

What to do when the amount exceeds 4294967295 ?
Title: Re: Large numbers
Post by: Biterider on August 30, 2021, 03:48:52 AM
Hi
Use add and adc. The carry will propagate the overflow from the 32 bit registers.


Biterider
Title: Re: Large numbers
Post by: clamicun on August 30, 2021, 05:20:10 AM

Thanks.
Yes, it does.
So I know when it happens, but still not what to do to avoid it.
Title: Re: Large numbers
Post by: Biterider on August 30, 2021, 05:41:36 AM
Hi
This is a snippet from the QWORD.inc file.
Adapt it to your needs.


add (QUADWORD ptr qWrd).LoDWord, eax
adc (QUADWORD ptr qWrd).HiDWord, 0


where

DOUBLEBYTE union
  WORD                       ?
  struc
    LoByte    BYTE           ?
    HiByte    BYTE           ?
  ends
DOUBLEBYTE ends
pDOUBLEBYTE typedef ptr DOUBLEBYTE

DOUBLEWORD union
  DWORD                      ?
  struc
    LoWrd    DOUBLEBYTE      {}
    HiWrd    DOUBLEBYTE      {}
  ends
DOUBLEWORD ends
PDOUBLEWORD typedef ptr DOUBLEWORD

QUADWORD union
  QWORD                      ?
  struc
    LoDWord    DOUBLEWORD    {}
    HiDWord    DOUBLEWORD    {}
  ends
QUADWORD ends
PQUADWORD typedef QUADWORD

Biterider
Title: Re: Large numbers
Post by: clamicun on August 31, 2021, 12:07:12 AM
Thanks.
That seems to be for people who understand Assembler.
Not for me.
I not even understand "add (QUADWORD ptr qWrd).LoDWord, eax"
"QUADWORD" ?

btw.
Where do i find QWORD.inc ?
Title: Re: Large numbers
Post by: mineiro on August 31, 2021, 01:47:28 AM
hello sir clamicun;
Others here said that carry goes to left.


mov eax,0ffffffffh      ;register full, if we add only one bit so carry bit in flag register will be on
mov edx,0               ;you're talking of a qword (2 dwords registers, I'm using edx:eax to fake one 64 bits register only)
                        ;00000000ffffffffh
mov ecx,1               ;will be 64(edx:eax) bits register plus a 32 bits register (ecx)
add eax,ecx             ;add low part (eax and ecx), but, if carry happens, we need add that carry to high part (edx)
adc edx,0               ;edx:eax=0000000100000000h
Title: Re: Large numbers
Post by: jj2007 on August 31, 2021, 02:21:29 AM
An alternative that avoids adc:

include \masm32\MasmBasic\MasmBasic.inc         ; download (http://masm32.com/board/index.php?topic=94.0)
  Init
  xor ebx, ebx
  xorps xmm7, xmm7
  .Repeat
        invoke GetTickCount
        movd xmm0, eax
        paddq xmm7, xmm0
        deb 4, "test", x:xmm7
        inc ebx
  .Until ebx>=30
  Inkey Str$("The final value is %i", xmm7)
EndOfCode


test    x:xmm7          00000000 00000000 00000000 6D0B1FBC
test    x:xmm7          00000000 00000000 00000000 DA163F78
test    x:xmm7          00000000 00000000 00000001 47215F34   <<<< first overflow
test    x:xmm7          00000000 00000000 00000001 B42C7EF0
test    x:xmm7          00000000 00000000 00000002 21379EAC
test    x:xmm7          00000000 00000000 00000002 8E42BE68
test    x:xmm7          00000000 00000000 00000002 FB4DDE24
test    x:xmm7          00000000 00000000 00000003 6858FDE0
test    x:xmm7          00000000 00000000 00000003 D5641D9C
test    x:xmm7          00000000 00000000 00000004 426F3D68
test    x:xmm7          00000000 00000000 00000004 AF7A5D34
test    x:xmm7          00000000 00000000 00000005 1C857D00
test    x:xmm7          00000000 00000000 00000005 89909CCC
test    x:xmm7          00000000 00000000 00000005 F69BBC98
test    x:xmm7          00000000 00000000 00000006 63A6DC64
test    x:xmm7          00000000 00000000 00000006 D0B1FC30
test    x:xmm7          00000000 00000000 00000007 3DBD1BFC
test    x:xmm7          00000000 00000000 00000007 AAC83BC8
test    x:xmm7          00000000 00000000 00000008 17D35B94
test    x:xmm7          00000000 00000000 00000008 84DE7B70
test    x:xmm7          00000000 00000000 00000008 F1E99B4C
test    x:xmm7          00000000 00000000 00000009 5EF4BB28
test    x:xmm7          00000000 00000000 00000009 CBFFDB04
test    x:xmm7          00000000 00000000 0000000A 390AFAE0
test    x:xmm7          00000000 00000000 0000000A A6161ABC
test    x:xmm7          00000000 00000000 0000000B 13213AA7
test    x:xmm7          00000000 00000000 0000000B 802C5A92
test    x:xmm7          00000000 00000000 0000000B ED377A7D
test    x:xmm7          00000000 00000000 0000000C 5A429A68
test    x:xmm7          00000000 00000000 0000000C C74DBA53
The final value is 54883367507

Title: Re: Large numbers
Post by: Biterider on August 31, 2021, 04:34:03 AM
Hi clamicun
The QWORD.inc file is part of ObjAsm.
OK, let's write it more simply considering that x86 uses little endian byte order  :cool:

local qCounter:QWORD
...
add DWORD ptr [qCounter], eax
adc DWORD ptr [qCounter + sizeof(DWORD)], 0
...


Biterider
Title: Re: Large numbers
Post by: raymond on August 31, 2021, 04:50:51 AM
QuoteThat seems to be for people who understand Assembler.
Not for me.

If you can get the size of files in a folder, you should understand the following "simple" code using MASM syntax.

The use of LABEL in the data description will simply define the next 64 bits as a qword called TotalSize without reserving any memory for it.
The next two dwords will become part of that qword in their 'little endian' order.

Let us know if there is anything needing more explanation relating to the following code.

.data
      TotalSize LABEL QWORD
      LowSize     dd    ?
      HiSize      dd    ?

.code
;     call get file size in EAX
      add   LowSize,eax
      adc   HiSize,0          ;will increment the HiSize whenever there is overflow in the lower 32 bits after the addition of eax
      ....


You can later use the accumulated total size by referring to it as a qword called TotalSize for whatever reason you need.

NOTE: For the sake of completeness, although such a situation may be very improbable, your result would be erroneous IF the size of any of your files exceeds 32 bits!
Title: Re: Large numbers
Post by: clamicun on September 01, 2021, 12:12:49 AM
Thank you.

add   LowSize,eax
adc   HiSize,0          ;will increment the HiSize whenever there is overflow in the lower 32 bits after the addition of eax.

That is very helpful.
HiSize = 3 means that LowSize 3 times exceeded 4294967295 und TotalSize contains at least 12.884.901.885 bytes.

How I get the real size I still do not understand but will find out.

Last question.
At the end I convert the total amount of bytes into some more readable - using:
INVOKE  StrFormatByteSize,totalSize, addr size_buffer, 30 
This doesn't seem to work with a qword.
Title: Re: Large numbers
Post by: raymond on September 01, 2021, 12:38:17 PM
There are numerous ways to convert 64-bit binary numbers to the decimal system for display purposes. The following code using the FPU is probably among the simplest ones if you are still restricted by a 32-bit assembler.


.data
temp_bcd dt  ?       ;reserves 10 bytes for temporary storage of the binary coded number (bcd) from the FPU
result db  18 dup(?)  ;for the resulting ascii string

.code
qw2ascii proc
push esi
push edi
finit         ;to insure full 64-bit precision of the FPU
fild TotalSize ;load the qword onto the FPU
fbstp temp_bcd  ;store it back as a bcd

;convert the bcd to a null-terminated ascii string
lea edi,result
lea    esi,temp_bcd
mov ecx,8       ;not necessary to check sign in highest byte in this case

;first find the highest digit
   @@:
movzx ax,byte ptr[esi+ecx]
or     al,al
jnz @F
dec   ecx
jns @B
mov al,30h
stosb          ;this would show "0" as the zero-terminated result string
          ;and allow the program to terminate normally if the total is in fact 0
jmp lastdigit

   @@:
;check if highest digit is still null
      .if   al < 0Fh    ;top digit would be 0 and must be disregarded
            add  al,30h
            stosb
            dec   ecx
            js    lastdigit
            movzx ax,byte ptr[esi+ecx]    ;proceed to next digits
      .endif

   @@:
      ror    ax,4
      ror    ah,4            ;splits the two nibbles in AL into the two bytes AH/AL
      add   ax,3030h     ;converts them to ascii
      stosw
      dec   ecx
      js     lastdigit
      movzx ax,byte ptr[esi+ecx]
      jmp   @B

lastdigit:
      xor   eax,eax
      stosb
      pop   edi
      pop   esi
      ret

qw2ascii endp
Title: Re: Large numbers
Post by: clamicun on September 02, 2021, 03:47:00 AM
Yes, that works well.
Thank you very much.
I learned a lot.

To convert the result into KB, MB, GB.
Are there any functions beside StrFormatByteSize to convert the result?
Title: Re: Large numbers
Post by: raymond on September 02, 2021, 04:47:05 AM
You don't really need any special function for that. The following simple code would give you a truncated result if that would be sufficient. If you would prefer to have a result rounded to the nearest integer, a few more simple instructions would be necessary. Otherwise if you need some decimal places of accuracy, you would then need to use the FPU and some of the functions available in the fpulib.


mov   eax,LowSize
mov   edx,HiSize
mov   ecx,1000    ;if you want kbytes as long as HiSize is smaller than 1000
                  ;otherwise, you would need a different procedure
div   ecx         ;your result in KB would be in EAX
                  ;you can then do whatever you want with that result
                  ;you have a wide choice of available procedures to convert the 32-bit integer in EAX to ascii


You can do as above with "mov  ecx,1000000" or 1000000000 to get either MB or GB in EAX.
Title: Re: Large numbers
Post by: nidud on September 02, 2021, 06:10:36 AM
deleted
Title: Re: Large numbers
Post by: raymond on September 02, 2021, 06:23:22 AM
 :thumbsup:
I must admit that I assumed clamicun had meant multiples of 1000 instead of 1024. His next posting will clarify if my assumption fell in the 50% wrong category. :biggrin:
Title: Re: Large numbers
Post by: daydreamer on September 02, 2021, 09:18:51 PM
yet another nitpick,when measure file sizes are seen explorer in check file size=two file sizes,first file size is for example 21345 bytes,second is file size on disk evenly divided by block size ca 24 k,file size on disk is 4k(4096b) blocks or other size if formatted different
also testwrote 13gb max sized file on mechanical drive,but only 1gb max on my SSD

Title: Re: Large numbers
Post by: clamicun on September 02, 2021, 10:42:12 PM
Thanks to everyone who participated in this topic.
I understand - at least theoretically - everything.
And everything works fine with defined qwords.

qword num1 4294967297
qword num2 103
result 4294967400
which I can print with Raymonds qw2ascii proc.

The problem is, that the value of the second qword is only available after some other operation.
And still I don't get the value in eax  into that second qword.
Title: Re: Large numbers
Post by: raymond on September 03, 2021, 03:13:15 AM
Quote from: clamicun on September 02, 2021, 10:42:12 PM
The problem is, that the value of the second qword is only available after some other operation.
And still I don't get the value in eax  into that second qword.
If you explain the purpose of that qword num2 (assuming that is your "second qword") and how you are using it without being able to get its value, we may be able to help.
Title: Re: Large numbers
Post by: clamicun on September 03, 2021, 10:12:48 PM
The value of the second keyword num2 is produced in eax and I don't know how to put eax  into that qword.
Excuse me.
"Blind alarm"
By now I know how to store eax in a qword.
Title: Re: Large numbers
Post by: mineiro on September 03, 2021, 10:19:27 PM
Quote from: clamicun on September 02, 2021, 10:42:12 PM
I understand - at least theoretically - everything.
The value of the second keyword num2 is produced in eax and I don't know how to put eax  into that qword.
I suppose you're looking to this with decimal numbers in mind instead of binary.
4294967297 == 100000000000000000000000000000001

Well, if you sum 2 numbers in decimal base, but each one have only one digit, how to proceed?

  9
+ 2
-----
  ?

The symbol 9 is the last possible, so, "register" is full. If we add anything bigger than 0 to symbol 9 an overflow will occur. But we have only one digit to play, and one digit only cannot hold that sum. We need create a digit to the left side (high part) so result can hold that sum.
Only result need be "expanded,extended", because we will continue adding only one digit in decimal base.


I put side by side to show you an invisible thing happening. The sum bellow in decimal base don't overflow, everything fits in result. But if you look to this in binary, you will see an overflow happening.

4294967295     ;32 bits                                        11111111111111111111111111111111
0000000002     ;32 bits                                        00000000000000000000000000000010
-----------
4294967297     ;64 bits        0000000000000000000000000000000100000000000000000000000000000001
Title: Re: Large numbers
Post by: clamicun on September 03, 2021, 11:43:50 PM
Obrigado mineiro.
I solved the "problem".
It is not that difficult to store eax in a qword.