flat assembler
Message board for the users of flat assembler.

Index > Main > 80 bit floats

Author
Thread Post new topic Reply to topic
edemko



Joined: 18 Jul 2009
Posts: 549
edemko 27 Aug 2010, 16:42
Hi.
It's a small revision.
Hope it helps.
Let me know when smth. comes wrong.
Ask free.
I wish you knew.
Once to be translated into Russian, sorry guys i'm tired now and bugs in raw version must be detected.
Can you propose DIVISION samples?
Smth else, smth needed in practice?
edit 2010_08_28: checked
Code:
_____________
80 bit floats




This document intended describing 80 bit floats all the computation by FPU
(Floating Point Unit) performed in. This document no way is a candidate into float
numbers format. There are many internet sources and documentation concerning FPU
internals, instructions. It's aim - bringing you basical review of the destinative
TBYTE =ten bytes= 80bits any loaded number gets transformed in as such form is the
most informative/valuable.




Suppose we have 625d of something.
  This equals: 6*10^2 + 2*10^1 + 5*10^0 =
             = 600    + 20     + 5      =
             = 625                      =
             = 6.25e2




Suppose we have 0.625d of something.
  This equals: 0*10^0 + 6*10^-1 + 2*10^-2 + 5*10^-3 =
             = 0      + 0.6     + 0.02    + 0.005   =
             = 0.625                                =
             = 6.25e-1




Let us see 625d in binary:
  625 / 2, 1 ->            Check it: 1*2^0 = 001 +
  312 / 2, 0 ->                    + 0*2^1 = 000 +
  156 / 2, 0 ->                    + 0*2^2 = 000 +
  078 / 2, 0 ->                    + 0*2^3 = 000 +
  039 / 2, 1 -> remainders         + 1*2^4 = 016 +
  019 / 2, 1 ->                    + 1*2^5 = 032 +
  009 / 2, 1 ->                    + 1*2^6 = 064 +
  004 / 2, 0 ->                    + 0*2^7 = 000 +
  002 / 2, 0 ->                    + 0*2^8 = 000 +
  001 / 2, 1 ->                    + 1*2^9 = 512 = 625

  If you feel difficult, divide 625 by 10 and try see analogy over:
  625., to get 5, we divide by 10
        to get 2, we divide by 10 by 10
        to get 6, we divide by 10 by 10 by 10

  = 1001110001.b * 2^0
  = 100111000.1b * 2^1
  = 10011100.01b * 2^2
  = 1001110.001b * 2^3
  = 100111.0001b * 2^4
  = 10011.10001b * 2^5
  = 1001.110001b * 2^6
  = 100.1110001b * 2^7
  = 10.01110001b * 2^8
  = 1.001110001b * 2^9, fpu will always normalize number like this




Well, now you know a method to get whole part ;)
Come to spread 625.625d in binary:
  625 as we know equals 1001110001b and, as though in decimal, to form binary output
  we must merge fractional part 0.625.

  Returning to our native count system:
  0.625, to get 6, we multiply by 10
         to get 2, we multiply by 10 by 10
         to get 5, we multiply by 10 by 10 by 10

  0.625 * 2, 1 ->            Check it: 1*2^-1 = 0.500 +
  0.250 * 2, 0 -> remainders         + 0*2^-2 = 0.000 +
  0.500 * 2, 1 ->                    + 1*2^-3 = 0.125 = 0.625

  = 0.101b * 2^0
  = 1.010b * 2^-1, fpu will always normalize number like this

  Gluing 625.0 and 0.625.
  1st points must be arranged as  625.0
                                + 0.625 is wrong.
    625.0
  +   0.625
  = 625.625 is ok.

  FPU does same thing, losing a lot of useful information sometimes if shifts are too big.
  It's the reason 80 bits were chosen still those are also doomed.

    1001110001.000b
  +          0.101b
  = 1001110001.101b * 2^0
  = 1.001110001101b * 2^9
    pos. powers---neg. powers




Cool, you've got it and are able using.
  As you know number/10=number*0.1.
  Are you eager :?
  0.1 * 2
  -------
  0.2 * 2
  0.4 * 2
  0.8 * 2
  .......
  1.6 * 2
  1.2 * 2
  0.4 * 2
  0.8 * 2
  .......
  1.6 * 2

  .000(1100)b
  Approximatelly = .0001101b ie rounded.
  Sharing into DWORD: .1100'1100'1100'1100'1100'1100'1100'1101 binary      shr 3
                    = .c       c    c    c    c    c    c    d hexadecimal shr 3

  Mind this principle 10*0.1 = 10*1.0/10.
  Hence eax*edx shr 32+3 must be executed to get whole part.
  32 as .cccc'cccd is a fraction but CPU treats it as an integer.
  Mind the principle mentioned over!
  03 as .cccc'cccd = 0.1 * shl 3.

  [code]
          mov     edx,$cccccccd      ;0.1 * 2^+3
          mov     eax,1'234'567'890  ;any number(dividend)
          mul     edx                ;number*0.1, result will take 64 bits as DWORD*DWORD=QWORD
          shr     edx,3              ;whole got
  [/code]




