flat assembler
Message board for the users of flat assembler.
Index
> Main > 80 bit floats |
Author |
|
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 |
|||
27 Aug 2010, 16:42 |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.