News:

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

decimal as KiB,Mib,GiB etc.

Started by sinsi, July 29, 2008, 12:38:02 PM

Previous topic - Next topic

sinsi

Anyone have any code for writing EDX:EAX as k's/megs/gigs? I've played around with it but using shifts loses the 0.5's and all.
I know there's a shell32? api but would like to know if there's an asm version.

I asked because of the thread about printing a decimal number - I think that a number like "4.0 GiB" is easier to understand than "4294967296" (or "18446744073709551615", which is 0FFFFFFFFFFFFFFFFh - what's that? 18 exabytes?))

Light travels faster than sound, that's why some people seem bright until you hear them.

MichaelW

The attachment is a quick attempt at a macro to do the scaling. With the floating-point approximations and the decimal conversions I could not think of any simple way to verify the correctness of the code, but the results at least look OK.

[attachment deleted by admin]
eschew obfuscation

sinsi

I was thinking more along the lines of automatic scaling e.g. the largest number would be 1023, so we would have "1023 bytes", then "1.00 Kib", "1023 KiB", "1023 MiB" etc.
I'm trying to use shifts, to avoid the overhead of div - they're fine for whole numbers, but lose any fractional part (1.9 Mib is a bit different to 1 Mib).

The main thing is avoiding any sort of API, since I was wanting to use this in my roll-your-own OS (or even actual DOS).
Light travels faster than sound, that's why some people seem bright until you hear them.

FORTRANS

sinsi wrote:

> I was thinking more along the lines of automatic scaling
>  e.g. the largest number would be 1023, so we would
> have "1023 bytes", then "1.00 Kib", "1023 KiB", "1023 MiB" etc.
> I'm trying to use shifts, to avoid the overhead of div - they're
>  fine for whole numbers, but lose any fractional part (1.9 Mib
> is a bit different to 1 Mib).

Using TEST you could do a binary search for the max value, and
then shift the value to a wanted size. Ten bits for the integer
and maybe four bits to use a lookup table for the fraction?

Steve N.

jj2007

- Test if your value is bigger than 1023 etc.
- for 1024, divide (using FPU) by 102.4
- result is 10
- move to a buffer, using dwtoa
- insert a dot at endofbuf-2, and at " kBytes"
- you got 1.0 kBytes

qWord

hi,

a while ago I've written a function uses binary prefixes. don't know if work all correct ... but i think so  :toothy
it uses some functions from masmlib.



regard qword

[attachment deleted by admin]
FPU in a trice: SmplMath
It's that simple!

sinsi

OK, here's my first attempt. I've never used fpu instructions before, and the code is a mess (since it's work-in-progress), so be gentle please. Am I on the right track here?

[attachment deleted by admin]
Light travels faster than sound, that's why some people seem bright until you hear them.

jj2007

You are certainly on the right track, Sinsi. Wrap it as print xByte$(123456789)... :wink

By the way, the FPU understands

      push 100
      fmul

Mark_Larson

Quote from: FORTRANS on July 30, 2008, 01:51:13 PM
sinsi wrote:

> I was thinking more along the lines of automatic scaling
>  e.g. the largest number would be 1023, so we would
> have "1023 bytes", then "1.00 Kib", "1023 KiB", "1023 MiB" etc.
> I'm trying to use shifts, to avoid the overhead of div - they're
>  fine for whole numbers, but lose any fractional part (1.9 Mib
> is a bit different to 1 Mib).

Using TEST you could do a binary search for the max value, and
then shift the value to a wanted size. Ten bits for the integer
and maybe four bits to use a lookup table for the fraction?

Steve N.

  There is actually a simpler way to do this.  There is an X86 instruction you can use to automatically scan for the highest bit that is set in the integer.  It is called BSR ( bit scan reverse).  It clears the zero flag if there is a high bit set.  And the high bit is returned in the destination.  Note it returns the BIT position.  And from there you could do a lookup table for 0-31 different bit positions, that has the largest number you can represent if that bit is set.

You can do the something similar with BSF from the front of the integer and find the first bit set.

EDIT:  Welcome to the board FORTRANS! :)  Forgot to say Hi on the other board.
BIOS programmers do it fastest, hehe.  ;)

My Optimization webpage
htttp://www.website.masmforum.com/mark/index.htm

FORTRANS

#9
Mark_Larson wrote:

QuoteThere is actually a simpler way to do this.  There is an X86 instruction you can use to automatically scan for the highest bit that is set in the integer.  It is called BSR ( bit scan reverse).  It clears the zero flag if there is a high bit set.  And the high bit is returned in the destination.  Note it returns the BIT position.  And from there you could do a lookup table for 0-31 different bit positions, that has the largest number you can represent if that bit is set.

   Oops.  Too much 16-bit coding...  Now if I had read your