Cool, we've avoided FPU.
  In future you'll see how FPU useful is so let's, at last, see the structure of TBYTE floats
  so much told about:
  0'000000000000000'0.000000000000000000000000000000000000000000000000000000000000000b
  | |               |
  | |               |mantissa 64 bits size
  | |
  | |2's power or an exponent, mantissa multiplied by, 15 bit size
  |
  |sign 1 bit size, 1="-", 0="+"

  +0d      = 0'000000000000000'0.000000000000000000000000000000000000000000000000000000000000000b
  -0d      = 1'000000000000000'0.000000000000000000000000000000000000000000000000000000000000000b

  Unlike decimal, the power of two(exponent) is biased to $3fff.
  So that -1=$3fff-1, 1=$3fff+1, and so on.
  Pitfall: FPU's FXTRACT decomposes float into ST0 and ST1 as mantissa and exponent respectivelly.
           $0000'8xxxxxxx'xxxxxxxx -> -16'382
           $0000'4xxxxxxx'xxxxxxxx -> -16'383

  Finally
  +625.625 = 0'100000000001000'1.001110001101000000000000000000000000000000000000000000000000000b
  -625.625 = 1'100000000001000'1.001110001101000000000000000000000000000000000000000000000000000b
               _______________ -----____----____
               $3fff+9=4008    9    c   6   8




Some practice.
  Addition: 625.625 + 001.000 = 626.625
            un-normalize 625.625 shifting it 9 places left
              1001110001.101000000000000000000000000000000000000000000000000000b
            un-normalize 001.000 shifting it 0 places neither left nor right
                       1.000000000000000000000000000000000000000000000000000000000000000b
            add un-normalized
              1001110010.101000000000000000000000000000000000000000000000000000b
            normalize
              1.001110010101000000000000000000000000000000000000000000000000000b
            hex
              $4008'9ca80000'00000000

  Addition: 625.625 + 625.625 = 1251.25
            arrange both nums and add
              1001110001.101000000000000000000000000000000000000000000000000000b
              1001110001.101000000000000000000000000000000000000000000000000000b
             10011100011.01000000000000000000000000000000000000000000000000000b
            normalize, shifting 10 digits right
            remember to reflect changes in exponent
              1.001110001101000000000000000000000000000000000000000000000000000b
            hex
              $4009'9c680000'00000000

  Addition: 625.000 - 625.625 = -(625.625-625.000) = -0.625
            mantissas arranged and there is nothing to shift, substracting
              1.001110001101000000000000000000000000000000000000000000000000000b
              1.001110001000000000000000000000000000000000000000000000000000000b
              0.000000000101000000000000000000000000000000000000000000000000000b
            normalize multiplying by 2^10(shifting left 10 times)
              1.010000000000000000000000000000000000000000000000000000000000000b
            hex
              $3fff+9-10'a0000000'00000000 with MINUS
              $3ffe     'a0000000'00000000 with MINUS
              $bffe     'aaaaaaaa'00000000

  Multiplication: a^x * a^y = a^(x+y) e.g. 1.5*0.75 = 15*10^-1 * 75*10^-2 = 15*75*10^(-1+-2)
            let us play with CPU again you to understand deeper
            1.50 = 3FFF'C0000000'00000000 = 2^0  * 1.1b
            0.75 = 3FFE'C0000000'00000000 = 2^-1 * 1.1b
            now view how we divided by ten ...
            now view how we multiplied by 0.1 ...
            jerk, catcha, have you remembered the principle :?
            here it is again: 0.1*0.1 = 1*1/10/10
            [code]
            mov     eax,$C0000000
            mov     edx,$C0000000
            mul     edx
            shrd    eax,edx,31*2+1-32
            shr     edx,31*2+1-32    ;edx.eax = whole.fraction = 1.125
                                     ;take care as fraction might got zero or denormalized
                                     ;eg. after such multiplication EAX=$20000000
            [/code]

  Multiplication:
            00.9 = 3FFE'E6666666'66666666, exp=-1
            10.0 = 4002'A0000000'00000000, exp=+3
            [code]
            mov     eax,$E6666667
            mov     edx,$a0000000
            mul     edx
            shr     edx,31*2+1-3-32  ;edx=9
            [/code]




Recommended links:
  http://ray.masmcode.com/
  http://www.intel.com/products/processor/manuals/




Compose date:
  2010_08_28, 10:52 Kiev Time




Contact:
  edemko@rambler.ru
    
Post 27 Aug 2010, 16:42
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.