Wikibooks
ltwikibooks
https://lt.wikibooks.org/wiki/Pagrindinis_puslapis
MediaWiki 1.47.0-wmf.18
first-letter
Medija
Specialus
Aptarimas
Naudotojas
Naudotojo aptarimas
Wikibooks
Wikibooks aptarimas
Vaizdas
Vaizdo aptarimas
MediaWiki
MediaWiki aptarimas
Šablonas
Šablono aptarimas
Pagalba
Pagalbos aptarimas
Kategorija
Kategorijos aptarimas
TimedText
TimedText talk
Module
Module talk
Event
Event talk
Dešimtainių skaičių vertimas į dvejetainius skaičius
0
11878
58987
58986
2026-09-03T12:59:06Z
Paraboloid
1294
/* Worked example */
58987
wikitext
text/x-wiki
==Dešimtainių skaičių vertimas į dvejetainius skaičius==
[https://www.google.com/search?client=opera&q=single+precision&sourceid=opera&ie=UTF-8&oe=UTF-8&udm=50&fbs=ABfTbFVyMZGZf1hfvX9uKjN_-G8c4u0nXx4bEIpwm1lnNH832VTJOOCxW_fyN-Q_ezyf8gKjm3rhh_G8jdZ2Q6tji4z8Mva6cfvBj5rpPch2IC955IbzrbwHf6tkbFbd-nuFdbKth9Y-58t5LtnYgTA4TWDFYCUNl4d7F9XBAwiEq2T2c7SNgrvMxYiRBXL4fnQnnTOewx28&aep=10&ntc=1&sxsrf=APpeQnvZo3fX2PwO881uSdWsoRELP18NhQ%3A1788348274309&mstk=AUtExfAJ0Kp9BqT3EJbzHOz3MHMalnyXkoOTLvgho5ZQ9lzjrnmmUFCgux_RVe7bouRlyBSGpkUcLpvfZ39N45TUoor6TyyEW7_PpE7eOwP-kU7IFxE6monk-HtsDXkDu7g362AN4NTW3oRjfwn9OtD0BIj2r4QAVauMhDPCIAiWgLimDuate6cf2o6bB5R-6-vzcCqbCju1KJQTdR4HSF9puZ_HCG1hXQ8QaCIqD1LJ_HWonNnZGma6Biu3I1wWFPy6esLnfaKpIX6VFWZsArfQN97XGipwkH7FLKCyZiev5rZBrhE8KincMthP7B9AJDugKLy8qJfORQ7PQR2GslAaCLnkechjBCnXfrmSohwJskbEWU9db6Q279uO4dGu0eI2YUvpEwoQUqkbREqJqrGpJQWFy7WoTzI93_o_2I61PU1FTiuGq-4AVN7erT0WmuWizHDEE2XsTes&aioh=3&csuir=1&atvm=2&mtid=dQeYaumuDL2Ixc8Px6Ts0QE DI atsakymas]
:Single-precision is a 32-bit computer number format that stores fractional and large numbers using a sign bit, an exponent, and a mantissa. Structure of Single-Precision (Binary32) According to Wikipedia, “Single-precision floating-point format (sometimes called FP32, float32, or float) is a computer number format, usually occupying 32 bits in computer memory.” The 32 bits are divided into three specific parts:
*Sign bit (1 bit): Determines if the number is positive (0) or negative (1).
*Biased exponent (8 bits): Stores the magnitude with an excess-127 bias, giving an actual exponent range of -126 to +127.
*Mantissa/Significand (23 explicitly stored bits): Represents the precision digits of the number, with an implicit leading 1 for normalized values.
:Precision and Applications. Decimal Precision: Provides about 7 to 8 decimal digits of accuracy. Most users on StackOverflow agree that “Single precision typically offers 7-8 decimal digits of precision.”
:'''Dešimtainių skaičių vertimas į dvejetainius.'''
:Step-by-Step Conversion Framework.
*Step 1: Determine the Sign Bit (1 bit). If the number is positive, the sign bit is 0. If the number is negative, the sign bit is 1. Example (-12.625): It is negative, so the sign bit is 1.
*Step 2: Convert the Absolute Value to Binary. Separate the number into its integer and fractional parts, convert both to binary, and combine them.
:Integer part '''12''': (12/2 = 6) ('''rem'''ainder 0), (6/2 = 3) (rem 0), (3/2 = 1) (rem 1), (1/2 = 0) (rem 1) <math>\rightarrow </math> '''1100'''.
:Fractional part '''0.625''': (0.625 * 2 = 1.25) (1), (0.25 * 2 = 0.5) (0), (0.5 * 2 = 1.0) (1) <math>\rightarrow </math> '''101'''.
:Example Combined: '''12.625''' = '''1100.101'''.
*Step 3: Normalize the Binary Number. Shift the binary point so that exactly one non-zero digit (which will always be 1) remains to its left. Count how many places you moved the point. This count is your exponent (E).
:Move the point 3 places to the left: '''1100.101''' <math>\rightarrow </math> '''1.100101'''.
:Example Exponent: Because we moved it 3 places, E = 3.
*Step 4: Calculate the Biased Exponent (8 bits) IEEE 754 single-precision uses a bias of 127. Add your exponent E to this bias, and convert the resulting integer to an 8-bit binary number.
:Calculation: 127 + 3 = 130.
:Convert 130 to 8-bit binary: '''130''' = '''10000010'''.
*Step 5: Extract the Mantissa/Significand (23 bits).
:Take the fractional bits from your normalized number (everything to the right of the binary point). Drop the leading 1. If the bits are fewer than 23, pad the right side with zeros until you reach exactly 23 bits.
:Normalized bits: 1.100101 <math>\rightarrow </math> Drop the ''1.'' (atmesti kairiausią vienetą ir tašką po jo) to get '''100101'''.
:Example Pad to 23 bits: 10010100000000000000000.
:'''Final Assembly.'''
:Combine the three components in order: Sign (1 bit) + Exponent (8 bits) + Mantissa (23 bits).
:Component_____________Bits______________Value for -12.625_______
:Sign____________________1_______________________1______________
:Exponent________________8____________________10000010__________
:Mantissa________________23______________10010100000000000000000
*Final 32-bit Binary String: '''11000001010010100000000000000000'''.
*Hexadecimal Representation: '''C1450000'''.
:Sign: '''1'''1000001010001010000000000000000.
:Exponent: 1'''10000010'''10001010000000000000000.
:Mantissa: 110000010'''10010100000000000000000'''.
:Patikrinimas (-12.625).
:Exponent: 10000010 = 128*1 + 64*0 + 32*0 + 16*0 + 8*0 + 4*0 + 2*1 +1*0 = 130. 130-127 = 3. 2^3 = 8.
:Mantissa: 100101 = 0.5*1 + 0.25*0 + 0.125*0 + 0.0625*1 + 0.03125*0 + 0.015625*1 + 0.0078125*0 = 0.578125.
:8 * 0.578125 = 4.625.
:8 * 1 = 8.
:8 + 4.625 = 12.625.
:Reikia gražinti paimtą vienetą priekyje ('''12.625''' = '''1100.101'''; '''1100.101''' <math>\rightarrow </math> '''1.100101'''):
:8 * (1 + 0.578125) = 8 * 1.578125 = 12.625.
:-12.625 = -1.2625 * 10^1.
:Čia mantisa 0.2625, o ekspontentė 1 dešimtainėje sistemoje. Skačių 0.2625 reikia kaskart dauginti iš 2.
:0.2625*2 = 0.525 (ne vienetas, reiškia pirmas skaitmuo 0),
:0.525*2 = 1.05 (vienetas, reiškia antras skaitmuo 1),
:0.05*2 = 0.1 (ne vienetas, reiškia trečias skaitmuo 0),
:0.1*2 = 0.2 (ne vienetas, reiškia ketvirtas skaitmuo 0),
:0.2*2 = 0.4 (ne vienetas, reiškia penktas skaitmuo 0),
:0.4*2 = 0.8 (ne vienetas, reiškia šeštas skaitmuo 0),
:0.8*2 = 1.6 (vienetas, reiškia septintas skaitmuo 1),
:0.6*2 = 1.2 (vienetas, reiškia aštuntas skaitmuo 1),
:0.2*2 = 0.4 (ne vienetas, reiškia devintas skaitmuo 0),
:0.4*2 = 0.8 (ne vienetas, reiškia dešimtas skaitmuo 0),
:0.8*2 = 1.6 (vienetas, reiškia vienuoliktas skaitmuo 1),
:0.6*2 = 1.2 (vienetas, reiškia dviliktas skaitmuo 1),
:0.2*2 = 0.4 (ne vienetas, reiškia tryliktas skaitmuo 0),
:0.4*2 = 0.8 (ne vienetas, reiškia keturioliktas skaitmuo 0),
:0.8*2 = 1.6 (vienetas, reiškia penkioliktas skaitmuo 1),
:0.6*2 = 1.2 (vienetas, reiškia šešioliktas skaitmuo 1).
:Tada galutinis skaičius '''0.2625''' yra toks:
:0.0100001100110011.
:Kad gauti didesnį tikslumą, procesą reikia kartoti begalo arba iki reikiamo tikslumo.
:Skaičiau '''0.2625''' reikšmė yra:
:0.0100001100110011 =
:= 0.5*0 + 0.25*1 + 0.125*0 + 0.0625*0 + 0.03125*0 + 0.015625*0 + 0.0078125*1 + 0.00390625*1 + 0.001953125*0 + 0.0009765625*0 +
:+ 0.00048828125*1 + 0.000244140625*1 + 0.0001220703125*0 + 0.00006103515625*0 + 0.000030517578125*1 + 0.0000152587890625*1 =
:= 0.26171875 + 0.0007781982421875 = '''0.26249'''69482421875.
:Taigi, 0.26249 labai panašus į 0.2625.
:Vadinasi '''1.2625''' dvejetainėje sistemoje apytiksliai yra '''1.0100001100110011'''.
:Eksponentę 10 reikia versti taip:
:10 = 8 + 2. Tada 10 dvejetainėje sistemoje yra 00001010 (1*0 + 2*1 + 4*0 + 8*1 + 0 + 0 + 0 + 0 = 10).
:Bet eksponentė single precision formate gali būti tik, 0, 1, 2, 4, 8, 16, 32, 64, 128 ir taip toliau.
:Arba reikia daryti taip:
:10/2 = 5 (rem 0),
:5/2 = 2 (rem 1),
:2/2 = 1 (rem 0)
:1/2 = 0.5 (rem 1).
:Va štai šitaip ir gaunamas skaičius 10. Tai yra 1010.
:Skaičius 1010 pakeičiamas skaičiu 1.010 su eksponente 3 (2^3 = 8).
:Tada skaičius 1.010 iškoduojamas taip:
:1 + 0.5*0 + 0.25*1 + 0.125*0 = 1.25.
:Padauginama iš dviejų pakelta eksponente 3:
:1.25 * 2^3 = 1.25 * 8 = 10.
:Tuomet
:1.2625 * 10 = 12.625.
:'''Grįžimas prie pavyzdžio.'''
:Patikrinimas (-12.625).
:Exponent: 10000010 = 128*1 + 64*0 + 32*0 + 16*0 + 8*0 + 4*0 + 2*1 +1*0 = 130. 130-127 = 3. 2^3 = 8.
:Skaičiaus 1100.101 kablelį galima pastumti 4 pozicijom į kairę ir eksponentę duoti 4. Mantisa tada yra 0.1100101, o eksponentė yra 4.
:0.5*1 + 0.25*1 + 0.125*0 + 0.0625*0 + 0.03125*1 + 0.015625*0 + 0.0078125*1 = 0.7890625.
:2^4 * 0.7890625 = 16 * 0.7890625 = '''12.625'''.
:Bandomas kitas skaičius 24:
:24/2 = 12 (rem 0),
:12/2 = 6 (rem 0),
:6/2 = 3 (rem 0),
:3/2 = 1 (rem 1),
:1/2 = 0.5 (rem 1).
:Reiškia 24 yra 11000 (16*1 + 8*1 + 4*0 + 2*0 + 1*0 = 24).
:Bandomas kitas skaičius 19:
:19/2 = 9 (rem 1),
:9/2 = 4 (rem 1),
:4/2 = 2 (rem 0),
:2/2 = 1 (rem 0),
:1/2 = 0.5 (rem 1).
:Reiškia 19 yra 10011 (16*1 + 8*0 + 4*0 + 2*1 + 1*1 = 19).
:Bandomas skaičius 22:
:22/2 = 11 (rem 0),
:11/2 = 5 (rem 1),
:5/2 = 2 (rem 1),
:2/2 = 1 (rem 0),
:1/2 = 0.5 (rem 1).
:Reiškia 22 yra 10110 (16*1 + 8*0 + 4*1 + 2*1 + 1*0 = 16+4+2 = 22).
:Trumpas paaiškinimas kodėl eksponentė saugoma formate nuo 1 iki 254, pridedant 127 prie -126 ir iki 127. Tai greičiausia yra todėl, kad sudedant single precision skaičių tokiame formate kokiame jis yra, jo reiikšmė gali būti gana tiksliai traktuojama kaip sveikojo skaičiaus reikšmė. Su kai kuriais pakeitimais.
:'''-12.625''' yra '''11000001010010100000000000000000'''.
:Pridėjus 127 ('''01111111''') prie eksponentės 3 ('''00000011''') gauname 130 ('''10000010'''):
:'''00000011'''+
:'''01111111'''=
:'''10000010'''.
:Vadinasi tada skaičius '''-12.625''' tampa
:Mantissa: 1100101 = 1 + 0.5*1 + 0.25*0 + 0.125*0 + 0.0625*1 + 0.03125*0 + 0.015625*1 + 0.0078125*0 = 1.578125;
:2^130 = 1.3611294676837538538534984297271e+39 = 1.3611294676837538538534984297271 * 10^39.
:O sveikasis skaičius '''11000001010010100000000000000000''' be minuso yra '''01000001010010100000000000000000''' ir užrašomas taip:
:1*0 + 2*0 + 4*0 + 8*0 + 16*0 + 32*0 + 64*0 + 128*0 + 256*0 + 512*0 + 1024*0 +
:+ 2048*0 + 4096*0 + 8192*0 + 16,384*0 + 32,768*0 + 65,536*0 + 131,072*0 +
:+ 262,144*1 + 524,288*0 + 1,048,576*1 + 2,097,152*0 + 4,194,304*0 + 8,388,608*1 + 16,777,216*0 + 33,554,432*1 +
:+ 67,108,864*0 + 134,217,728*0 + 268,435,456*0 + 536,870,912*0 + 1,073,741,824*0 +
:+ 2,147,483,648*1 + 4,294,967,296*0 =
:= 0 + 0 + 43,253,760 + 0 + 2,147,483,648 = 2,190,737,408.
:Kažka supainiojau. Atrodė, kad eksponentė beveik tas pats kas didesni skaičiai priekyje.
==Skaičiavimas inverse square root su C kodu==
:Čia https://en.wikipedia.org/wiki/Fast_inverse_square_root aiškinama kaip naudojant sveikuosius skaičius galima apsakičiuoti <math>\frac{1}{\sqrt{x}}.</math>
:"The fast inverse square generates a good approximation through integer operations by adding and subtracting the integer form of floating-point numbers, and taking a square root by dividing by two (which is just a right-shift)."
:Iš čia https://lt.wikibooks.org/wiki/Sekos_riba#Greitas_šaknies_iš_skaičiaus_a_traukimo_būdas gauta formulė
:<math>y_{n+1} = \frac{y_{n}\left(3-xy_n^2\right)}{2}. \quad (4)</math>
:<math>y_n\approx \frac{1}{\sqrt{x}}.</math>
:Ją dar galima pagreitint, pakeitus z = x/2. Tada ši formulė tampa tokia:
:<math>y_{n+1} = y_{n}\left(1.5 - zy_n^2\right). \quad (4.1)</math>
:Programavimo kalbos C kodas skaičiuoti <math>\frac{1}{\sqrt{x}}</math> yra toks:
<syntaxhighlight lang="c">
float Q_rsqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = * ( long * ) &y; // evil floating point bit level hacking
i = 0x5f3759df - ( i >> 1 ); // what the fuck?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
return y;
}
</syntaxhighlight>
:Šito kodo paaiškinimas yra toks:
:Skaičius '''i''' yra ''long integer'' (32 bitų sveikasis skaičius, https://en.wikipedia.org/wiki/C_data_types).
:Skaičiai '''x2''' ir '''y''' yra floating point skaičiai (32 bitų arba 64 bitų). Jeigu 32 bitų, tai tada tai yra single precision 32 bitų float skaičiai.
:Konstanta threehalfs = 1.5F yra 32 bitų single precision skaičius 1.5.
:Skaičius '''number''' yra 32 bitų single precision float ir paduodamas funkcijai. Kitaip tariant '''number''' yra '''x''', o '''y''' bus <math>y\approx \frac{1}{\sqrt{x}}.</math>
:'''x2''' yra '''number'''*0.5 = z.
:Eilutė
i = * ( long * ) &y;
:paverčia ''floating point number'' '''y''' į ''long integer number'' '''i'''. Dabar i yra toks pat kaip y, tik laikomas kaip sveikasis skaičius, o ne slankaus kablelio skaičius. Simbolis * yra pointer to memory address, skirtas įdėti į tą adresą kažką, o ženklas & skirtas paemimui iš tam tikro RAM adreso (arba atvirkščiai, * paėmimui, o & įdėjimui, gerai neatsimenu).
:Todėl ši eilutė gali būti suprantama kaip
:( long * ) &y
:paimti iš y RAM adreso y reikšmę ir įdėti į ''long integer'' (kol kas be pavadinimo) RAM adresą.
:Paskui iš to ''long integer'' RAM adreso įdėti į sveikojo skaičiaus '''i''' RAM adresą (ši kodo dalis "i = *"). Kaip sakyta, iš esmės floating number '''y''' paverčiamas į long integer number '''i'''.
:Šito kodo paaiškinimas yra toks:
:Skaičius '''i''' yra ''long integer'' (32 bitų sveikasis skaičius, https://en.wikipedia.org/wiki/C_data_types).
:Skaičiai '''x2''' ir '''y''' yra floating point skaičiai (32 bitų arba 64 bitų). Jeigu 32 bitų, tai tada tai yra single precision 32 bitų float skaičiai.
:Konstanta threehalfs = 1.5F yra 32 bitų single precision skaičius 1.5.
:Skaičius '''number''' yra 32 bitų single precision float ir paduodamas funkcijai. Kitaip tariant '''number''' yra '''x''', o '''y''' bus <math>y\approx \frac{1}{\sqrt{x}}.</math>
:'''x2''' yra '''number'''*0.5 = z.
:Eilutė
i = * ( long * ) &y;
:paverčia ''floating point number'' '''y''' į ''long integer number'' '''i'''. Dabar i yra toks pat kaip y, tik laikomas kaip sveikasis skaičius, o ne slankaus kablelio skaičius. Simbolis * yra pointer to memory address, skirtas įdėti į tą adresą kažką, o ženklas & skirtas paemimui iš tam tikro RAM adreso (arba atvirkščiai, * paėmimui, o & įdėjimui, gerai neatsimenu).
:Todėl ši eilutė gali būti suprantama kaip
:( long * ) &y
:paimti iš y RAM adreso y reikšmę ir įdėti į ''long integer'' (kol kas be pavadinimo) RAM adresą.
:Paskui iš to ''long integer'' RAM adreso įdėti į sveikojo skaičiaus '''i''' RAM adresą (ši kodo dalis "i = *"). Kaip sakyta, iš esmės floating number '''y''' paverčiamas į long integer number '''i'''.
:Toliau eilutė
i = 0x5f3759df - ( i >> 1 );
:reiškia pastumti sveikąjį skaičių '''i''' viena pozicija į dešinę ir paskui atimti iš sveikojo skaičiaus 0x5f3759df ir rezultatą įdėti į skaičiaus '''i''' adresą. Skaičius 5f3759df turi 8 hexodecimal skaitmenis. Vienas heksodecimal skaitmuo sudaro 4 bitus.
:5 yra 0101, f yra 1111, 3 yra 0011, 7 yra 0111, 5 yra 0101, 9 yra 1001, d yra 1101 (nes A yra 1010, B yra 1011, C yra 1100), f yra 1111. Todėl
:5F3759DFh = 0101,1111,0011,0111,0101,1001,1101,1111;
:5F3759DFh = 01011111001101110101100111011111.
:Gale raidė h reiškia, kad tai hexodecimal skaičius.
:Ši eilutė:
y = * ( float * ) &i;
:paverčia long int '''i''' į float, o paskui tą float perkelią į '''y'''.
:Toliau daromos Niutono iteracijos:
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
:čia y jau turi apytikslią reikšmę <math>\frac{1}{\sqrt{\text{number}}}.</math>
===Worked example===
As an example, the number <math>x=0.15625</math> can be used to calculate <math display=inline>\frac{1}{\sqrt{x}} \approx 2.52982</math>. The first steps of the algorithm are illustrated below:
0011_1110_0010_0000_0000_0000_0000_0000 Bit pattern of both x and i
0001_1111_0001_0000_0000_0000_0000_0000 Shift right one position: (i >> 1)
0101_1111_0011_0111_0101_1001_1101_1111 The magic number 0x5F3759DF
0100_0000_0010_0111_0101_1001_1101_1111 The result of 0x5F3759DF - (i >> 1)
Interpreting as [[IEEE 754|IEEE]] 32-bit representation:
0_01111100_01000000000000000000000 1.25 × 2<sup>−3</sup>
0_00111110_00100000000000000000000 1.125 × 2<sup>−65</sup>
0_10111110_01101110101100111011111 1.432430... × 2<sup>63</sup>
0_10000000_01001110101100111011111 1.307430... × 2<sup>1</sup>
Reinterpreting this last bit pattern as a floating point number gives the approximation <math>y=2.61486</math>, which has an error of about 3.4%. After one iteration of Newton's method, the final result is <math>y=2.52549</math>, an error of only 0.17%.
:'''Patikrinimas.'''
:<math>x=0.15625.</math>
:Sing: '''0'''011_1110_0010_0000_0000_0000_0000_0000 (1 bitas).
:Exponent: 0'''011_1110_0'''010_0000_0000_0000_0000_0000 (8 bitai).
:Mantissa: 0011_1110_0'''010_0000_0000_0000_0000_0000''' (23 bitai).
:Exponente yra '''01111100'''. Tai yra
:128*0 + 64*1 + 32*1 + 16*1 + 8*1 + 4*1 + 2*0 + 1*0 = 124.
:124-127 = -3. Tada eksponentė yra '''-3'''. 2^(-3) = 0.125.
:Mantisa yra ''''010_0000_0000_0000_0000_0000'''.
:Arba '''101''' = 1 + 0.5*0 + 0.25*1 = '''1.25'''.
:1.25 * 0.125 = 0.15625.
:Visi bitai pastumiami viena bito pozicija į dešinę. Tai tas pats kas padalinti iš dviejų mantisą ir eksponentę. Po pastumimo 32 bitų skaičius tampa:
:0001_1111_0001_0000_0000_0000_0000_0000
:Eksponentė tampa 001_1111_0 arba '''00111110'''. Tai yra 128*0+64*0+32*1+16*1+8*1+4*1+2*1+1*0 = 62.
:62-127 = -65. Padauginus iš 2^(-65) = 2.7105054312137610850186320021749e-20 mantisoje nieko neliks.
:Mantisa tapo 001_0000_0000_0000_0000_0000, kas yra
:1001 = 1 + 0.5*0 + 0.25*0 + 0.125*1 = 1.125.
:1.125 * 2^62 = 5,188,146,770,730,811,392.
:1.125 * 2^(-65) = 3.0493186101154812206459610024467e-20 = 3.0493186101154812206459610024467*10^(-20).
:Vat ir išlindo yla iš maišo. Jei nereikėtų prirašyt priekyje vienetoje mantisoje, o eksponentė butų vienetu didesnė, tai rezultatas būtų
:1001 = 0.5*1 + 0.25*0 + 0.125*0 + 0.0625*1 = 0.5 + 0.0625 = 0.5625. (0.5625*2 = 1.125)
:Eksponentė būtų vienetu didesnė (63 arba -64 po atėmimo 127).
:0.5625 * 2^63 = 5,188,146,770,730,811,392.
:0.5625 * 2^(-64) = 3.0493186101154812206459610024467e-20.
:Vadinasi išekstraktuojant atskirai eksponentę ir mantisą ir pastumus mantisos bitus į dešine viena pozicija, į kairiausį bitą turi įeitį vienetas. O prie eksponentės prisidėti vienetas, jeigu norima turėti tą patį skaičių.
:'''Magiškas skaičius reikalingas šiam darbui.'''
:Magiškas skaičius yra
:0101_1111_0011_0111_0101_1001_1101_1111 The magic number 0x5F3759DF
:Sing: '''0''' (1 bitas).
:Exponent: '''101_1111_0''' (8 bitai).
:Mantissa: '''011_0111_0101_1001_1101_1111''' (23 bitai).
:Eksponentė yra 10111110 = 128 + 0 + 32 + 16 + 8 + 4 + 2 + 0 = 190. Atėmus 127 ji tampa 190-127 = 63.
:Mantisa yra
:011_0111_0101_1001_1101_1111 =
:= 0.5*0 + 0.25*1 + 0.125*1 + 0.0625*0 + 0.03125*1 + 0.015625*1 + 0.0078125*1 + 0.00390625*0 + 0.001953125*1 + 0.0009765625*0 +
:+ 0.00048828125*1 + 0.000244140625*1 + 0.0001220703125*0 + 0.00006103515625*0 + 0.000030517578125*1 + 0.0000152587890625*1 +
:+ 0.00000762939453125*1 + 0.000003814697265625*0 + 0.0000019073486328125*1 + 0.00000095367431640625*1 +
:+ 0.000000476837158203125*1 + 0.0000002384185791015625*1 + 0.00000011920928955078125*1 =
:= 0.431640625 + 0.0007781982421875 + 0.00078868865966796875 + 0.00000083446502685546875 = 0.43320834636688232421875.
:Viso skaičiaus reikšmė yra:
:1.43320834636688232421875 * 2^190 = 2.2490986495375580205008307141844e+57 = 2.2490986495375580205008307141844 * 10^57.
:Arba:
:1.43320834636688232421875 * 2^63 = 13,219,013,784,867,176,448 = 1.3219013784867176448 * 10^19.
:Kaip sakyta, 32 bitų skaičius pastumtas viena bito pozicija į dešinę atimamas iš magiško skaičiaus kaip atiminėjami sveikieji skaičiai.
:0101_1111_0011_0111_0101_1001_1101_1111-
:0001_1111_0001_0000_0000_0000_0000_0000=
:0100_0000_0010_0111_0101_1001_1101_1111.
:Gautas skaičius 0100_0000_0010_0111_0101_1001_1101_1111.
:Sign bit: '''0'''100_0000_0010_0111_0101_1001_1101_1111.
:Exponent: 0'''100_0000_0'''010_0111_0101_1001_1101_1111.
:Mantissa: 0100_0000_0'''010_0111_0101_1001_1101_1111'''.
:Eksponentė yra '''10000000''' = 128. Atėmus 127, eksponentė yra 128-127 = 1.
:Mantisa yra '''010_0111_0101_1001_1101_1111''' =
:= 0.5*0 + 0.25*1 + 0.125*0 + 0.0625*0 + 0.03125*1 + 0.015625*1 + 0.0078125*1 + 0.00390625*0 + 0.001953125*1 + 0.0009765625*0 +
:+ 0.00048828125*1 + 0.000244140625*1 + 0.0001220703125*0 + 0.00006103515625*0 + 0.000030517578125*1 + 0.0000152587890625*1 +
:+ 0.00000762939453125*1 + 0.000003814697265625*0 + 0.0000019073486328125*1 + 0.00000095367431640625*1 +
:+ 0.000000476837158203125*1 + 0.0000002384185791015625*1 + 0.00000011920928955078125*1 =
:= 0.306640625 + 0.0007781982421875 + 0.00001049041748046875 + 0.00000083446502685546875 = 0.30743014812469482421875.
:Gautas skaičius yra:
:1.30743014812469482421875 * 2^1 = 2.6148602962493896484375.
:Arba:
:1.30743014812469482421875 * 2^128 = 4.4489542538766432951275906695431e+38 = 4.4489542538766432951275906695431 * 10^38.
:Toliau tereikia daryti iteracijas pagal formulę:
:y = y * ( threehalfs - ( x2 * y * y ) );
:y_0 = 2.6148602962493896484375. z = x/2 = 0.15625/2 = 0.078125.
:y_1 = y_0 * (1.5 - z * y_0 * y_0) =
:= 2.6148602962493896484375 * (1.5 - 0.078125 * 2.6148602962493896484375 * 2.6148602962493896484375) =
:= '''2.52'''54863388218057175296506574507.
:Tikroji reikšmė:
:1/(0.15625)^0.5 = 2.5298221281347034655991148355462.
:Antra iteracija:
:y_2 = y_1 * (1.5 - z * y_1 * y_1) =
:= 2.5254863388218057175296506574507 * (1.5 - 0.078125 * 2.5254863388218057175296506574507 * 2.5254863388218057175296506574507) =
:= '''2.5298'''109880258619023169570466177. 2.5298109880258619023169570466177
:Trečia iteracija:
:y_3 = y_2 * (1.5 - z * y_2 * y_2) =
:= 2.5298109880258619023169570466177 * (1.5 - 0.078125 * 2.5298109880258619023169570466177^2) =
:= '''2.529822128'''0611201246242590927426. 2.5298221280611201246242590927426
:10 pirmų teisingų skaitmenų (beveik 11).
:Ketvirta iteracija:
:y_4 = y_3 * (1.5 - z * y_3 * y_3) =
:= 2.5298221280611201246242590927426 * (1.5 - 0.078125 * 2.5298221280611201246242590927426^2) =
:= '''2.52982212813470346559'''59044271886.
:21 teisingas skaitmenuo po 4 iteracijų. Tai didesnis tikslumas nei Double precision (64 bits). Maždaug toks tikslumas kaip Double Extended precision (80 bits).
:Darant dalybą ar šaknies traukimą gali prireikti panaikinti eksponentę (padaryti ją lygia nuliui ar vienetui). Tai galima atlikti labai paprastai. Reikia padaryti logišką '''AND''' operaciją skaičiaus
:'''1000,0000,0111,1111,1111,1111,1111,1111''' = '''10000000011111111111111111111111''' su norimu skaičiumi, kaip pvz. '''0011_1110_0010_0000_0000_0000_0000_0000''', kuris yra <math>x=0.15625.</math>
:Po '''AND operacjos''' bus gautas skaičius:
:'''0011_1110_0010_0000_0000_0000_0000_0000''' '''AND'''
:'''1000_0000_0111_1111_1111_1111_1111_1111''' =
:'''0000_0000_0010_0000_0000_0000_0000_0000'''.
:Gauta mantisa 01 = 0.5*0 + 0.25*1 = 0.25. Pridėjus nematomą vienetą priekyje galutinis teisingas skaičius lieka:
:1 + 0.25 = 1.25.
:Eksponentė tampa lygi 0. 2^0 = 1.
:AND operacija veikia tokiu budu:
:1 AND 1 = 1,
:1 AND 0 = 0,
:0 AND 1 = 0,
:0 AND 0 = 0.
:Analogišku budu galima paversti mantisos bitus nuliais ir palikti tik eksponentę, prie kurios paskui galima pridėti arba atimti 8 bitus esančius viena bito pozicija į dešinę nuo kairės. Analogiškai galima panaikinti minuso ženklą su AND operacija. Arba suteikti minuso ženklą pridėjus 32 bitų skaičių '''1000_0000_0000_0000_0000_0000_0000_0000''' prie kokio nors teigiamo 32 bitų skaičiaus (kai pirmas bitas yra 0).
[https://lt.wikibooks.org/wiki/Wikibooks:Knygos/High_Level_Shading_Language High Level Shading Language]
cul2xk0hcxu60ny7u8228980tft76d3
58988
58987
2026-09-03T13:53:01Z
Paraboloid
1294
/* Skaičiavimas inverse square root su C kodu */
58988
wikitext
text/x-wiki
==Dešimtainių skaičių vertimas į dvejetainius skaičius==
[https://www.google.com/search?client=opera&q=single+precision&sourceid=opera&ie=UTF-8&oe=UTF-8&udm=50&fbs=ABfTbFVyMZGZf1hfvX9uKjN_-G8c4u0nXx4bEIpwm1lnNH832VTJOOCxW_fyN-Q_ezyf8gKjm3rhh_G8jdZ2Q6tji4z8Mva6cfvBj5rpPch2IC955IbzrbwHf6tkbFbd-nuFdbKth9Y-58t5LtnYgTA4TWDFYCUNl4d7F9XBAwiEq2T2c7SNgrvMxYiRBXL4fnQnnTOewx28&aep=10&ntc=1&sxsrf=APpeQnvZo3fX2PwO881uSdWsoRELP18NhQ%3A1788348274309&mstk=AUtExfAJ0Kp9BqT3EJbzHOz3MHMalnyXkoOTLvgho5ZQ9lzjrnmmUFCgux_RVe7bouRlyBSGpkUcLpvfZ39N45TUoor6TyyEW7_PpE7eOwP-kU7IFxE6monk-HtsDXkDu7g362AN4NTW3oRjfwn9OtD0BIj2r4QAVauMhDPCIAiWgLimDuate6cf2o6bB5R-6-vzcCqbCju1KJQTdR4HSF9puZ_HCG1hXQ8QaCIqD1LJ_HWonNnZGma6Biu3I1wWFPy6esLnfaKpIX6VFWZsArfQN97XGipwkH7FLKCyZiev5rZBrhE8KincMthP7B9AJDugKLy8qJfORQ7PQR2GslAaCLnkechjBCnXfrmSohwJskbEWU9db6Q279uO4dGu0eI2YUvpEwoQUqkbREqJqrGpJQWFy7WoTzI93_o_2I61PU1FTiuGq-4AVN7erT0WmuWizHDEE2XsTes&aioh=3&csuir=1&atvm=2&mtid=dQeYaumuDL2Ixc8Px6Ts0QE DI atsakymas]
:Single-precision is a 32-bit computer number format that stores fractional and large numbers using a sign bit, an exponent, and a mantissa. Structure of Single-Precision (Binary32) According to Wikipedia, “Single-precision floating-point format (sometimes called FP32, float32, or float) is a computer number format, usually occupying 32 bits in computer memory.” The 32 bits are divided into three specific parts:
*Sign bit (1 bit): Determines if the number is positive (0) or negative (1).
*Biased exponent (8 bits): Stores the magnitude with an excess-127 bias, giving an actual exponent range of -126 to +127.
*Mantissa/Significand (23 explicitly stored bits): Represents the precision digits of the number, with an implicit leading 1 for normalized values.
:Precision and Applications. Decimal Precision: Provides about 7 to 8 decimal digits of accuracy. Most users on StackOverflow agree that “Single precision typically offers 7-8 decimal digits of precision.”
:'''Dešimtainių skaičių vertimas į dvejetainius.'''
:Step-by-Step Conversion Framework.
*Step 1: Determine the Sign Bit (1 bit). If the number is positive, the sign bit is 0. If the number is negative, the sign bit is 1. Example (-12.625): It is negative, so the sign bit is 1.
*Step 2: Convert the Absolute Value to Binary. Separate the number into its integer and fractional parts, convert both to binary, and combine them.
:Integer part '''12''': (12/2 = 6) ('''rem'''ainder 0), (6/2 = 3) (rem 0), (3/2 = 1) (rem 1), (1/2 = 0) (rem 1) <math>\rightarrow </math> '''1100'''.
:Fractional part '''0.625''': (0.625 * 2 = 1.25) (1), (0.25 * 2 = 0.5) (0), (0.5 * 2 = 1.0) (1) <math>\rightarrow </math> '''101'''.
:Example Combined: '''12.625''' = '''1100.101'''.
*Step 3: Normalize the Binary Number. Shift the binary point so that exactly one non-zero digit (which will always be 1) remains to its left. Count how many places you moved the point. This count is your exponent (E).
:Move the point 3 places to the left: '''1100.101''' <math>\rightarrow </math> '''1.100101'''.
:Example Exponent: Because we moved it 3 places, E = 3.
*Step 4: Calculate the Biased Exponent (8 bits) IEEE 754 single-precision uses a bias of 127. Add your exponent E to this bias, and convert the resulting integer to an 8-bit binary number.
:Calculation: 127 + 3 = 130.
:Convert 130 to 8-bit binary: '''130''' = '''10000010'''.
*Step 5: Extract the Mantissa/Significand (23 bits).
:Take the fractional bits from your normalized number (everything to the right of the binary point). Drop the leading 1. If the bits are fewer than 23, pad the right side with zeros until you reach exactly 23 bits.
:Normalized bits: 1.100101 <math>\rightarrow </math> Drop the ''1.'' (atmesti kairiausią vienetą ir tašką po jo) to get '''100101'''.
:Example Pad to 23 bits: 10010100000000000000000.
:'''Final Assembly.'''
:Combine the three components in order: Sign (1 bit) + Exponent (8 bits) + Mantissa (23 bits).
:Component_____________Bits______________Value for -12.625_______
:Sign____________________1_______________________1______________
:Exponent________________8____________________10000010__________
:Mantissa________________23______________10010100000000000000000
*Final 32-bit Binary String: '''11000001010010100000000000000000'''.
*Hexadecimal Representation: '''C1450000'''.
:Sign: '''1'''1000001010001010000000000000000.
:Exponent: 1'''10000010'''10001010000000000000000.
:Mantissa: 110000010'''10010100000000000000000'''.
:Patikrinimas (-12.625).
:Exponent: 10000010 = 128*1 + 64*0 + 32*0 + 16*0 + 8*0 + 4*0 + 2*1 +1*0 = 130. 130-127 = 3. 2^3 = 8.
:Mantissa: 100101 = 0.5*1 + 0.25*0 + 0.125*0 + 0.0625*1 + 0.03125*0 + 0.015625*1 + 0.0078125*0 = 0.578125.
:8 * 0.578125 = 4.625.
:8 * 1 = 8.
:8 + 4.625 = 12.625.
:Reikia gražinti paimtą vienetą priekyje ('''12.625''' = '''1100.101'''; '''1100.101''' <math>\rightarrow </math> '''1.100101'''):
:8 * (1 + 0.578125) = 8 * 1.578125 = 12.625.
:-12.625 = -1.2625 * 10^1.
:Čia mantisa 0.2625, o ekspontentė 1 dešimtainėje sistemoje. Skačių 0.2625 reikia kaskart dauginti iš 2.
:0.2625*2 = 0.525 (ne vienetas, reiškia pirmas skaitmuo 0),
:0.525*2 = 1.05 (vienetas, reiškia antras skaitmuo 1),
:0.05*2 = 0.1 (ne vienetas, reiškia trečias skaitmuo 0),
:0.1*2 = 0.2 (ne vienetas, reiškia ketvirtas skaitmuo 0),
:0.2*2 = 0.4 (ne vienetas, reiškia penktas skaitmuo 0),
:0.4*2 = 0.8 (ne vienetas, reiškia šeštas skaitmuo 0),
:0.8*2 = 1.6 (vienetas, reiškia septintas skaitmuo 1),
:0.6*2 = 1.2 (vienetas, reiškia aštuntas skaitmuo 1),
:0.2*2 = 0.4 (ne vienetas, reiškia devintas skaitmuo 0),
:0.4*2 = 0.8 (ne vienetas, reiškia dešimtas skaitmuo 0),
:0.8*2 = 1.6 (vienetas, reiškia vienuoliktas skaitmuo 1),
:0.6*2 = 1.2 (vienetas, reiškia dviliktas skaitmuo 1),
:0.2*2 = 0.4 (ne vienetas, reiškia tryliktas skaitmuo 0),
:0.4*2 = 0.8 (ne vienetas, reiškia keturioliktas skaitmuo 0),
:0.8*2 = 1.6 (vienetas, reiškia penkioliktas skaitmuo 1),
:0.6*2 = 1.2 (vienetas, reiškia šešioliktas skaitmuo 1).
:Tada galutinis skaičius '''0.2625''' yra toks:
:0.0100001100110011.
:Kad gauti didesnį tikslumą, procesą reikia kartoti begalo arba iki reikiamo tikslumo.
:Skaičiau '''0.2625''' reikšmė yra:
:0.0100001100110011 =
:= 0.5*0 + 0.25*1 + 0.125*0 + 0.0625*0 + 0.03125*0 + 0.015625*0 + 0.0078125*1 + 0.00390625*1 + 0.001953125*0 + 0.0009765625*0 +
:+ 0.00048828125*1 + 0.000244140625*1 + 0.0001220703125*0 + 0.00006103515625*0 + 0.000030517578125*1 + 0.0000152587890625*1 =
:= 0.26171875 + 0.0007781982421875 = '''0.26249'''69482421875.
:Taigi, 0.26249 labai panašus į 0.2625.
:Vadinasi '''1.2625''' dvejetainėje sistemoje apytiksliai yra '''1.0100001100110011'''.
:Eksponentę 10 reikia versti taip:
:10 = 8 + 2. Tada 10 dvejetainėje sistemoje yra 00001010 (1*0 + 2*1 + 4*0 + 8*1 + 0 + 0 + 0 + 0 = 10).
:Bet eksponentė single precision formate gali būti tik, 0, 1, 2, 4, 8, 16, 32, 64, 128 ir taip toliau.
:Arba reikia daryti taip:
:10/2 = 5 (rem 0),
:5/2 = 2 (rem 1),
:2/2 = 1 (rem 0)
:1/2 = 0.5 (rem 1).
:Va štai šitaip ir gaunamas skaičius 10. Tai yra 1010.
:Skaičius 1010 pakeičiamas skaičiu 1.010 su eksponente 3 (2^3 = 8).
:Tada skaičius 1.010 iškoduojamas taip:
:1 + 0.5*0 + 0.25*1 + 0.125*0 = 1.25.
:Padauginama iš dviejų pakelta eksponente 3:
:1.25 * 2^3 = 1.25 * 8 = 10.
:Tuomet
:1.2625 * 10 = 12.625.
:'''Grįžimas prie pavyzdžio.'''
:Patikrinimas (-12.625).
:Exponent: 10000010 = 128*1 + 64*0 + 32*0 + 16*0 + 8*0 + 4*0 + 2*1 +1*0 = 130. 130-127 = 3. 2^3 = 8.
:Skaičiaus 1100.101 kablelį galima pastumti 4 pozicijom į kairę ir eksponentę duoti 4. Mantisa tada yra 0.1100101, o eksponentė yra 4.
:0.5*1 + 0.25*1 + 0.125*0 + 0.0625*0 + 0.03125*1 + 0.015625*0 + 0.0078125*1 = 0.7890625.
:2^4 * 0.7890625 = 16 * 0.7890625 = '''12.625'''.
:Bandomas kitas skaičius 24:
:24/2 = 12 (rem 0),
:12/2 = 6 (rem 0),
:6/2 = 3 (rem 0),
:3/2 = 1 (rem 1),
:1/2 = 0.5 (rem 1).
:Reiškia 24 yra 11000 (16*1 + 8*1 + 4*0 + 2*0 + 1*0 = 24).
:Bandomas kitas skaičius 19:
:19/2 = 9 (rem 1),
:9/2 = 4 (rem 1),
:4/2 = 2 (rem 0),
:2/2 = 1 (rem 0),
:1/2 = 0.5 (rem 1).
:Reiškia 19 yra 10011 (16*1 + 8*0 + 4*0 + 2*1 + 1*1 = 19).
:Bandomas skaičius 22:
:22/2 = 11 (rem 0),
:11/2 = 5 (rem 1),
:5/2 = 2 (rem 1),
:2/2 = 1 (rem 0),
:1/2 = 0.5 (rem 1).
:Reiškia 22 yra 10110 (16*1 + 8*0 + 4*1 + 2*1 + 1*0 = 16+4+2 = 22).
:Trumpas paaiškinimas kodėl eksponentė saugoma formate nuo 1 iki 254, pridedant 127 prie -126 ir iki 127. Tai greičiausia yra todėl, kad sudedant single precision skaičių tokiame formate kokiame jis yra, jo reiikšmė gali būti gana tiksliai traktuojama kaip sveikojo skaičiaus reikšmė. Su kai kuriais pakeitimais.
:'''-12.625''' yra '''11000001010010100000000000000000'''.
:Pridėjus 127 ('''01111111''') prie eksponentės 3 ('''00000011''') gauname 130 ('''10000010'''):
:'''00000011'''+
:'''01111111'''=
:'''10000010'''.
:Vadinasi tada skaičius '''-12.625''' tampa
:Mantissa: 1100101 = 1 + 0.5*1 + 0.25*0 + 0.125*0 + 0.0625*1 + 0.03125*0 + 0.015625*1 + 0.0078125*0 = 1.578125;
:2^130 = 1.3611294676837538538534984297271e+39 = 1.3611294676837538538534984297271 * 10^39.
:O sveikasis skaičius '''11000001010010100000000000000000''' be minuso yra '''01000001010010100000000000000000''' ir užrašomas taip:
:1*0 + 2*0 + 4*0 + 8*0 + 16*0 + 32*0 + 64*0 + 128*0 + 256*0 + 512*0 + 1024*0 +
:+ 2048*0 + 4096*0 + 8192*0 + 16,384*0 + 32,768*0 + 65,536*0 + 131,072*0 +
:+ 262,144*1 + 524,288*0 + 1,048,576*1 + 2,097,152*0 + 4,194,304*0 + 8,388,608*1 + 16,777,216*0 + 33,554,432*1 +
:+ 67,108,864*0 + 134,217,728*0 + 268,435,456*0 + 536,870,912*0 + 1,073,741,824*0 +
:+ 2,147,483,648*1 + 4,294,967,296*0 =
:= 0 + 0 + 43,253,760 + 0 + 2,147,483,648 = 2,190,737,408.
:Kažka supainiojau. Atrodė, kad eksponentė beveik tas pats kas didesni skaičiai priekyje.
==Skaičiavimas inverse square root su C kodu==
:Čia https://en.wikipedia.org/wiki/Fast_inverse_square_root aiškinama kaip naudojant sveikuosius skaičius galima apsakičiuoti <math>\frac{1}{\sqrt{x}}.</math>
:"The fast inverse square generates a good approximation through integer operations by adding and subtracting the integer form of floating-point numbers, and taking a square root by dividing by two (which is just a right-shift)."
:Iš čia https://lt.wikibooks.org/wiki/Sekos_riba#Greitas_šaknies_iš_skaičiaus_a_traukimo_būdas gauta formulė
:<math>y_{n+1} = \frac{y_{n}\left(3-xy_n^2\right)}{2}. \quad (4)</math>
:<math>y_n\approx \frac{1}{\sqrt{x}}.</math>
:Ją dar galima pagreitint, pakeitus z = x/2. Tada ši formulė tampa tokia:
:<math>y_{n+1} = y_{n}\left(1.5 - zy_n^2\right). \quad (4.1)</math>
:Programavimo kalbos C kodas skaičiuoti <math>\frac{1}{\sqrt{x}}</math> yra toks:
<syntaxhighlight lang="c">
float Q_rsqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = * ( long * ) &y; // evil floating point bit level hacking
i = 0x5f3759df - ( i >> 1 ); // what the fuck?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
return y;
}
</syntaxhighlight>
:Šito kodo paaiškinimas yra toks:
:Skaičius '''i''' yra ''long integer'' (32 bitų sveikasis skaičius, https://en.wikipedia.org/wiki/C_data_types).
:Skaičiai '''x2''' ir '''y''' yra floating point skaičiai (32 bitų arba 64 bitų). Jeigu 32 bitų, tai tada tai yra single precision 32 bitų float skaičiai.
:Konstanta threehalfs = 1.5F yra 32 bitų single precision skaičius 1.5.
:Skaičius '''number''' yra 32 bitų single precision float ir paduodamas funkcijai. Kitaip tariant '''number''' yra '''x''', o '''y''' bus <math>y\approx \frac{1}{\sqrt{x}}.</math>
:'''x2''' yra '''number'''*0.5 = z.
:Eilutė
i = * ( long * ) &y;
:paverčia ''floating point number'' '''y''' į ''long integer number'' '''i'''. Dabar i yra toks pat kaip y, tik laikomas kaip sveikasis skaičius, o ne slankaus kablelio skaičius. Simbolis * yra pointer to memory address, skirtas įdėti į tą adresą kažką, o ženklas & skirtas paemimui iš tam tikro RAM adreso (arba atvirkščiai, * paėmimui, o & įdėjimui, gerai neatsimenu).
:Todėl ši eilutė gali būti suprantama kaip
:( long * ) &y
:paimti iš y RAM adreso y reikšmę ir įdėti į ''long integer'' (kol kas be pavadinimo) RAM adresą.
:Paskui iš to ''long integer'' RAM adreso įdėti į sveikojo skaičiaus '''i''' RAM adresą (ši kodo dalis "i = *"). Kaip sakyta, iš esmės floating number '''y''' paverčiamas į long integer number '''i'''.
:Šito kodo paaiškinimas yra toks:
:Skaičius '''i''' yra ''long integer'' (32 bitų sveikasis skaičius, https://en.wikipedia.org/wiki/C_data_types).
:Skaičiai '''x2''' ir '''y''' yra floating point skaičiai (32 bitų arba 64 bitų). Jeigu 32 bitų, tai tada tai yra single precision 32 bitų float skaičiai.
:Konstanta threehalfs = 1.5F yra 32 bitų single precision skaičius 1.5.
:Skaičius '''number''' yra 32 bitų single precision float ir paduodamas funkcijai. Kitaip tariant '''number''' yra '''x''', o '''y''' bus <math>y\approx \frac{1}{\sqrt{x}}.</math>
:'''x2''' yra '''number'''*0.5 = z.
:Eilutė
i = * ( long * ) &y;
:paverčia ''floating point number'' '''y''' į ''long integer number'' '''i'''. Dabar i yra toks pat kaip y, tik laikomas kaip sveikasis skaičius, o ne slankaus kablelio skaičius. Simbolis * yra pointer to memory address, skirtas įdėti į tą adresą kažką, o ženklas & skirtas paemimui iš tam tikro RAM adreso (arba atvirkščiai, * paėmimui, o & įdėjimui, gerai neatsimenu).
:Todėl ši eilutė gali būti suprantama kaip
:( long * ) &y
:paimti iš y RAM adreso y reikšmę ir įdėti į ''long integer'' (kol kas be pavadinimo) RAM adresą.
:Paskui iš to ''long integer'' RAM adreso įdėti į sveikojo skaičiaus '''i''' RAM adresą (ši kodo dalis "i = *"). Kaip sakyta, iš esmės floating number '''y''' paverčiamas į long integer number '''i'''.
:Toliau eilutė
i = 0x5f3759df - ( i >> 1 );
:reiškia pastumti sveikąjį skaičių '''i''' viena pozicija į dešinę ir paskui atimti iš sveikojo skaičiaus 0x5f3759df ir rezultatą įdėti į skaičiaus '''i''' adresą. Skaičius 5f3759df turi 8 hexodecimal skaitmenis. Vienas heksodecimal skaitmuo sudaro 4 bitus.
:5 yra 0101, f yra 1111, 3 yra 0011, 7 yra 0111, 5 yra 0101, 9 yra 1001, d yra 1101 (nes A yra 1010, B yra 1011, C yra 1100), f yra 1111. Todėl
:5F3759DFh = 0101,1111,0011,0111,0101,1001,1101,1111;
:5F3759DFh = 01011111001101110101100111011111.
:Gale raidė h reiškia, kad tai hexodecimal skaičius.
:Ši eilutė:
y = * ( float * ) &i;
:paverčia long int '''i''' į float, o paskui tą float perkelią į '''y'''.
:Toliau daromos Niutono iteracijos:
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
:čia y jau turi apytikslią reikšmę <math>\frac{1}{\sqrt{\text{number}}}.</math>
===Worked example===
As an example, the number <math>x=0.15625</math> can be used to calculate <math display=inline>\frac{1}{\sqrt{x}} \approx 2.52982</math>. The first steps of the algorithm are illustrated below:
0011_1110_0010_0000_0000_0000_0000_0000 Bit pattern of both x and i
0001_1111_0001_0000_0000_0000_0000_0000 Shift right one position: (i >> 1)
0101_1111_0011_0111_0101_1001_1101_1111 The magic number 0x5F3759DF
0100_0000_0010_0111_0101_1001_1101_1111 The result of 0x5F3759DF - (i >> 1)
Interpreting as [[IEEE 754|IEEE]] 32-bit representation:
0_01111100_01000000000000000000000 1.25 × 2<sup>−3</sup>
0_00111110_00100000000000000000000 1.125 × 2<sup>−65</sup>
0_10111110_01101110101100111011111 1.432430... × 2<sup>63</sup>
0_10000000_01001110101100111011111 1.307430... × 2<sup>1</sup>
Reinterpreting this last bit pattern as a floating point number gives the approximation <math>y=2.61486</math>, which has an error of about 3.4%. After one iteration of Newton's method, the final result is <math>y=2.52549</math>, an error of only 0.17%.
:'''Patikrinimas.'''
:<math>x=0.15625.</math>
:Sing: '''0'''011_1110_0010_0000_0000_0000_0000_0000 (1 bitas).
:Exponent: 0'''011_1110_0'''010_0000_0000_0000_0000_0000 (8 bitai).
:Mantissa: 0011_1110_0'''010_0000_0000_0000_0000_0000''' (23 bitai).
:Exponente yra '''01111100'''. Tai yra
:128*0 + 64*1 + 32*1 + 16*1 + 8*1 + 4*1 + 2*0 + 1*0 = 124.
:124-127 = -3. Tada eksponentė yra '''-3'''. 2^(-3) = 0.125.
:Mantisa yra ''''010_0000_0000_0000_0000_0000'''.
:Arba '''101''' = 1 + 0.5*0 + 0.25*1 = '''1.25'''.
:1.25 * 0.125 = 0.15625.
:Visi bitai pastumiami viena bito pozicija į dešinę. Tai tas pats kas padalinti iš dviejų mantisą ir eksponentę. Po pastumimo 32 bitų skaičius tampa:
:0001_1111_0001_0000_0000_0000_0000_0000
:Eksponentė tampa 001_1111_0 arba '''00111110'''. Tai yra 128*0+64*0+32*1+16*1+8*1+4*1+2*1+1*0 = 62.
:62-127 = -65. Padauginus iš 2^(-65) = 2.7105054312137610850186320021749e-20 mantisoje nieko neliks.
:Mantisa tapo 001_0000_0000_0000_0000_0000, kas yra
:1001 = 1 + 0.5*0 + 0.25*0 + 0.125*1 = 1.125.
:1.125 * 2^62 = 5,188,146,770,730,811,392.
:1.125 * 2^(-65) = 3.0493186101154812206459610024467e-20 = 3.0493186101154812206459610024467*10^(-20).
:Vat ir išlindo yla iš maišo. Jei nereikėtų prirašyt priekyje vienetoje mantisoje, o eksponentė butų vienetu didesnė, tai rezultatas būtų
:1001 = 0.5*1 + 0.25*0 + 0.125*0 + 0.0625*1 = 0.5 + 0.0625 = 0.5625. (0.5625*2 = 1.125)
:Eksponentė būtų vienetu didesnė (63 arba -64 po atėmimo 127).
:0.5625 * 2^63 = 5,188,146,770,730,811,392.
:0.5625 * 2^(-64) = 3.0493186101154812206459610024467e-20.
:Vadinasi išekstraktuojant atskirai eksponentę ir mantisą ir pastumus mantisos bitus į dešine viena pozicija, į kairiausį bitą turi įeitį vienetas. O prie eksponentės prisidėti vienetas, jeigu norima turėti tą patį skaičių.
:'''Magiškas skaičius reikalingas šiam darbui.'''
:Magiškas skaičius yra
:0101_1111_0011_0111_0101_1001_1101_1111 The magic number 0x5F3759DF
:Sing: '''0''' (1 bitas).
:Exponent: '''101_1111_0''' (8 bitai).
:Mantissa: '''011_0111_0101_1001_1101_1111''' (23 bitai).
:Eksponentė yra 10111110 = 128 + 0 + 32 + 16 + 8 + 4 + 2 + 0 = 190. Atėmus 127 ji tampa 190-127 = 63.
:Mantisa yra
:011_0111_0101_1001_1101_1111 =
:= 0.5*0 + 0.25*1 + 0.125*1 + 0.0625*0 + 0.03125*1 + 0.015625*1 + 0.0078125*1 + 0.00390625*0 + 0.001953125*1 + 0.0009765625*0 +
:+ 0.00048828125*1 + 0.000244140625*1 + 0.0001220703125*0 + 0.00006103515625*0 + 0.000030517578125*1 + 0.0000152587890625*1 +
:+ 0.00000762939453125*1 + 0.000003814697265625*0 + 0.0000019073486328125*1 + 0.00000095367431640625*1 +
:+ 0.000000476837158203125*1 + 0.0000002384185791015625*1 + 0.00000011920928955078125*1 =
:= 0.431640625 + 0.0007781982421875 + 0.00078868865966796875 + 0.00000083446502685546875 = 0.43320834636688232421875.
:Viso skaičiaus reikšmė yra:
:1.43320834636688232421875 * 2^190 = 2.2490986495375580205008307141844e+57 = 2.2490986495375580205008307141844 * 10^57.
:Arba:
:1.43320834636688232421875 * 2^63 = 13,219,013,784,867,176,448 = 1.3219013784867176448 * 10^19.
:Kaip sakyta, 32 bitų skaičius pastumtas viena bito pozicija į dešinę atimamas iš magiško skaičiaus kaip atiminėjami sveikieji skaičiai.
:0101_1111_0011_0111_0101_1001_1101_1111-
:0001_1111_0001_0000_0000_0000_0000_0000=
:0100_0000_0010_0111_0101_1001_1101_1111.
:Gautas skaičius 0100_0000_0010_0111_0101_1001_1101_1111.
:Sign bit: '''0'''100_0000_0010_0111_0101_1001_1101_1111.
:Exponent: 0'''100_0000_0'''010_0111_0101_1001_1101_1111.
:Mantissa: 0100_0000_0'''010_0111_0101_1001_1101_1111'''.
:Eksponentė yra '''10000000''' = 128. Atėmus 127, eksponentė yra 128-127 = 1.
:Mantisa yra '''010_0111_0101_1001_1101_1111''' =
:= 0.5*0 + 0.25*1 + 0.125*0 + 0.0625*0 + 0.03125*1 + 0.015625*1 + 0.0078125*1 + 0.00390625*0 + 0.001953125*1 + 0.0009765625*0 +
:+ 0.00048828125*1 + 0.000244140625*1 + 0.0001220703125*0 + 0.00006103515625*0 + 0.000030517578125*1 + 0.0000152587890625*1 +
:+ 0.00000762939453125*1 + 0.000003814697265625*0 + 0.0000019073486328125*1 + 0.00000095367431640625*1 +
:+ 0.000000476837158203125*1 + 0.0000002384185791015625*1 + 0.00000011920928955078125*1 =
:= 0.306640625 + 0.0007781982421875 + 0.00001049041748046875 + 0.00000083446502685546875 = 0.30743014812469482421875.
:Gautas skaičius yra:
:1.30743014812469482421875 * 2^1 = 2.6148602962493896484375.
:Arba:
:1.30743014812469482421875 * 2^128 = 4.4489542538766432951275906695431e+38 = 4.4489542538766432951275906695431 * 10^38.
:Toliau tereikia daryti iteracijas pagal formulę:
:y = y * ( threehalfs - ( x2 * y * y ) );
:y_0 = 2.6148602962493896484375. z = x/2 = 0.15625/2 = 0.078125.
:y_1 = y_0 * (1.5 - z * y_0 * y_0) =
:= 2.6148602962493896484375 * (1.5 - 0.078125 * 2.6148602962493896484375 * 2.6148602962493896484375) =
:= '''2.52'''54863388218057175296506574507.
:Tikroji reikšmė:
:1/(0.15625)^0.5 = 2.5298221281347034655991148355462.
:Antra iteracija:
:y_2 = y_1 * (1.5 - z * y_1 * y_1) =
:= 2.5254863388218057175296506574507 * (1.5 - 0.078125 * 2.5254863388218057175296506574507 * 2.5254863388218057175296506574507) =
:= '''2.5298'''109880258619023169570466177. 2.5298109880258619023169570466177
:Trečia iteracija:
:y_3 = y_2 * (1.5 - z * y_2 * y_2) =
:= 2.5298109880258619023169570466177 * (1.5 - 0.078125 * 2.5298109880258619023169570466177^2) =
:= '''2.529822128'''0611201246242590927426. 2.5298221280611201246242590927426
:10 pirmų teisingų skaitmenų (beveik 11).
:Ketvirta iteracija:
:y_4 = y_3 * (1.5 - z * y_3 * y_3) =
:= 2.5298221280611201246242590927426 * (1.5 - 0.078125 * 2.5298221280611201246242590927426^2) =
:= '''2.52982212813470346559'''59044271886.
:21 teisingas skaitmenuo po 4 iteracijų. Tai didesnis tikslumas nei Double precision (64 bits). Maždaug toks tikslumas kaip Double Extended precision (80 bits).
:Darant dalybą ar šaknies traukimą gali prireikti panaikinti eksponentę (padaryti ją lygia nuliui ar vienetui). Tai galima atlikti labai paprastai. Reikia padaryti logišką '''AND''' operaciją skaičiaus
:'''1000,0000,0111,1111,1111,1111,1111,1111''' = '''10000000011111111111111111111111''' su norimu skaičiumi, kaip pvz. '''0011_1110_0010_0000_0000_0000_0000_0000''', kuris yra <math>x=0.15625.</math>
:Po '''AND operacjos''' bus gautas skaičius:
:'''0011_1110_0010_0000_0000_0000_0000_0000''' '''AND'''
:'''1000_0000_0111_1111_1111_1111_1111_1111''' =
:'''0000_0000_0010_0000_0000_0000_0000_0000'''.
:Gauta mantisa 01 = 0.5*0 + 0.25*1 = 0.25. Pridėjus nematomą vienetą priekyje galutinis teisingas skaičius lieka:
:1 + 0.25 = 1.25.
:Eksponentė tampa lygi 0. 2^0 = 1.
:AND operacija veikia tokiu budu:
:1 AND 1 = 1,
:1 AND 0 = 0,
:0 AND 1 = 0,
:0 AND 0 = 0.
:Analogišku budu galima paversti mantisos bitus nuliais ir palikti tik eksponentę, prie kurios paskui galima pridėti arba atimti 8 bitus esančius viena bito pozicija į dešinę nuo kairės. Analogiškai galima panaikinti minuso ženklą su AND operacija. Arba suteikti minuso ženklą pridėjus 32 bitų skaičių '''1000_0000_0000_0000_0000_0000_0000_0000''' prie kokio nors teigiamo 32 bitų skaičiaus (kai pirmas bitas yra 0).
==Kaip FPU galėtų apseit be barrel shifters sudedant skaičius su skirtingom eksponentėm==
:https://en.wikipedia.org/wiki/Barrel_shifter
:Barrel Shifter gali stumti pavyzdžiui 32 bito skaičiaus bitus į kairę ar į dešinę ne per vieną bito poziciją, bet per kelias kaip, kad per dvi bito pozicijas ar per 4 bito pozicijas ar per 8 bito pozicijas.
:Sudedant 32 bitų single precision skaičius su skirtingomis eksponentėmis, mažesnio skaičiaus mantisos bitai turi būti pastumti į dešinę per tiek pozicijų koks yra tu dviejų skaičių eksponenčių skirtumas, atėmus eksponentę mažesnio skaičiaus iš eksponentės didesnio skaičiaus.
:Be barrel shifter dviejų 32 bitų floating point skaičių sudėtį su skirtingomis eksponentėmis galima atlikti pakeitus mažesnio skaičiaus eksponentę į denormal ir padauginus tą mažesnį skaičių iš skaičiaus, kurio fractional part yra vienetas (visa mantisa lygi nuliui, jeigu be nematomo vieneto) o eksponentė yra neigiamas skaičius gautas atėmus didesnio 32 bitų float skaičiaus eksponentę iš mažesnio 32 bitų float skaičiaus eksponentės. Tada šio skaičiaus eksponentė bus neigiama ir ją padauginus iš paversto į denormal mažesniojo skaičiaus, bus gautas rezultatas, kad mažesnio skaičiaus mantisa bus pastumta į dešinę tiek pozicijų koks yra tos neigiamos eksponentės skaičiaus modulis.
:Bet turbūt vis tiek reikės šiftinti mantisos bitus į dešinę, kad paversti mažesnio 32 bitų skaičiaus mantisą kaip pas denormal skaičius pastumta atitinkama bitų skaičių į dešinę, kad paskui pridėti gautą mantisą prie didesnio skaičiaus mantios, ir eksponentę po sudeties palikti didesnio skaičiaus, jeigu ji nepakils vienetu dėl sudeties.
:Tai tiesiog čia kaip veikia skaičių sudėtis su skirtingom eksponentėm. Buvau pagalvojęs, kad galima apseiti be barrel shifter, bet pasirodo, kad ne. Arba reikia šiftinti po vieną bitą (jeigu nėra barrel shifter circuit), kas gali pareikalauti nemažai laiko, jeigu sudedamų skaičių eksponentės stipriai skiriasi.
:Todėl iš esmės sudėtis gali būti ilgesnė nei daugyba net su barrel shifter, nes daugyba su padaryta schema galinčia padauginti mantisas iš vieno ciklo, bus daug greitesnė. Ten iš esmės ta daugybos schema turėtų ir užimti didžiausią dalį FPU. Senesni FPU daugino iš daug ciklų, nes negalėjo sau leisti daug transistorių daugybos transistorių schemai. Maždaug Pentium procesoriai pradėjo dauginti iš vieno ciklo, jei neskaičiuoti visokių įkrovimo, užkrovimo, išėmimo operacijų dviejų dauginamų skaičių.
[https://lt.wikibooks.org/wiki/Wikibooks:Knygos/High_Level_Shading_Language High Level Shading Language]
mdwfudtw0jeol1u2pp2ayeyjuhypiaf
58989
58988
2026-09-04T05:10:57Z
Paraboloid
1294
/* Dešimtainių skaičių vertimas į dvejetainius skaičius */
58989
wikitext
text/x-wiki
==Dešimtainių skaičių vertimas į dvejetainius skaičius==
[https://www.google.com/search?client=opera&q=single+precision&sourceid=opera&ie=UTF-8&oe=UTF-8&udm=50&fbs=ABfTbFVyMZGZf1hfvX9uKjN_-G8c4u0nXx4bEIpwm1lnNH832VTJOOCxW_fyN-Q_ezyf8gKjm3rhh_G8jdZ2Q6tji4z8Mva6cfvBj5rpPch2IC955IbzrbwHf6tkbFbd-nuFdbKth9Y-58t5LtnYgTA4TWDFYCUNl4d7F9XBAwiEq2T2c7SNgrvMxYiRBXL4fnQnnTOewx28&aep=10&ntc=1&sxsrf=APpeQnvZo3fX2PwO881uSdWsoRELP18NhQ%3A1788348274309&mstk=AUtExfAJ0Kp9BqT3EJbzHOz3MHMalnyXkoOTLvgho5ZQ9lzjrnmmUFCgux_RVe7bouRlyBSGpkUcLpvfZ39N45TUoor6TyyEW7_PpE7eOwP-kU7IFxE6monk-HtsDXkDu7g362AN4NTW3oRjfwn9OtD0BIj2r4QAVauMhDPCIAiWgLimDuate6cf2o6bB5R-6-vzcCqbCju1KJQTdR4HSF9puZ_HCG1hXQ8QaCIqD1LJ_HWonNnZGma6Biu3I1wWFPy6esLnfaKpIX6VFWZsArfQN97XGipwkH7FLKCyZiev5rZBrhE8KincMthP7B9AJDugKLy8qJfORQ7PQR2GslAaCLnkechjBCnXfrmSohwJskbEWU9db6Q279uO4dGu0eI2YUvpEwoQUqkbREqJqrGpJQWFy7WoTzI93_o_2I61PU1FTiuGq-4AVN7erT0WmuWizHDEE2XsTes&aioh=3&csuir=1&atvm=2&mtid=dQeYaumuDL2Ixc8Px6Ts0QE DI atsakymas]
:Single-precision is a 32-bit computer number format that stores fractional and large numbers using a sign bit, an exponent, and a mantissa. Structure of Single-Precision (Binary32) According to Wikipedia, “Single-precision floating-point format (sometimes called FP32, float32, or float) is a computer number format, usually occupying 32 bits in computer memory.” The 32 bits are divided into three specific parts:
*Sign bit (1 bit): Determines if the number is positive (0) or negative (1).
*Biased exponent (8 bits): Stores the magnitude with an excess-127 bias, giving an actual exponent range of -126 to +127.
*Mantissa/Significand (23 explicitly stored bits): Represents the precision digits of the number, with an implicit leading 1 for normalized values.
:Precision and Applications. Decimal Precision: Provides about 7 to 8 decimal digits of accuracy. Most users on StackOverflow agree that “Single precision typically offers 7-8 decimal digits of precision.”
:'''Dešimtainių skaičių vertimas į dvejetainius.'''
:Step-by-Step Conversion Framework.
*Step 1: Determine the Sign Bit (1 bit). If the number is positive, the sign bit is 0. If the number is negative, the sign bit is 1. Example (-12.625): It is negative, so the sign bit is 1.
*Step 2: Convert the Absolute Value to Binary. Separate the number into its integer and fractional parts, convert both to binary, and combine them.
:Integer part '''12''': (12/2 = 6) ('''rem'''ainder 0), (6/2 = 3) (rem 0), (3/2 = 1) (rem 1), (1/2 = 0) (rem 1) <math>\rightarrow </math> '''1100'''.
:Fractional part '''0.625''': (0.625 * 2 = 1.25) (1), (0.25 * 2 = 0.5) (0), (0.5 * 2 = 1.0) (1) <math>\rightarrow </math> '''101'''.
:Example Combined: '''12.625''' = '''1100.101'''.
*Step 3: Normalize the Binary Number. Shift the binary point so that exactly one non-zero digit (which will always be 1) remains to its left. Count how many places you moved the point. This count is your exponent (E).
:Move the point 3 places to the left: '''1100.101''' <math>\rightarrow </math> '''1.100101'''.
:Example Exponent: Because we moved it 3 places, E = 3.
*Step 4: Calculate the Biased Exponent (8 bits) IEEE 754 single-precision uses a bias of 127. Add your exponent E to this bias, and convert the resulting integer to an 8-bit binary number.
:Calculation: 127 + 3 = 130.
:Convert 130 to 8-bit binary: '''130''' = '''10000010'''.
*Step 5: Extract the Mantissa/Significand (23 bits).
:Take the fractional bits from your normalized number (everything to the right of the binary point). Drop the leading 1. If the bits are fewer than 23, pad the right side with zeros until you reach exactly 23 bits.
:Normalized bits: 1.100101 <math>\rightarrow </math> Drop the ''1.'' (atmesti kairiausią vienetą ir tašką po jo) to get '''100101'''.
:Example Pad to 23 bits: 10010100000000000000000.
:'''Final Assembly.'''
:Combine the three components in order: Sign (1 bit) + Exponent (8 bits) + Mantissa (23 bits).
:Component_____________Bits______________Value for -12.625_______
:Sign____________________1_______________________1______________
:Exponent________________8____________________10000010__________
:Mantissa________________23______________10010100000000000000000
*Final 32-bit Binary String: '''11000001010010100000000000000000'''.
*Hexadecimal Representation: '''C1450000'''.
:Sign: '''1'''1000001010001010000000000000000.
:Exponent: 1'''10000010'''10001010000000000000000.
:Mantissa: 110000010'''10010100000000000000000'''.
:Patikrinimas (-12.625).
:Exponent: 10000010 = 128*1 + 64*0 + 32*0 + 16*0 + 8*0 + 4*0 + 2*1 +1*0 = 130. 130-127 = 3. 2^3 = 8.
:Mantissa: 100101 = 0.5*1 + 0.25*0 + 0.125*0 + 0.0625*1 + 0.03125*0 + 0.015625*1 + 0.0078125*0 = 0.578125.
:8 * 0.578125 = 4.625.
:8 * 1 = 8.
:8 + 4.625 = 12.625.
:Reikia gražinti paimtą vienetą priekyje ('''12.625''' = '''1100.101'''; '''1100.101''' <math>\rightarrow </math> '''1.100101'''):
:8 * (1 + 0.578125) = 8 * 1.578125 = 12.625.
:-12.625 = -1.2625 * 10^1.
:Čia mantisa 0.2625, o ekspontentė 1 dešimtainėje sistemoje. Skačių 0.2625 reikia kaskart dauginti iš 2.
:0.2625*2 = 0.525 (ne vienetas, reiškia pirmas skaitmuo 0),
:0.525*2 = 1.05 (vienetas, reiškia antras skaitmuo 1),
:0.05*2 = 0.1 (ne vienetas, reiškia trečias skaitmuo 0),
:0.1*2 = 0.2 (ne vienetas, reiškia ketvirtas skaitmuo 0),
:0.2*2 = 0.4 (ne vienetas, reiškia penktas skaitmuo 0),
:0.4*2 = 0.8 (ne vienetas, reiškia šeštas skaitmuo 0),
:0.8*2 = 1.6 (vienetas, reiškia septintas skaitmuo 1),
:0.6*2 = 1.2 (vienetas, reiškia aštuntas skaitmuo 1),
:0.2*2 = 0.4 (ne vienetas, reiškia devintas skaitmuo 0),
:0.4*2 = 0.8 (ne vienetas, reiškia dešimtas skaitmuo 0),
:0.8*2 = 1.6 (vienetas, reiškia vienuoliktas skaitmuo 1),
:0.6*2 = 1.2 (vienetas, reiškia dviliktas skaitmuo 1),
:0.2*2 = 0.4 (ne vienetas, reiškia tryliktas skaitmuo 0),
:0.4*2 = 0.8 (ne vienetas, reiškia keturioliktas skaitmuo 0),
:0.8*2 = 1.6 (vienetas, reiškia penkioliktas skaitmuo 1),
:0.6*2 = 1.2 (vienetas, reiškia šešioliktas skaitmuo 1).
:Tada galutinis skaičius '''0.2625''' yra toks:
:0.0100001100110011.
:Kad gauti didesnį tikslumą, procesą reikia kartoti begalo arba iki reikiamo tikslumo.
:Skaičiau '''0.2625''' reikšmė yra:
:0.0100001100110011 =
:= 0.5*0 + 0.25*1 + 0.125*0 + 0.0625*0 + 0.03125*0 + 0.015625*0 + 0.0078125*1 + 0.00390625*1 + 0.001953125*0 + 0.0009765625*0 +
:+ 0.00048828125*1 + 0.000244140625*1 + 0.0001220703125*0 + 0.00006103515625*0 + 0.000030517578125*1 + 0.0000152587890625*1 =
:= 0.26171875 + 0.0007781982421875 = '''0.26249'''69482421875.
:Taigi, 0.26249 labai panašus į 0.2625.
:Vadinasi '''1.2625''' dvejetainėje sistemoje apytiksliai yra '''1.0100001100110011'''.
:Eksponentę 10 reikia versti taip:
:10 = 8 + 2. Tada 10 dvejetainėje sistemoje yra 00001010 (1*0 + 2*1 + 4*0 + 8*1 + 0 + 0 + 0 + 0 = 10).
:Bet eksponentė single precision formate gali būti tik, 0, 1, 2, 4, 8, 16, 32, 64, 128 ir taip toliau.
:Arba reikia daryti taip:
:10/2 = 5 (rem 0),
:5/2 = 2 (rem 1),
:2/2 = 1 (rem 0)
:1/2 = 0.5 (rem 1).
:Va štai šitaip ir gaunamas skaičius 10. Tai yra 1010.
:Skaičius 1010 pakeičiamas skaičiu 1.010 su eksponente 3 (2^3 = 8).
:Tada skaičius 1.010 iškoduojamas taip:
:1 + 0.5*0 + 0.25*1 + 0.125*0 = 1.25.
:Padauginama iš dviejų pakelta eksponente 3:
:1.25 * 2^3 = 1.25 * 8 = 10.
:Tuomet
:1.2625 * 10 = 12.625.
:'''Grįžimas prie pavyzdžio.'''
:Patikrinimas (-12.625).
:Exponent: 10000010 = 128*1 + 64*0 + 32*0 + 16*0 + 8*0 + 4*0 + 2*1 +1*0 = 130. 130-127 = 3. 2^3 = 8.
:Skaičiaus 1100.101 kablelį galima pastumti 4 pozicijom į kairę ir eksponentę duoti 4. Mantisa tada yra 0.1100101, o eksponentė yra 4.
:0.5*1 + 0.25*1 + 0.125*0 + 0.0625*0 + 0.03125*1 + 0.015625*0 + 0.0078125*1 = 0.7890625.
:2^4 * 0.7890625 = 16 * 0.7890625 = '''12.625'''.
:Bandomas kitas skaičius 24:
:24/2 = 12 (rem 0),
:12/2 = 6 (rem 0),
:6/2 = 3 (rem 0),
:3/2 = 1 (rem 1),
:1/2 = 0.5 (rem 1).
:Reiškia 24 yra 11000 (16*1 + 8*1 + 4*0 + 2*0 + 1*0 = 24).
:Bandomas kitas skaičius 19:
:19/2 = 9 (rem 1),
:9/2 = 4 (rem 1),
:4/2 = 2 (rem 0),
:2/2 = 1 (rem 0),
:1/2 = 0.5 (rem 1).
:Reiškia 19 yra 10011 (16*1 + 8*0 + 4*0 + 2*1 + 1*1 = 19).
:Bandomas skaičius 22:
:22/2 = 11 (rem 0),
:11/2 = 5 (rem 1),
:5/2 = 2 (rem 1),
:2/2 = 1 (rem 0),
:1/2 = 0.5 (rem 1).
:Reiškia 22 yra 10110 (16*1 + 8*0 + 4*1 + 2*1 + 1*0 = 16+4+2 = 22).
:Trumpas paaiškinimas kodėl eksponentė saugoma formate nuo 1 iki 254, pridedant 127 prie -126 ir iki 127. Tai greičiausia yra todėl, kad sudedant single precision skaičių tokiame formate kokiame jis yra, jo reiikšmė gali būti gana tiksliai traktuojama kaip sveikojo skaičiaus reikšmė. Su kai kuriais pakeitimais.
:'''-12.625''' yra '''11000001010010100000000000000000'''.
:Pridėjus 127 ('''01111111''') prie eksponentės 3 ('''00000011''') gauname 130 ('''10000010'''):
:'''00000011'''+
:'''01111111'''=
:'''10000010'''.
:Vadinasi tada skaičius '''-12.625''' tampa
:Mantissa: 1100101 = 1 + 0.5*1 + 0.25*0 + 0.125*0 + 0.0625*1 + 0.03125*0 + 0.015625*1 + 0.0078125*0 = 1.578125;
:2^130 = 1.3611294676837538538534984297271e+39 = 1.3611294676837538538534984297271 * 10^39.
:1.578125 * 2^130 = 2.148032441188424050612552209413e+39.
:O sveikasis skaičius '''11000001010010100000000000000000''' be minuso yra '''01000001010010100000000000000000''' ir užrašomas taip:
:1*0 + 2*0 + 4*0 + 8*0 + 16*0 + 32*0 + 64*0 + 128*0 + 256*0 + 512*0 + 1024*0 +
:+ 2048*0 + 4096*0 + 8192*0 + 16,384*0 + 32,768*0 + 65,536*0 + 131,072*0 +
:+ 262,144*1 + 524,288*0 + 1,048,576*1 + 2,097,152*0 + 4,194,304*0 + 8,388,608*1 + 16,777,216*0 + 33,554,432*1 +
:+ 67,108,864*0 + 134,217,728*0 + 268,435,456*0 + 536,870,912*0 + 1,073,741,824*0 +
:+ 2,147,483,648*1 + 4,294,967,296*0 =
:= 0 + 0 + 43,253,760 + 0 + 2,147,483,648 = 2,190,737,408.
:Kažka supainiojau. Atrodė, kad eksponentė beveik tas pats kas didesni skaičiai priekyje.
==Skaičiavimas inverse square root su C kodu==
:Čia https://en.wikipedia.org/wiki/Fast_inverse_square_root aiškinama kaip naudojant sveikuosius skaičius galima apsakičiuoti <math>\frac{1}{\sqrt{x}}.</math>
:"The fast inverse square generates a good approximation through integer operations by adding and subtracting the integer form of floating-point numbers, and taking a square root by dividing by two (which is just a right-shift)."
:Iš čia https://lt.wikibooks.org/wiki/Sekos_riba#Greitas_šaknies_iš_skaičiaus_a_traukimo_būdas gauta formulė
:<math>y_{n+1} = \frac{y_{n}\left(3-xy_n^2\right)}{2}. \quad (4)</math>
:<math>y_n\approx \frac{1}{\sqrt{x}}.</math>
:Ją dar galima pagreitint, pakeitus z = x/2. Tada ši formulė tampa tokia:
:<math>y_{n+1} = y_{n}\left(1.5 - zy_n^2\right). \quad (4.1)</math>
:Programavimo kalbos C kodas skaičiuoti <math>\frac{1}{\sqrt{x}}</math> yra toks:
<syntaxhighlight lang="c">
float Q_rsqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = * ( long * ) &y; // evil floating point bit level hacking
i = 0x5f3759df - ( i >> 1 ); // what the fuck?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
return y;
}
</syntaxhighlight>
:Šito kodo paaiškinimas yra toks:
:Skaičius '''i''' yra ''long integer'' (32 bitų sveikasis skaičius, https://en.wikipedia.org/wiki/C_data_types).
:Skaičiai '''x2''' ir '''y''' yra floating point skaičiai (32 bitų arba 64 bitų). Jeigu 32 bitų, tai tada tai yra single precision 32 bitų float skaičiai.
:Konstanta threehalfs = 1.5F yra 32 bitų single precision skaičius 1.5.
:Skaičius '''number''' yra 32 bitų single precision float ir paduodamas funkcijai. Kitaip tariant '''number''' yra '''x''', o '''y''' bus <math>y\approx \frac{1}{\sqrt{x}}.</math>
:'''x2''' yra '''number'''*0.5 = z.
:Eilutė
i = * ( long * ) &y;
:paverčia ''floating point number'' '''y''' į ''long integer number'' '''i'''. Dabar i yra toks pat kaip y, tik laikomas kaip sveikasis skaičius, o ne slankaus kablelio skaičius. Simbolis * yra pointer to memory address, skirtas įdėti į tą adresą kažką, o ženklas & skirtas paemimui iš tam tikro RAM adreso (arba atvirkščiai, * paėmimui, o & įdėjimui, gerai neatsimenu).
:Todėl ši eilutė gali būti suprantama kaip
:( long * ) &y
:paimti iš y RAM adreso y reikšmę ir įdėti į ''long integer'' (kol kas be pavadinimo) RAM adresą.
:Paskui iš to ''long integer'' RAM adreso įdėti į sveikojo skaičiaus '''i''' RAM adresą (ši kodo dalis "i = *"). Kaip sakyta, iš esmės floating number '''y''' paverčiamas į long integer number '''i'''.
:Šito kodo paaiškinimas yra toks:
:Skaičius '''i''' yra ''long integer'' (32 bitų sveikasis skaičius, https://en.wikipedia.org/wiki/C_data_types).
:Skaičiai '''x2''' ir '''y''' yra floating point skaičiai (32 bitų arba 64 bitų). Jeigu 32 bitų, tai tada tai yra single precision 32 bitų float skaičiai.
:Konstanta threehalfs = 1.5F yra 32 bitų single precision skaičius 1.5.
:Skaičius '''number''' yra 32 bitų single precision float ir paduodamas funkcijai. Kitaip tariant '''number''' yra '''x''', o '''y''' bus <math>y\approx \frac{1}{\sqrt{x}}.</math>
:'''x2''' yra '''number'''*0.5 = z.
:Eilutė
i = * ( long * ) &y;
:paverčia ''floating point number'' '''y''' į ''long integer number'' '''i'''. Dabar i yra toks pat kaip y, tik laikomas kaip sveikasis skaičius, o ne slankaus kablelio skaičius. Simbolis * yra pointer to memory address, skirtas įdėti į tą adresą kažką, o ženklas & skirtas paemimui iš tam tikro RAM adreso (arba atvirkščiai, * paėmimui, o & įdėjimui, gerai neatsimenu).
:Todėl ši eilutė gali būti suprantama kaip
:( long * ) &y
:paimti iš y RAM adreso y reikšmę ir įdėti į ''long integer'' (kol kas be pavadinimo) RAM adresą.
:Paskui iš to ''long integer'' RAM adreso įdėti į sveikojo skaičiaus '''i''' RAM adresą (ši kodo dalis "i = *"). Kaip sakyta, iš esmės floating number '''y''' paverčiamas į long integer number '''i'''.
:Toliau eilutė
i = 0x5f3759df - ( i >> 1 );
:reiškia pastumti sveikąjį skaičių '''i''' viena pozicija į dešinę ir paskui atimti iš sveikojo skaičiaus 0x5f3759df ir rezultatą įdėti į skaičiaus '''i''' adresą. Skaičius 5f3759df turi 8 hexodecimal skaitmenis. Vienas heksodecimal skaitmuo sudaro 4 bitus.
:5 yra 0101, f yra 1111, 3 yra 0011, 7 yra 0111, 5 yra 0101, 9 yra 1001, d yra 1101 (nes A yra 1010, B yra 1011, C yra 1100), f yra 1111. Todėl
:5F3759DFh = 0101,1111,0011,0111,0101,1001,1101,1111;
:5F3759DFh = 01011111001101110101100111011111.
:Gale raidė h reiškia, kad tai hexodecimal skaičius.
:Ši eilutė:
y = * ( float * ) &i;
:paverčia long int '''i''' į float, o paskui tą float perkelią į '''y'''.
:Toliau daromos Niutono iteracijos:
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
:čia y jau turi apytikslią reikšmę <math>\frac{1}{\sqrt{\text{number}}}.</math>
===Worked example===
As an example, the number <math>x=0.15625</math> can be used to calculate <math display=inline>\frac{1}{\sqrt{x}} \approx 2.52982</math>. The first steps of the algorithm are illustrated below:
0011_1110_0010_0000_0000_0000_0000_0000 Bit pattern of both x and i
0001_1111_0001_0000_0000_0000_0000_0000 Shift right one position: (i >> 1)
0101_1111_0011_0111_0101_1001_1101_1111 The magic number 0x5F3759DF
0100_0000_0010_0111_0101_1001_1101_1111 The result of 0x5F3759DF - (i >> 1)
Interpreting as [[IEEE 754|IEEE]] 32-bit representation:
0_01111100_01000000000000000000000 1.25 × 2<sup>−3</sup>
0_00111110_00100000000000000000000 1.125 × 2<sup>−65</sup>
0_10111110_01101110101100111011111 1.432430... × 2<sup>63</sup>
0_10000000_01001110101100111011111 1.307430... × 2<sup>1</sup>
Reinterpreting this last bit pattern as a floating point number gives the approximation <math>y=2.61486</math>, which has an error of about 3.4%. After one iteration of Newton's method, the final result is <math>y=2.52549</math>, an error of only 0.17%.
:'''Patikrinimas.'''
:<math>x=0.15625.</math>
:Sing: '''0'''011_1110_0010_0000_0000_0000_0000_0000 (1 bitas).
:Exponent: 0'''011_1110_0'''010_0000_0000_0000_0000_0000 (8 bitai).
:Mantissa: 0011_1110_0'''010_0000_0000_0000_0000_0000''' (23 bitai).
:Exponente yra '''01111100'''. Tai yra
:128*0 + 64*1 + 32*1 + 16*1 + 8*1 + 4*1 + 2*0 + 1*0 = 124.
:124-127 = -3. Tada eksponentė yra '''-3'''. 2^(-3) = 0.125.
:Mantisa yra ''''010_0000_0000_0000_0000_0000'''.
:Arba '''101''' = 1 + 0.5*0 + 0.25*1 = '''1.25'''.
:1.25 * 0.125 = 0.15625.
:Visi bitai pastumiami viena bito pozicija į dešinę. Tai tas pats kas padalinti iš dviejų mantisą ir eksponentę. Po pastumimo 32 bitų skaičius tampa:
:0001_1111_0001_0000_0000_0000_0000_0000
:Eksponentė tampa 001_1111_0 arba '''00111110'''. Tai yra 128*0+64*0+32*1+16*1+8*1+4*1+2*1+1*0 = 62.
:62-127 = -65. Padauginus iš 2^(-65) = 2.7105054312137610850186320021749e-20 mantisoje nieko neliks.
:Mantisa tapo 001_0000_0000_0000_0000_0000, kas yra
:1001 = 1 + 0.5*0 + 0.25*0 + 0.125*1 = 1.125.
:1.125 * 2^62 = 5,188,146,770,730,811,392.
:1.125 * 2^(-65) = 3.0493186101154812206459610024467e-20 = 3.0493186101154812206459610024467*10^(-20).
:Vat ir išlindo yla iš maišo. Jei nereikėtų prirašyt priekyje vienetoje mantisoje, o eksponentė butų vienetu didesnė, tai rezultatas būtų
:1001 = 0.5*1 + 0.25*0 + 0.125*0 + 0.0625*1 = 0.5 + 0.0625 = 0.5625. (0.5625*2 = 1.125)
:Eksponentė būtų vienetu didesnė (63 arba -64 po atėmimo 127).
:0.5625 * 2^63 = 5,188,146,770,730,811,392.
:0.5625 * 2^(-64) = 3.0493186101154812206459610024467e-20.
:Vadinasi išekstraktuojant atskirai eksponentę ir mantisą ir pastumus mantisos bitus į dešine viena pozicija, į kairiausį bitą turi įeitį vienetas. O prie eksponentės prisidėti vienetas, jeigu norima turėti tą patį skaičių.
:'''Magiškas skaičius reikalingas šiam darbui.'''
:Magiškas skaičius yra
:0101_1111_0011_0111_0101_1001_1101_1111 The magic number 0x5F3759DF
:Sing: '''0''' (1 bitas).
:Exponent: '''101_1111_0''' (8 bitai).
:Mantissa: '''011_0111_0101_1001_1101_1111''' (23 bitai).
:Eksponentė yra 10111110 = 128 + 0 + 32 + 16 + 8 + 4 + 2 + 0 = 190. Atėmus 127 ji tampa 190-127 = 63.
:Mantisa yra
:011_0111_0101_1001_1101_1111 =
:= 0.5*0 + 0.25*1 + 0.125*1 + 0.0625*0 + 0.03125*1 + 0.015625*1 + 0.0078125*1 + 0.00390625*0 + 0.001953125*1 + 0.0009765625*0 +
:+ 0.00048828125*1 + 0.000244140625*1 + 0.0001220703125*0 + 0.00006103515625*0 + 0.000030517578125*1 + 0.0000152587890625*1 +
:+ 0.00000762939453125*1 + 0.000003814697265625*0 + 0.0000019073486328125*1 + 0.00000095367431640625*1 +
:+ 0.000000476837158203125*1 + 0.0000002384185791015625*1 + 0.00000011920928955078125*1 =
:= 0.431640625 + 0.0007781982421875 + 0.00078868865966796875 + 0.00000083446502685546875 = 0.43320834636688232421875.
:Viso skaičiaus reikšmė yra:
:1.43320834636688232421875 * 2^190 = 2.2490986495375580205008307141844e+57 = 2.2490986495375580205008307141844 * 10^57.
:Arba:
:1.43320834636688232421875 * 2^63 = 13,219,013,784,867,176,448 = 1.3219013784867176448 * 10^19.
:Kaip sakyta, 32 bitų skaičius pastumtas viena bito pozicija į dešinę atimamas iš magiško skaičiaus kaip atiminėjami sveikieji skaičiai.
:0101_1111_0011_0111_0101_1001_1101_1111-
:0001_1111_0001_0000_0000_0000_0000_0000=
:0100_0000_0010_0111_0101_1001_1101_1111.
:Gautas skaičius 0100_0000_0010_0111_0101_1001_1101_1111.
:Sign bit: '''0'''100_0000_0010_0111_0101_1001_1101_1111.
:Exponent: 0'''100_0000_0'''010_0111_0101_1001_1101_1111.
:Mantissa: 0100_0000_0'''010_0111_0101_1001_1101_1111'''.
:Eksponentė yra '''10000000''' = 128. Atėmus 127, eksponentė yra 128-127 = 1.
:Mantisa yra '''010_0111_0101_1001_1101_1111''' =
:= 0.5*0 + 0.25*1 + 0.125*0 + 0.0625*0 + 0.03125*1 + 0.015625*1 + 0.0078125*1 + 0.00390625*0 + 0.001953125*1 + 0.0009765625*0 +
:+ 0.00048828125*1 + 0.000244140625*1 + 0.0001220703125*0 + 0.00006103515625*0 + 0.000030517578125*1 + 0.0000152587890625*1 +
:+ 0.00000762939453125*1 + 0.000003814697265625*0 + 0.0000019073486328125*1 + 0.00000095367431640625*1 +
:+ 0.000000476837158203125*1 + 0.0000002384185791015625*1 + 0.00000011920928955078125*1 =
:= 0.306640625 + 0.0007781982421875 + 0.00001049041748046875 + 0.00000083446502685546875 = 0.30743014812469482421875.
:Gautas skaičius yra:
:1.30743014812469482421875 * 2^1 = 2.6148602962493896484375.
:Arba:
:1.30743014812469482421875 * 2^128 = 4.4489542538766432951275906695431e+38 = 4.4489542538766432951275906695431 * 10^38.
:Toliau tereikia daryti iteracijas pagal formulę:
:y = y * ( threehalfs - ( x2 * y * y ) );
:y_0 = 2.6148602962493896484375. z = x/2 = 0.15625/2 = 0.078125.
:y_1 = y_0 * (1.5 - z * y_0 * y_0) =
:= 2.6148602962493896484375 * (1.5 - 0.078125 * 2.6148602962493896484375 * 2.6148602962493896484375) =
:= '''2.52'''54863388218057175296506574507.
:Tikroji reikšmė:
:1/(0.15625)^0.5 = 2.5298221281347034655991148355462.
:Antra iteracija:
:y_2 = y_1 * (1.5 - z * y_1 * y_1) =
:= 2.5254863388218057175296506574507 * (1.5 - 0.078125 * 2.5254863388218057175296506574507 * 2.5254863388218057175296506574507) =
:= '''2.5298'''109880258619023169570466177. 2.5298109880258619023169570466177
:Trečia iteracija:
:y_3 = y_2 * (1.5 - z * y_2 * y_2) =
:= 2.5298109880258619023169570466177 * (1.5 - 0.078125 * 2.5298109880258619023169570466177^2) =
:= '''2.529822128'''0611201246242590927426. 2.5298221280611201246242590927426
:10 pirmų teisingų skaitmenų (beveik 11).
:Ketvirta iteracija:
:y_4 = y_3 * (1.5 - z * y_3 * y_3) =
:= 2.5298221280611201246242590927426 * (1.5 - 0.078125 * 2.5298221280611201246242590927426^2) =
:= '''2.52982212813470346559'''59044271886.
:21 teisingas skaitmenuo po 4 iteracijų. Tai didesnis tikslumas nei Double precision (64 bits). Maždaug toks tikslumas kaip Double Extended precision (80 bits).
:Darant dalybą ar šaknies traukimą gali prireikti panaikinti eksponentę (padaryti ją lygia nuliui ar vienetui). Tai galima atlikti labai paprastai. Reikia padaryti logišką '''AND''' operaciją skaičiaus
:'''1000,0000,0111,1111,1111,1111,1111,1111''' = '''10000000011111111111111111111111''' su norimu skaičiumi, kaip pvz. '''0011_1110_0010_0000_0000_0000_0000_0000''', kuris yra <math>x=0.15625.</math>
:Po '''AND operacjos''' bus gautas skaičius:
:'''0011_1110_0010_0000_0000_0000_0000_0000''' '''AND'''
:'''1000_0000_0111_1111_1111_1111_1111_1111''' =
:'''0000_0000_0010_0000_0000_0000_0000_0000'''.
:Gauta mantisa 01 = 0.5*0 + 0.25*1 = 0.25. Pridėjus nematomą vienetą priekyje galutinis teisingas skaičius lieka:
:1 + 0.25 = 1.25.
:Eksponentė tampa lygi 0. 2^0 = 1.
:AND operacija veikia tokiu budu:
:1 AND 1 = 1,
:1 AND 0 = 0,
:0 AND 1 = 0,
:0 AND 0 = 0.
:Analogišku budu galima paversti mantisos bitus nuliais ir palikti tik eksponentę, prie kurios paskui galima pridėti arba atimti 8 bitus esančius viena bito pozicija į dešinę nuo kairės. Analogiškai galima panaikinti minuso ženklą su AND operacija. Arba suteikti minuso ženklą pridėjus 32 bitų skaičių '''1000_0000_0000_0000_0000_0000_0000_0000''' prie kokio nors teigiamo 32 bitų skaičiaus (kai pirmas bitas yra 0).
==Kaip FPU galėtų apseit be barrel shifters sudedant skaičius su skirtingom eksponentėm==
:https://en.wikipedia.org/wiki/Barrel_shifter
:Barrel Shifter gali stumti pavyzdžiui 32 bito skaičiaus bitus į kairę ar į dešinę ne per vieną bito poziciją, bet per kelias kaip, kad per dvi bito pozicijas ar per 4 bito pozicijas ar per 8 bito pozicijas.
:Sudedant 32 bitų single precision skaičius su skirtingomis eksponentėmis, mažesnio skaičiaus mantisos bitai turi būti pastumti į dešinę per tiek pozicijų koks yra tu dviejų skaičių eksponenčių skirtumas, atėmus eksponentę mažesnio skaičiaus iš eksponentės didesnio skaičiaus.
:Be barrel shifter dviejų 32 bitų floating point skaičių sudėtį su skirtingomis eksponentėmis galima atlikti pakeitus mažesnio skaičiaus eksponentę į denormal ir padauginus tą mažesnį skaičių iš skaičiaus, kurio fractional part yra vienetas (visa mantisa lygi nuliui, jeigu be nematomo vieneto) o eksponentė yra neigiamas skaičius gautas atėmus didesnio 32 bitų float skaičiaus eksponentę iš mažesnio 32 bitų float skaičiaus eksponentės. Tada šio skaičiaus eksponentė bus neigiama ir ją padauginus iš paversto į denormal mažesniojo skaičiaus, bus gautas rezultatas, kad mažesnio skaičiaus mantisa bus pastumta į dešinę tiek pozicijų koks yra tos neigiamos eksponentės skaičiaus modulis.
:Bet turbūt vis tiek reikės šiftinti mantisos bitus į dešinę, kad paversti mažesnio 32 bitų skaičiaus mantisą kaip pas denormal skaičius pastumta atitinkama bitų skaičių į dešinę, kad paskui pridėti gautą mantisą prie didesnio skaičiaus mantios, ir eksponentę po sudeties palikti didesnio skaičiaus, jeigu ji nepakils vienetu dėl sudeties.
:Tai tiesiog čia kaip veikia skaičių sudėtis su skirtingom eksponentėm. Buvau pagalvojęs, kad galima apseiti be barrel shifter, bet pasirodo, kad ne. Arba reikia šiftinti po vieną bitą (jeigu nėra barrel shifter circuit), kas gali pareikalauti nemažai laiko, jeigu sudedamų skaičių eksponentės stipriai skiriasi.
:Todėl iš esmės sudėtis gali būti ilgesnė nei daugyba net su barrel shifter, nes daugyba su padaryta schema galinčia padauginti mantisas iš vieno ciklo, bus daug greitesnė. Ten iš esmės ta daugybos schema turėtų ir užimti didžiausią dalį FPU. Senesni FPU daugino iš daug ciklų, nes negalėjo sau leisti daug transistorių daugybos transistorių schemai. Maždaug Pentium procesoriai pradėjo dauginti iš vieno ciklo, jei neskaičiuoti visokių įkrovimo, užkrovimo, išėmimo operacijų dviejų dauginamų skaičių.
[https://lt.wikibooks.org/wiki/Wikibooks:Knygos/High_Level_Shading_Language High Level Shading Language]
crzu4nlddlvcmh1ebvsyou9pprvxgs1
58990
58989
2026-09-04T05:12:48Z
Paraboloid
1294
/* Worked example */
58990
wikitext
text/x-wiki
==Dešimtainių skaičių vertimas į dvejetainius skaičius==
[https://www.google.com/search?client=opera&q=single+precision&sourceid=opera&ie=UTF-8&oe=UTF-8&udm=50&fbs=ABfTbFVyMZGZf1hfvX9uKjN_-G8c4u0nXx4bEIpwm1lnNH832VTJOOCxW_fyN-Q_ezyf8gKjm3rhh_G8jdZ2Q6tji4z8Mva6cfvBj5rpPch2IC955IbzrbwHf6tkbFbd-nuFdbKth9Y-58t5LtnYgTA4TWDFYCUNl4d7F9XBAwiEq2T2c7SNgrvMxYiRBXL4fnQnnTOewx28&aep=10&ntc=1&sxsrf=APpeQnvZo3fX2PwO881uSdWsoRELP18NhQ%3A1788348274309&mstk=AUtExfAJ0Kp9BqT3EJbzHOz3MHMalnyXkoOTLvgho5ZQ9lzjrnmmUFCgux_RVe7bouRlyBSGpkUcLpvfZ39N45TUoor6TyyEW7_PpE7eOwP-kU7IFxE6monk-HtsDXkDu7g362AN4NTW3oRjfwn9OtD0BIj2r4QAVauMhDPCIAiWgLimDuate6cf2o6bB5R-6-vzcCqbCju1KJQTdR4HSF9puZ_HCG1hXQ8QaCIqD1LJ_HWonNnZGma6Biu3I1wWFPy6esLnfaKpIX6VFWZsArfQN97XGipwkH7FLKCyZiev5rZBrhE8KincMthP7B9AJDugKLy8qJfORQ7PQR2GslAaCLnkechjBCnXfrmSohwJskbEWU9db6Q279uO4dGu0eI2YUvpEwoQUqkbREqJqrGpJQWFy7WoTzI93_o_2I61PU1FTiuGq-4AVN7erT0WmuWizHDEE2XsTes&aioh=3&csuir=1&atvm=2&mtid=dQeYaumuDL2Ixc8Px6Ts0QE DI atsakymas]
:Single-precision is a 32-bit computer number format that stores fractional and large numbers using a sign bit, an exponent, and a mantissa. Structure of Single-Precision (Binary32) According to Wikipedia, “Single-precision floating-point format (sometimes called FP32, float32, or float) is a computer number format, usually occupying 32 bits in computer memory.” The 32 bits are divided into three specific parts:
*Sign bit (1 bit): Determines if the number is positive (0) or negative (1).
*Biased exponent (8 bits): Stores the magnitude with an excess-127 bias, giving an actual exponent range of -126 to +127.
*Mantissa/Significand (23 explicitly stored bits): Represents the precision digits of the number, with an implicit leading 1 for normalized values.
:Precision and Applications. Decimal Precision: Provides about 7 to 8 decimal digits of accuracy. Most users on StackOverflow agree that “Single precision typically offers 7-8 decimal digits of precision.”
:'''Dešimtainių skaičių vertimas į dvejetainius.'''
:Step-by-Step Conversion Framework.
*Step 1: Determine the Sign Bit (1 bit). If the number is positive, the sign bit is 0. If the number is negative, the sign bit is 1. Example (-12.625): It is negative, so the sign bit is 1.
*Step 2: Convert the Absolute Value to Binary. Separate the number into its integer and fractional parts, convert both to binary, and combine them.
:Integer part '''12''': (12/2 = 6) ('''rem'''ainder 0), (6/2 = 3) (rem 0), (3/2 = 1) (rem 1), (1/2 = 0) (rem 1) <math>\rightarrow </math> '''1100'''.
:Fractional part '''0.625''': (0.625 * 2 = 1.25) (1), (0.25 * 2 = 0.5) (0), (0.5 * 2 = 1.0) (1) <math>\rightarrow </math> '''101'''.
:Example Combined: '''12.625''' = '''1100.101'''.
*Step 3: Normalize the Binary Number. Shift the binary point so that exactly one non-zero digit (which will always be 1) remains to its left. Count how many places you moved the point. This count is your exponent (E).
:Move the point 3 places to the left: '''1100.101''' <math>\rightarrow </math> '''1.100101'''.
:Example Exponent: Because we moved it 3 places, E = 3.
*Step 4: Calculate the Biased Exponent (8 bits) IEEE 754 single-precision uses a bias of 127. Add your exponent E to this bias, and convert the resulting integer to an 8-bit binary number.
:Calculation: 127 + 3 = 130.
:Convert 130 to 8-bit binary: '''130''' = '''10000010'''.
*Step 5: Extract the Mantissa/Significand (23 bits).
:Take the fractional bits from your normalized number (everything to the right of the binary point). Drop the leading 1. If the bits are fewer than 23, pad the right side with zeros until you reach exactly 23 bits.
:Normalized bits: 1.100101 <math>\rightarrow </math> Drop the ''1.'' (atmesti kairiausią vienetą ir tašką po jo) to get '''100101'''.
:Example Pad to 23 bits: 10010100000000000000000.
:'''Final Assembly.'''
:Combine the three components in order: Sign (1 bit) + Exponent (8 bits) + Mantissa (23 bits).
:Component_____________Bits______________Value for -12.625_______
:Sign____________________1_______________________1______________
:Exponent________________8____________________10000010__________
:Mantissa________________23______________10010100000000000000000
*Final 32-bit Binary String: '''11000001010010100000000000000000'''.
*Hexadecimal Representation: '''C1450000'''.
:Sign: '''1'''1000001010001010000000000000000.
:Exponent: 1'''10000010'''10001010000000000000000.
:Mantissa: 110000010'''10010100000000000000000'''.
:Patikrinimas (-12.625).
:Exponent: 10000010 = 128*1 + 64*0 + 32*0 + 16*0 + 8*0 + 4*0 + 2*1 +1*0 = 130. 130-127 = 3. 2^3 = 8.
:Mantissa: 100101 = 0.5*1 + 0.25*0 + 0.125*0 + 0.0625*1 + 0.03125*0 + 0.015625*1 + 0.0078125*0 = 0.578125.
:8 * 0.578125 = 4.625.
:8 * 1 = 8.
:8 + 4.625 = 12.625.
:Reikia gražinti paimtą vienetą priekyje ('''12.625''' = '''1100.101'''; '''1100.101''' <math>\rightarrow </math> '''1.100101'''):
:8 * (1 + 0.578125) = 8 * 1.578125 = 12.625.
:-12.625 = -1.2625 * 10^1.
:Čia mantisa 0.2625, o ekspontentė 1 dešimtainėje sistemoje. Skačių 0.2625 reikia kaskart dauginti iš 2.
:0.2625*2 = 0.525 (ne vienetas, reiškia pirmas skaitmuo 0),
:0.525*2 = 1.05 (vienetas, reiškia antras skaitmuo 1),
:0.05*2 = 0.1 (ne vienetas, reiškia trečias skaitmuo 0),
:0.1*2 = 0.2 (ne vienetas, reiškia ketvirtas skaitmuo 0),
:0.2*2 = 0.4 (ne vienetas, reiškia penktas skaitmuo 0),
:0.4*2 = 0.8 (ne vienetas, reiškia šeštas skaitmuo 0),
:0.8*2 = 1.6 (vienetas, reiškia septintas skaitmuo 1),
:0.6*2 = 1.2 (vienetas, reiškia aštuntas skaitmuo 1),
:0.2*2 = 0.4 (ne vienetas, reiškia devintas skaitmuo 0),
:0.4*2 = 0.8 (ne vienetas, reiškia dešimtas skaitmuo 0),
:0.8*2 = 1.6 (vienetas, reiškia vienuoliktas skaitmuo 1),
:0.6*2 = 1.2 (vienetas, reiškia dviliktas skaitmuo 1),
:0.2*2 = 0.4 (ne vienetas, reiškia tryliktas skaitmuo 0),
:0.4*2 = 0.8 (ne vienetas, reiškia keturioliktas skaitmuo 0),
:0.8*2 = 1.6 (vienetas, reiškia penkioliktas skaitmuo 1),
:0.6*2 = 1.2 (vienetas, reiškia šešioliktas skaitmuo 1).
:Tada galutinis skaičius '''0.2625''' yra toks:
:0.0100001100110011.
:Kad gauti didesnį tikslumą, procesą reikia kartoti begalo arba iki reikiamo tikslumo.
:Skaičiau '''0.2625''' reikšmė yra:
:0.0100001100110011 =
:= 0.5*0 + 0.25*1 + 0.125*0 + 0.0625*0 + 0.03125*0 + 0.015625*0 + 0.0078125*1 + 0.00390625*1 + 0.001953125*0 + 0.0009765625*0 +
:+ 0.00048828125*1 + 0.000244140625*1 + 0.0001220703125*0 + 0.00006103515625*0 + 0.000030517578125*1 + 0.0000152587890625*1 =
:= 0.26171875 + 0.0007781982421875 = '''0.26249'''69482421875.
:Taigi, 0.26249 labai panašus į 0.2625.
:Vadinasi '''1.2625''' dvejetainėje sistemoje apytiksliai yra '''1.0100001100110011'''.
:Eksponentę 10 reikia versti taip:
:10 = 8 + 2. Tada 10 dvejetainėje sistemoje yra 00001010 (1*0 + 2*1 + 4*0 + 8*1 + 0 + 0 + 0 + 0 = 10).
:Bet eksponentė single precision formate gali būti tik, 0, 1, 2, 4, 8, 16, 32, 64, 128 ir taip toliau.
:Arba reikia daryti taip:
:10/2 = 5 (rem 0),
:5/2 = 2 (rem 1),
:2/2 = 1 (rem 0)
:1/2 = 0.5 (rem 1).
:Va štai šitaip ir gaunamas skaičius 10. Tai yra 1010.
:Skaičius 1010 pakeičiamas skaičiu 1.010 su eksponente 3 (2^3 = 8).
:Tada skaičius 1.010 iškoduojamas taip:
:1 + 0.5*0 + 0.25*1 + 0.125*0 = 1.25.
:Padauginama iš dviejų pakelta eksponente 3:
:1.25 * 2^3 = 1.25 * 8 = 10.
:Tuomet
:1.2625 * 10 = 12.625.
:'''Grįžimas prie pavyzdžio.'''
:Patikrinimas (-12.625).
:Exponent: 10000010 = 128*1 + 64*0 + 32*0 + 16*0 + 8*0 + 4*0 + 2*1 +1*0 = 130. 130-127 = 3. 2^3 = 8.
:Skaičiaus 1100.101 kablelį galima pastumti 4 pozicijom į kairę ir eksponentę duoti 4. Mantisa tada yra 0.1100101, o eksponentė yra 4.
:0.5*1 + 0.25*1 + 0.125*0 + 0.0625*0 + 0.03125*1 + 0.015625*0 + 0.0078125*1 = 0.7890625.
:2^4 * 0.7890625 = 16 * 0.7890625 = '''12.625'''.
:Bandomas kitas skaičius 24:
:24/2 = 12 (rem 0),
:12/2 = 6 (rem 0),
:6/2 = 3 (rem 0),
:3/2 = 1 (rem 1),
:1/2 = 0.5 (rem 1).
:Reiškia 24 yra 11000 (16*1 + 8*1 + 4*0 + 2*0 + 1*0 = 24).
:Bandomas kitas skaičius 19:
:19/2 = 9 (rem 1),
:9/2 = 4 (rem 1),
:4/2 = 2 (rem 0),
:2/2 = 1 (rem 0),
:1/2 = 0.5 (rem 1).
:Reiškia 19 yra 10011 (16*1 + 8*0 + 4*0 + 2*1 + 1*1 = 19).
:Bandomas skaičius 22:
:22/2 = 11 (rem 0),
:11/2 = 5 (rem 1),
:5/2 = 2 (rem 1),
:2/2 = 1 (rem 0),
:1/2 = 0.5 (rem 1).
:Reiškia 22 yra 10110 (16*1 + 8*0 + 4*1 + 2*1 + 1*0 = 16+4+2 = 22).
:Trumpas paaiškinimas kodėl eksponentė saugoma formate nuo 1 iki 254, pridedant 127 prie -126 ir iki 127. Tai greičiausia yra todėl, kad sudedant single precision skaičių tokiame formate kokiame jis yra, jo reiikšmė gali būti gana tiksliai traktuojama kaip sveikojo skaičiaus reikšmė. Su kai kuriais pakeitimais.
:'''-12.625''' yra '''11000001010010100000000000000000'''.
:Pridėjus 127 ('''01111111''') prie eksponentės 3 ('''00000011''') gauname 130 ('''10000010'''):
:'''00000011'''+
:'''01111111'''=
:'''10000010'''.
:Vadinasi tada skaičius '''-12.625''' tampa
:Mantissa: 1100101 = 1 + 0.5*1 + 0.25*0 + 0.125*0 + 0.0625*1 + 0.03125*0 + 0.015625*1 + 0.0078125*0 = 1.578125;
:2^130 = 1.3611294676837538538534984297271e+39 = 1.3611294676837538538534984297271 * 10^39.
:1.578125 * 2^130 = 2.148032441188424050612552209413e+39.
:O sveikasis skaičius '''11000001010010100000000000000000''' be minuso yra '''01000001010010100000000000000000''' ir užrašomas taip:
:1*0 + 2*0 + 4*0 + 8*0 + 16*0 + 32*0 + 64*0 + 128*0 + 256*0 + 512*0 + 1024*0 +
:+ 2048*0 + 4096*0 + 8192*0 + 16,384*0 + 32,768*0 + 65,536*0 + 131,072*0 +
:+ 262,144*1 + 524,288*0 + 1,048,576*1 + 2,097,152*0 + 4,194,304*0 + 8,388,608*1 + 16,777,216*0 + 33,554,432*1 +
:+ 67,108,864*0 + 134,217,728*0 + 268,435,456*0 + 536,870,912*0 + 1,073,741,824*0 +
:+ 2,147,483,648*1 + 4,294,967,296*0 =
:= 0 + 0 + 43,253,760 + 0 + 2,147,483,648 = 2,190,737,408.
:Kažka supainiojau. Atrodė, kad eksponentė beveik tas pats kas didesni skaičiai priekyje.
==Skaičiavimas inverse square root su C kodu==
:Čia https://en.wikipedia.org/wiki/Fast_inverse_square_root aiškinama kaip naudojant sveikuosius skaičius galima apsakičiuoti <math>\frac{1}{\sqrt{x}}.</math>
:"The fast inverse square generates a good approximation through integer operations by adding and subtracting the integer form of floating-point numbers, and taking a square root by dividing by two (which is just a right-shift)."
:Iš čia https://lt.wikibooks.org/wiki/Sekos_riba#Greitas_šaknies_iš_skaičiaus_a_traukimo_būdas gauta formulė
:<math>y_{n+1} = \frac{y_{n}\left(3-xy_n^2\right)}{2}. \quad (4)</math>
:<math>y_n\approx \frac{1}{\sqrt{x}}.</math>
:Ją dar galima pagreitint, pakeitus z = x/2. Tada ši formulė tampa tokia:
:<math>y_{n+1} = y_{n}\left(1.5 - zy_n^2\right). \quad (4.1)</math>
:Programavimo kalbos C kodas skaičiuoti <math>\frac{1}{\sqrt{x}}</math> yra toks:
<syntaxhighlight lang="c">
float Q_rsqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = * ( long * ) &y; // evil floating point bit level hacking
i = 0x5f3759df - ( i >> 1 ); // what the fuck?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
return y;
}
</syntaxhighlight>
:Šito kodo paaiškinimas yra toks:
:Skaičius '''i''' yra ''long integer'' (32 bitų sveikasis skaičius, https://en.wikipedia.org/wiki/C_data_types).
:Skaičiai '''x2''' ir '''y''' yra floating point skaičiai (32 bitų arba 64 bitų). Jeigu 32 bitų, tai tada tai yra single precision 32 bitų float skaičiai.
:Konstanta threehalfs = 1.5F yra 32 bitų single precision skaičius 1.5.
:Skaičius '''number''' yra 32 bitų single precision float ir paduodamas funkcijai. Kitaip tariant '''number''' yra '''x''', o '''y''' bus <math>y\approx \frac{1}{\sqrt{x}}.</math>
:'''x2''' yra '''number'''*0.5 = z.
:Eilutė
i = * ( long * ) &y;
:paverčia ''floating point number'' '''y''' į ''long integer number'' '''i'''. Dabar i yra toks pat kaip y, tik laikomas kaip sveikasis skaičius, o ne slankaus kablelio skaičius. Simbolis * yra pointer to memory address, skirtas įdėti į tą adresą kažką, o ženklas & skirtas paemimui iš tam tikro RAM adreso (arba atvirkščiai, * paėmimui, o & įdėjimui, gerai neatsimenu).
:Todėl ši eilutė gali būti suprantama kaip
:( long * ) &y
:paimti iš y RAM adreso y reikšmę ir įdėti į ''long integer'' (kol kas be pavadinimo) RAM adresą.
:Paskui iš to ''long integer'' RAM adreso įdėti į sveikojo skaičiaus '''i''' RAM adresą (ši kodo dalis "i = *"). Kaip sakyta, iš esmės floating number '''y''' paverčiamas į long integer number '''i'''.
:Šito kodo paaiškinimas yra toks:
:Skaičius '''i''' yra ''long integer'' (32 bitų sveikasis skaičius, https://en.wikipedia.org/wiki/C_data_types).
:Skaičiai '''x2''' ir '''y''' yra floating point skaičiai (32 bitų arba 64 bitų). Jeigu 32 bitų, tai tada tai yra single precision 32 bitų float skaičiai.
:Konstanta threehalfs = 1.5F yra 32 bitų single precision skaičius 1.5.
:Skaičius '''number''' yra 32 bitų single precision float ir paduodamas funkcijai. Kitaip tariant '''number''' yra '''x''', o '''y''' bus <math>y\approx \frac{1}{\sqrt{x}}.</math>
:'''x2''' yra '''number'''*0.5 = z.
:Eilutė
i = * ( long * ) &y;
:paverčia ''floating point number'' '''y''' į ''long integer number'' '''i'''. Dabar i yra toks pat kaip y, tik laikomas kaip sveikasis skaičius, o ne slankaus kablelio skaičius. Simbolis * yra pointer to memory address, skirtas įdėti į tą adresą kažką, o ženklas & skirtas paemimui iš tam tikro RAM adreso (arba atvirkščiai, * paėmimui, o & įdėjimui, gerai neatsimenu).
:Todėl ši eilutė gali būti suprantama kaip
:( long * ) &y
:paimti iš y RAM adreso y reikšmę ir įdėti į ''long integer'' (kol kas be pavadinimo) RAM adresą.
:Paskui iš to ''long integer'' RAM adreso įdėti į sveikojo skaičiaus '''i''' RAM adresą (ši kodo dalis "i = *"). Kaip sakyta, iš esmės floating number '''y''' paverčiamas į long integer number '''i'''.
:Toliau eilutė
i = 0x5f3759df - ( i >> 1 );
:reiškia pastumti sveikąjį skaičių '''i''' viena pozicija į dešinę ir paskui atimti iš sveikojo skaičiaus 0x5f3759df ir rezultatą įdėti į skaičiaus '''i''' adresą. Skaičius 5f3759df turi 8 hexodecimal skaitmenis. Vienas heksodecimal skaitmuo sudaro 4 bitus.
:5 yra 0101, f yra 1111, 3 yra 0011, 7 yra 0111, 5 yra 0101, 9 yra 1001, d yra 1101 (nes A yra 1010, B yra 1011, C yra 1100), f yra 1111. Todėl
:5F3759DFh = 0101,1111,0011,0111,0101,1001,1101,1111;
:5F3759DFh = 01011111001101110101100111011111.
:Gale raidė h reiškia, kad tai hexodecimal skaičius.
:Ši eilutė:
y = * ( float * ) &i;
:paverčia long int '''i''' į float, o paskui tą float perkelią į '''y'''.
:Toliau daromos Niutono iteracijos:
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
:čia y jau turi apytikslią reikšmę <math>\frac{1}{\sqrt{\text{number}}}.</math>
===Worked example===
As an example, the number <math>x=0.15625</math> can be used to calculate <math display=inline>\frac{1}{\sqrt{x}} \approx 2.52982</math>. The first steps of the algorithm are illustrated below:
0011_1110_0010_0000_0000_0000_0000_0000 Bit pattern of both x and i
0001_1111_0001_0000_0000_0000_0000_0000 Shift right one position: (i >> 1)
0101_1111_0011_0111_0101_1001_1101_1111 The magic number 0x5F3759DF
0100_0000_0010_0111_0101_1001_1101_1111 The result of 0x5F3759DF - (i >> 1)
Interpreting as [[IEEE 754|IEEE]] 32-bit representation:
0_01111100_01000000000000000000000 1.25 × 2<sup>−3</sup>
0_00111110_00100000000000000000000 1.125 × 2<sup>−65</sup>
0_10111110_01101110101100111011111 1.432430... × 2<sup>63</sup>
0_10000000_01001110101100111011111 1.307430... × 2<sup>1</sup>
Reinterpreting this last bit pattern as a floating point number gives the approximation <math>y=2.61486</math>, which has an error of about 3.4%. After one iteration of Newton's method, the final result is <math>y=2.52549</math>, an error of only 0.17%.
:'''Patikrinimas.'''
:<math>x=0.15625.</math>
:Sing: '''0'''011_1110_0010_0000_0000_0000_0000_0000 (1 bitas).
:Exponent: 0'''011_1110_0'''010_0000_0000_0000_0000_0000 (8 bitai).
:Mantissa: 0011_1110_0'''010_0000_0000_0000_0000_0000''' (23 bitai).
:Exponente yra '''01111100'''. Tai yra
:128*0 + 64*1 + 32*1 + 16*1 + 8*1 + 4*1 + 2*0 + 1*0 = 124.
:124-127 = -3. Tada eksponentė yra '''-3'''. 2^(-3) = 0.125.
:Mantisa yra '''010_0000_0000_0000_0000_0000'''.
:Arba '''101''' = 1 + 0.5*0 + 0.25*1 = '''1.25'''.
:1.25 * 0.125 = 0.15625.
:Visi bitai pastumiami viena bito pozicija į dešinę. Tai tas pats kas padalinti iš dviejų mantisą ir eksponentę. Po pastumimo 32 bitų skaičius tampa:
:0001_1111_0001_0000_0000_0000_0000_0000
:Eksponentė tampa 001_1111_0 arba '''00111110'''. Tai yra 128*0+64*0+32*1+16*1+8*1+4*1+2*1+1*0 = 62.
:62-127 = -65. Padauginus iš 2^(-65) = 2.7105054312137610850186320021749e-20 mantisoje nieko neliks.
:Mantisa tapo 001_0000_0000_0000_0000_0000, kas yra
:1001 = 1 + 0.5*0 + 0.25*0 + 0.125*1 = 1.125.
:1.125 * 2^62 = 5,188,146,770,730,811,392.
:1.125 * 2^(-65) = 3.0493186101154812206459610024467e-20 = 3.0493186101154812206459610024467*10^(-20).
:Vat ir išlindo yla iš maišo. Jei nereikėtų prirašyt priekyje vienetoje mantisoje, o eksponentė butų vienetu didesnė, tai rezultatas būtų
:1001 = 0.5*1 + 0.25*0 + 0.125*0 + 0.0625*1 = 0.5 + 0.0625 = 0.5625. (0.5625*2 = 1.125)
:Eksponentė būtų vienetu didesnė (63 arba -64 po atėmimo 127).
:0.5625 * 2^63 = 5,188,146,770,730,811,392.
:0.5625 * 2^(-64) = 3.0493186101154812206459610024467e-20.
:Vadinasi išekstraktuojant atskirai eksponentę ir mantisą ir pastumus mantisos bitus į dešine viena pozicija, į kairiausį bitą turi įeitį vienetas. O prie eksponentės prisidėti vienetas, jeigu norima turėti tą patį skaičių.
:'''Magiškas skaičius reikalingas šiam darbui.'''
:Magiškas skaičius yra
:0101_1111_0011_0111_0101_1001_1101_1111 The magic number 0x5F3759DF
:Sing: '''0''' (1 bitas).
:Exponent: '''101_1111_0''' (8 bitai).
:Mantissa: '''011_0111_0101_1001_1101_1111''' (23 bitai).
:Eksponentė yra 10111110 = 128 + 0 + 32 + 16 + 8 + 4 + 2 + 0 = 190. Atėmus 127 ji tampa 190-127 = 63.
:Mantisa yra
:011_0111_0101_1001_1101_1111 =
:= 0.5*0 + 0.25*1 + 0.125*1 + 0.0625*0 + 0.03125*1 + 0.015625*1 + 0.0078125*1 + 0.00390625*0 + 0.001953125*1 + 0.0009765625*0 +
:+ 0.00048828125*1 + 0.000244140625*1 + 0.0001220703125*0 + 0.00006103515625*0 + 0.000030517578125*1 + 0.0000152587890625*1 +
:+ 0.00000762939453125*1 + 0.000003814697265625*0 + 0.0000019073486328125*1 + 0.00000095367431640625*1 +
:+ 0.000000476837158203125*1 + 0.0000002384185791015625*1 + 0.00000011920928955078125*1 =
:= 0.431640625 + 0.0007781982421875 + 0.00078868865966796875 + 0.00000083446502685546875 = 0.43320834636688232421875.
:Viso skaičiaus reikšmė yra:
:1.43320834636688232421875 * 2^190 = 2.2490986495375580205008307141844e+57 = 2.2490986495375580205008307141844 * 10^57.
:Arba:
:1.43320834636688232421875 * 2^63 = 13,219,013,784,867,176,448 = 1.3219013784867176448 * 10^19.
:Kaip sakyta, 32 bitų skaičius pastumtas viena bito pozicija į dešinę atimamas iš magiško skaičiaus kaip atiminėjami sveikieji skaičiai.
:0101_1111_0011_0111_0101_1001_1101_1111-
:0001_1111_0001_0000_0000_0000_0000_0000=
:0100_0000_0010_0111_0101_1001_1101_1111.
:Gautas skaičius 0100_0000_0010_0111_0101_1001_1101_1111.
:Sign bit: '''0'''100_0000_0010_0111_0101_1001_1101_1111.
:Exponent: 0'''100_0000_0'''010_0111_0101_1001_1101_1111.
:Mantissa: 0100_0000_0'''010_0111_0101_1001_1101_1111'''.
:Eksponentė yra '''10000000''' = 128. Atėmus 127, eksponentė yra 128-127 = 1.
:Mantisa yra '''010_0111_0101_1001_1101_1111''' =
:= 0.5*0 + 0.25*1 + 0.125*0 + 0.0625*0 + 0.03125*1 + 0.015625*1 + 0.0078125*1 + 0.00390625*0 + 0.001953125*1 + 0.0009765625*0 +
:+ 0.00048828125*1 + 0.000244140625*1 + 0.0001220703125*0 + 0.00006103515625*0 + 0.000030517578125*1 + 0.0000152587890625*1 +
:+ 0.00000762939453125*1 + 0.000003814697265625*0 + 0.0000019073486328125*1 + 0.00000095367431640625*1 +
:+ 0.000000476837158203125*1 + 0.0000002384185791015625*1 + 0.00000011920928955078125*1 =
:= 0.306640625 + 0.0007781982421875 + 0.00001049041748046875 + 0.00000083446502685546875 = 0.30743014812469482421875.
:Gautas skaičius yra:
:1.30743014812469482421875 * 2^1 = 2.6148602962493896484375.
:Arba:
:1.30743014812469482421875 * 2^128 = 4.4489542538766432951275906695431e+38 = 4.4489542538766432951275906695431 * 10^38.
:Toliau tereikia daryti iteracijas pagal formulę:
:y = y * ( threehalfs - ( x2 * y * y ) );
:y_0 = 2.6148602962493896484375. z = x/2 = 0.15625/2 = 0.078125.
:y_1 = y_0 * (1.5 - z * y_0 * y_0) =
:= 2.6148602962493896484375 * (1.5 - 0.078125 * 2.6148602962493896484375 * 2.6148602962493896484375) =
:= '''2.52'''54863388218057175296506574507.
:Tikroji reikšmė:
:1/(0.15625)^0.5 = 2.5298221281347034655991148355462.
:Antra iteracija:
:y_2 = y_1 * (1.5 - z * y_1 * y_1) =
:= 2.5254863388218057175296506574507 * (1.5 - 0.078125 * 2.5254863388218057175296506574507 * 2.5254863388218057175296506574507) =
:= '''2.5298'''109880258619023169570466177. 2.5298109880258619023169570466177
:Trečia iteracija:
:y_3 = y_2 * (1.5 - z * y_2 * y_2) =
:= 2.5298109880258619023169570466177 * (1.5 - 0.078125 * 2.5298109880258619023169570466177^2) =
:= '''2.529822128'''0611201246242590927426. 2.5298221280611201246242590927426
:10 pirmų teisingų skaitmenų (beveik 11).
:Ketvirta iteracija:
:y_4 = y_3 * (1.5 - z * y_3 * y_3) =
:= 2.5298221280611201246242590927426 * (1.5 - 0.078125 * 2.5298221280611201246242590927426^2) =
:= '''2.52982212813470346559'''59044271886.
:21 teisingas skaitmenuo po 4 iteracijų. Tai didesnis tikslumas nei Double precision (64 bits). Maždaug toks tikslumas kaip Double Extended precision (80 bits).
:Darant dalybą ar šaknies traukimą gali prireikti panaikinti eksponentę (padaryti ją lygia nuliui ar vienetui). Tai galima atlikti labai paprastai. Reikia padaryti logišką '''AND''' operaciją skaičiaus
:'''1000,0000,0111,1111,1111,1111,1111,1111''' = '''10000000011111111111111111111111''' su norimu skaičiumi, kaip pvz. '''0011_1110_0010_0000_0000_0000_0000_0000''', kuris yra <math>x=0.15625.</math>
:Po '''AND operacjos''' bus gautas skaičius:
:'''0011_1110_0010_0000_0000_0000_0000_0000''' '''AND'''
:'''1000_0000_0111_1111_1111_1111_1111_1111''' =
:'''0000_0000_0010_0000_0000_0000_0000_0000'''.
:Gauta mantisa 01 = 0.5*0 + 0.25*1 = 0.25. Pridėjus nematomą vienetą priekyje galutinis teisingas skaičius lieka:
:1 + 0.25 = 1.25.
:Eksponentė tampa lygi 0. 2^0 = 1.
:AND operacija veikia tokiu budu:
:1 AND 1 = 1,
:1 AND 0 = 0,
:0 AND 1 = 0,
:0 AND 0 = 0.
:Analogišku budu galima paversti mantisos bitus nuliais ir palikti tik eksponentę, prie kurios paskui galima pridėti arba atimti 8 bitus esančius viena bito pozicija į dešinę nuo kairės. Analogiškai galima panaikinti minuso ženklą su AND operacija. Arba suteikti minuso ženklą pridėjus 32 bitų skaičių '''1000_0000_0000_0000_0000_0000_0000_0000''' prie kokio nors teigiamo 32 bitų skaičiaus (kai pirmas bitas yra 0).
==Kaip FPU galėtų apseit be barrel shifters sudedant skaičius su skirtingom eksponentėm==
:https://en.wikipedia.org/wiki/Barrel_shifter
:Barrel Shifter gali stumti pavyzdžiui 32 bito skaičiaus bitus į kairę ar į dešinę ne per vieną bito poziciją, bet per kelias kaip, kad per dvi bito pozicijas ar per 4 bito pozicijas ar per 8 bito pozicijas.
:Sudedant 32 bitų single precision skaičius su skirtingomis eksponentėmis, mažesnio skaičiaus mantisos bitai turi būti pastumti į dešinę per tiek pozicijų koks yra tu dviejų skaičių eksponenčių skirtumas, atėmus eksponentę mažesnio skaičiaus iš eksponentės didesnio skaičiaus.
:Be barrel shifter dviejų 32 bitų floating point skaičių sudėtį su skirtingomis eksponentėmis galima atlikti pakeitus mažesnio skaičiaus eksponentę į denormal ir padauginus tą mažesnį skaičių iš skaičiaus, kurio fractional part yra vienetas (visa mantisa lygi nuliui, jeigu be nematomo vieneto) o eksponentė yra neigiamas skaičius gautas atėmus didesnio 32 bitų float skaičiaus eksponentę iš mažesnio 32 bitų float skaičiaus eksponentės. Tada šio skaičiaus eksponentė bus neigiama ir ją padauginus iš paversto į denormal mažesniojo skaičiaus, bus gautas rezultatas, kad mažesnio skaičiaus mantisa bus pastumta į dešinę tiek pozicijų koks yra tos neigiamos eksponentės skaičiaus modulis.
:Bet turbūt vis tiek reikės šiftinti mantisos bitus į dešinę, kad paversti mažesnio 32 bitų skaičiaus mantisą kaip pas denormal skaičius pastumta atitinkama bitų skaičių į dešinę, kad paskui pridėti gautą mantisą prie didesnio skaičiaus mantios, ir eksponentę po sudeties palikti didesnio skaičiaus, jeigu ji nepakils vienetu dėl sudeties.
:Tai tiesiog čia kaip veikia skaičių sudėtis su skirtingom eksponentėm. Buvau pagalvojęs, kad galima apseiti be barrel shifter, bet pasirodo, kad ne. Arba reikia šiftinti po vieną bitą (jeigu nėra barrel shifter circuit), kas gali pareikalauti nemažai laiko, jeigu sudedamų skaičių eksponentės stipriai skiriasi.
:Todėl iš esmės sudėtis gali būti ilgesnė nei daugyba net su barrel shifter, nes daugyba su padaryta schema galinčia padauginti mantisas iš vieno ciklo, bus daug greitesnė. Ten iš esmės ta daugybos schema turėtų ir užimti didžiausią dalį FPU. Senesni FPU daugino iš daug ciklų, nes negalėjo sau leisti daug transistorių daugybos transistorių schemai. Maždaug Pentium procesoriai pradėjo dauginti iš vieno ciklo, jei neskaičiuoti visokių įkrovimo, užkrovimo, išėmimo operacijų dviejų dauginamų skaičių.
[https://lt.wikibooks.org/wiki/Wikibooks:Knygos/High_Level_Shading_Language High Level Shading Language]
myfnrlm7fg0m8t3i60r3bkmw9tq4qiv