message _before_ I coded something up.  With the magic of
Cut-n-Paste here is a 16-bit DOS subroutine pretending to
be a generic/no OS 32-bit subroutine.  Tested, though barely.
And to code it up quickly, no binary search, just brute forced.

QuoteEDIT:  Welcome to the board FORTRANS! :)  Forgot to say Hi on the other board.

   Thanks.  Still figuring out the interface.  (Or not.  I will work
on an avatar if I figure that one out.)

Regards,

Steve N.

I found an error.

[attachment deleted by admin]

jj2007

Quote from: Mark_Larson on July 31, 2008, 03:35:14 PM
There is an X86 instruction you can use to automatically scan for the highest bit that is set in the integer.  It is called BSR ( bit scan reverse).

Seems to be incredibly slow - 103 cycles for a single instruction??

BSR- Bit Scan Reverse  (386+)
        Usage:  BSR     dest,src
        Modifies flags: ZF
        Scans source operand for first bit set.  Sets ZF if a bit is found
        set and loads the destination with an index to first set bit.  Clears
        ZF is no bits are found set.  BSF scans forward across bit pattern
        (0-n) while BSR scans in reverse (n-0).
                                 Clocks                 Size
        Operands         808x  286   386   486          Bytes

        reg,reg           -     -   10+3n  6-103          3
        reg,mem           -     -   10+3n  7-104         3-7
        reg32,reg32       -     -   10+3n  6-103         3-7
        reg32,mem32       -     -   10+3n  7-104         3-7


sinsi

Quote from: jj2007 on July 31, 2008, 07:36:59 AM
By the way, the FPU understands

      push 100
      fmul


Huh? Do you mean

    push 100.0
    fmul dword ptr [esp]

Light travels faster than sound, that's why some people seem bright until you hear them.

GregL

Quote from: jj2007By the way, the FPU understands

      push 100
      fmul
It does not. This works:

    push 100
    fimul DWORD PTR [esp]



Quote from: jj2007Seems to be incredibly slow - 103 cycles for a single instruction??

Speed isn't everything.




jj2007

#13
I am struggling with the proper representation of qwords. In the attachment [EDIT: obsolete, removed, see later post], I use a series of example values like this:

qw1a dq 1023 ; 1023.00 bytes
qw1b dq 1099 ; 1.07 kBytes

qw2a dq 1023*1024
qw2b dq 1099*1024

qw3a dq 1023*1024*1024
qw3b dq 1099*1024*1024


I pass the values to the proc like this:
lea ecx, [qw1a+8*ebx]
invoke ShowQw, ecx, addr buffer
...
  mov esi, pNum ; pointer to our 8-byte number
  xor edx, edx ; counter
  mov IsLow, edx ; flag
  mov eax, [esi+4] ; eax is high dword of qword to convert
  .if eax==0
mov ecx, 1024*1024*1024 ; 2^30
mov eax, [esi] ; low dword only
  .endif


This works fine until No. 6:
qw4a dq 1023*1024*1024*1024
qw4b dq 1099*1024*1024*1024


Maybe related: Is there a correct way to convince the FPU that we are working with unsigned CPU registers?

  push eax ; our number, either high or low dword
  fild dword ptr [esp] ; move into ST (0)

  .if signed eax<0 ; if eax==C000000,
fabs ; the FPU thinks it's negative...

sinsi

One reason for my convoluted code is that fpu stuff is signed, so using "fild 0ffffffffh' (you get the idea) is treated as signed...help, Raymond!  :bdg

jj, I'm thinking that if you want to use 'qw1a dq 1023' as a real8, it needs to be 'qw1a dq 1023.0'.
That way masm knows it's an fpu number (my god, the fpu has been around for yonks and I don't know jack shit about it  ::))

The bsf thing I didn't worry about, since I saw the same 100+ cycles that jj did, but qword's code and michael's helped me figure out what the hell is happening.
(my fpu code is basically michael's - I don't really get it, but my fpu programming is growing exponentially, thanks mate).

One thing, I used Windbg to go through the code, the 'view registers' really helped here - st(0) and such really f*cked me up until I could see what the hell was happening.
Anyway, tomorrow (maybe) is the big rewrite of the proc, then it's fair game.


PS sorry jj, your love of the 'xxx$()' macro is for you to do... :bg
Light travels faster than sound, that's why some people seem bright until you hear them.