News:

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

Main Menu

Large numbers

Started by clamicun, August 30, 2021, 03:33:55 AM

Previous topic - Next topic

clamicun

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 ?

Biterider

Hi
Use add and adc. The carry will propagate the overflow from the 32 bit registers.


Biterider

clamicun


Thanks.
Yes, it does.
So I know when it happens, but still not what to do to avoid it.

Biterider

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

clamicun

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 ?

mineiro

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
I'd rather be this ambulant metamorphosis than to have that old opinion about everything

jj2007

An alternative that avoids adc:

include \masm32\MasmBasic\MasmBasic.inc         ; download
  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


Biterider

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

raymond

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!
Whenever you assume something, you risk being wrong half the time.
http://www.ray.masmcode.com

clamicun

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.

raymond

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
Whenever you assume something, you risk being wrong half the time.
http://www.ray.masmcode.com

clamicun

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?

raymond

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.
Whenever you assume something, you risk being wrong half the time.
http://www.ray.masmcode.com

nidud

#13
deleted

raymond

 :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:
Whenever you assume something, you risk being wrong half the time.
http://www.ray.masmcode.com