01110111010110 11110101010101 00101011010011 01010111010101 01001010101010 10101010101010 Tietokoneen mysteeri bitit ja data Petteri Kaski Tietotekniikan laitos Aalto-yliopisto CS-A1120 Ohjelmointi 2 22. helmikuuta 2017 10101011110101 01010101011101 01010111010110 10101101010110 10101110101010 11101010101101 01110111010110 10111011010101 11110101010101 00010101010101 01011010101110
Tuhat miljoonaa laskutoimitusta sekunnissa def test(m: Long) = { var i = 1L var s = 0L } while(i <= m) { s = s + i i = i + 1 } s // s = 1 + 2 +... + m val NANOS_PER_SEC = 1e9 val test_start_time = System.nanoTime test(4000000000l) val test_end_time = System.nanoTime val test_duration = test_end_time - test_start_time println("test took %.2f seconds".format(test_duration/nanos_per_sec))
Intel Haswell konekieliesimerkki (***) 1029: c4 e2 7d 19 02 vbroadcastsd (%rdx),%ymm0 102e: c4 e2 7d 19 0c 0a vbroadcastsd (%rdx,%rcx,1),%ymm1 1034: c4 e2 7d 19 14 4a vbroadcastsd (%rdx,%rcx,2),%ymm2 103a: 48 83 c2 08 add $0x8,%rdx 103e: c5 fd 28 18 vmovapd (%rax),%ymm3 1042: c4 e2 fd b8 e3 vfmadd231pd %ymm3,%ymm0,%ymm4 1047: c4 e2 f5 b8 eb vfmadd231pd %ymm3,%ymm1,%ymm5 104c: c4 e2 ed b8 f3 vfmadd231pd %ymm3,%ymm2,%ymm6 1051: c5 fd 28 58 20 vmovapd 0x20(%rax),%ymm3 1056: c4 e2 fd b8 fb vfmadd231pd %ymm3,%ymm0,%ymm7 105b: c4 62 f5 b8 c3 vfmadd231pd %ymm3,%ymm1,%ymm8 1060: c4 62 ed b8 cb vfmadd231pd %ymm3,%ymm2,%ymm9 1065: c5 fd 28 58 40 vmovapd 0x40(%rax),%ymm3 106a: c4 62 fd b8 d3 vfmadd231pd %ymm3,%ymm0,%ymm10 106f: c4 62 f5 b8 db vfmadd231pd %ymm3,%ymm1,%ymm11 1074: c4 62 ed b8 e3 vfmadd231pd %ymm3,%ymm2,%ymm12 1079: c5 fd 28 58 60 vmovapd 0x60(%rax),%ymm3 107e: c4 62 fd b8 eb vfmadd231pd %ymm3,%ymm0,%ymm13 1083: c4 62 f5 b8 f3 vfmadd231pd %ymm3,%ymm1,%ymm14 1088: c4 62 ed b8 fb vfmadd231pd %ymm3,%ymm2,%ymm15 108d: 48 01 c8 add %rcx,%rax 1090: 48 ff cb dec %rbx 1093: 75 94 jne 1029 Esimerkki: Matriisikertolaskualirutiinin sisin silmukka Intel x86 64 konekielellä käyttäen hyväksi Haswell- mikroarkkitehtuurin tukemia AVX2 & FMA -käskykantalaajennuksia https://github.com/pkaski/cluster-play/blob/master/haswell-mm-test/libmynative.c
? 1029: c4 e2 7d 19 02 vbroadcastsd (%rdx),%ymm0 102e: c4 e2 7d 19 0c 0a vbroadcastsd (%rdx,%rcx,1),%ymm1 1034: c4 e2 7d 19 14 4a vbroadcastsd (%rdx,%rcx,2),%ymm2 103a: 48 83 c2 08 add $0x8,%rdx 103e: c5 fd 28 18 vmovapd (%rax),%ymm3 1042: c4 e2 fd b8 e3 vfmadd231pd %ymm3,%ymm0,%ymm4 1047: c4 e2 f5 b8 eb vfmadd231pd %ymm3,%ymm1,%ymm5 104c: c4 e2 ed b8 f3 vfmadd231pd %ymm3,%ymm2,%ymm6 1051: c5 fd 28 58 20 vmovapd 0x20(%rax),%ymm3 1056: c4 e2 fd b8 fb vfmadd231pd %ymm3,%ymm0,%ymm7 105b: c4 62 f5 b8 c3 vfmadd231pd %ymm3,%ymm1,%ymm8 1060: c4 62 ed b8 cb vfmadd231pd %ymm3,%ymm2,%ymm9 1065: c5 fd 28 58 40 vmovapd 0x40(%rax),%ymm3 106a: c4 62 fd b8 d3 vfmadd231pd %ymm3,%ymm0,%ymm10 106f: c4 62 f5 b8 db vfmadd231pd %ymm3,%ymm1,%ymm11 1074: c4 62 ed b8 e3 vfmadd231pd %ymm3,%ymm2,%ymm12 1079: c5 fd 28 58 60 vmovapd 0x60(%rax),%ymm3 107e: c4 62 fd b8 eb vfmadd231pd %ymm3,%ymm0,%ymm13 1083: c4 62 f5 b8 f3 vfmadd231pd %ymm3,%ymm1,%ymm14 1088: c4 62 ed b8 fb vfmadd231pd %ymm3,%ymm2,%ymm15 108d: 48 01 c8 add %rcx,%rax 1090: 48 ff cb dec %rbx 1093: 75 94 jne 1029 Intel Haswell konekieliesimerkki (***) Esimerkki: Matriisikertolaskualirutiinin sisin silmukka Intel x86 64 konekielellä käyttäen hyväksi Haswell- mikroarkkitehtuurin tukemia AVX2 & FMA -käskykantalaajennuksia https://github.com/pkaski/cluster-play/blob/master/haswell-mm-test/libmynative.c
Tietokoneen mysteeri Millä periaatteilla tietokone toimii? Mitä on laskenta?
Miksi ohjelmoijan on tärkeä ymmärtää tietokoneen keskeiset toimintaperiaatteet?
Tietokone on kone ymmärrys periaatteista millä kone toimii kuuluu oleellisesti ohjelmoijan ammattitaitoon Taito käyttää konetta sovelluksissa koneen suorituskyvyn äärirajoilla Fyysinen laitteisto ( hardware ) ja ohjelmat ( software ) ovat keskinäisessä vuorovaikutuksessa suunnittelusta suoritukseen Uteliaisuus ja oivaltamisen riemu maailma laskennan silmin
#3 top500.org (***) Each node has an NVIDIA Tesla K20X card (2688 cores @ 732 MHz) (4 nodes) (8 blades) (3 cages) (18,688 GPUs, 50,233,344 cores) [From Tiwari et al., Reliability Lessons Learned From GPU Experience With The Titan Supercomputer at Oak Ridge Leadership Computing Facility, Supercomputing 2015 (Austin TX, Nov. 15 20, 2015).]
Tietokoneiden fysikaalisista rajoista (***) [From Tiwari et al., Reliability Lessons Learned From GPU Experience With The Titan Supercomputer at Oak Ridge Leadership Computing Facility, Supercomputing 2015 (Austin TX, Nov. 15 20, 2015).]
Toimintaperiaatteet a) loogisella tasolla b) fysikaalisella tasolla
Tietokoneen mysteeri (4 kierrosta) 2. Bitit ja data binäärilukujärjestelmä, bittien käsittely Scalalla 3. Kombinaatiologiikka 4. Sekventiaalilogiikka 5. Ohjelmoitava kone logiikkaporteista rakennettuja piirejä Scala-simuloituna kello ja takaisinkytkentä Scala-simulaatioon, prosessorin laskentapolku konekieliohjelmoimme 5574-porttista Scalalla rak. & simuloitua armlet -prosessoria
Kierros 2: Bitit ja data Data on jono bittejä Suuruusluokista Datalla on formaatti (Scalan tietotyyppien formaatit) Binäärilukujärjestelmä (2-kantainen lukujärjestelmä) Bittien käsittelyä Scalalla Liukuluvut (IEEE 754 2008) (*)
Bitti 0 1 Engl. bit (lyhennetty binary digit ) Perusyksikkö informaatiota esitettäessä Claude E. Shannon [A mathematical theory of communication. Bell System Tech. J. 27 (1948) 379 423, 623 656] mukaan J. W. Tukey otti sanan bit käyttöön tarkoittamaan binäärilukujärjestelmän numeroa 0 tai 1.
Bittijono ( data ) 0 0 1 0 0 1 0 1 1 1 0 1 0 0 0 1 Kaikki laskennassa tarkasteltava informaatio esitetään jonona bittejä ( datana ) Datan määrää mitataan bitteinä (= montako bittiä jono sisältää)
Suuruusluokista Datan määrää mitataan tyypillisesti bitteinä tai tavuina (engl. byte) [1 tavu = 8 bittiä] Määrän suuruusluokka on tapana ilmaista SI-etuliitteitä (kilo, mega, giga, jne.) käyttäen Suuruusluokat on tapana ilmaista joko tavanomaisesti 10-kantaisina suuruusluokkina tai vaihtoehtoisesti 2-kantaisina suuruusluokkina
10-kantaiset suuruusluokat
2-kantaiset suuruusluokat (lue: kilobinääri, megabinääri, )
Esimerkki: megabitti ja terabitti Oletetaan, että yksi bitti voidaan tallentaa neliömillimetrin pinta-alalle Tällöin yksi megabitti (10 6 bittiä) tallentuu neliömetrille Otaniemi (Google Earth) Yksi terabitti (10 12 bittiä) puolestaan tallentuu neliökilometrille
Terabinääritavu suorituskykyesimerkki Single core All 24 cores Read (consecutive 64-bit words) Read (random 512-bit cache lines) Read (random 64-bit words) 3.7 GiB/s 18 GiB/s 0.74 GiB/s 7.5 GiB/s 0.15 GiB/s 1.9 GiB/s 4 x 2.67-GHz Intel Xeon X7542 (Nehalem, 6 cores, 18 MiB last-level cache) 1 TiB main memory (64 x 16 GiB DDR3-1066 SDRAM) HP Proliant DL580 G7 Aalto-yliopisto, triton -laskentaklusteri fn01.triton.aalto.fi fn02.triton.aalto.fi
Petatavu https://databricks.com/blog/2014/10/10/spark-petabyte-sort.html
$144.22 / 100 TB https://databricks.com/blog/2016/11/14/setting-new-world-record-apache-spark.html
Mitä data esittää? Jono bittejä on vain tylsä jono nollia ja ykkösiä 0 0 1 0 0 1 0 1 1 1 0 1 0 0 0 1 Jotta bittijonosta tulee mielenkiintoisempi, tarvitaan lisäksi sopimuksia ja käytänteitä siitä mitä bittijonolla esitetään
27550 = 145 x 190 bittiä http://search.dilbert.com/search?w=planet+zorp&x=0&y=0
64 bittiä 0100000000001001001000011111101101010100010001000010110100011000 scala.math.pi (3.141592653589793115997963468544185161590576171875) IEEE Std 754 2008 http://dx.doi.org/10.1109%2fieeestd.2008.4610935
256 bittiä 0010000101000111011100100110010101100101011101000110100101101110 0110011101110011001000000110011001110010011011110110110100100000 0111010001101000011001010010000001110000011011000110000101101110 0110010101110100001000000101101001101111011100100111000000100001!Greetings from the planet Zorp! Unicode (UTF-8) http://unicode.org
625 bittiä http://www.qrcode.com/en/about/standards.html
Data ja datan formaatti Varsinaisen datan (=bittijono) lisäksi tarvitaan sopimus siitä mitä data esittää Tällaista sopimusta tai käytännettä siitä mitä data esittää kutsutaan formaatiksi tai vaihtoehtoisesti datan tyypiksi
Numeerinen ja tekstuaalinen data Useimmat ohjelmat käsittelevät ainakin toista seuraavista: numeerinen data (= data joka esittää lukuja) tekstuaalinen data (= data joka esittää tekstiä)
Numeerinen ja tekstuaalinen data Myös Scala-kielen perustietotyypit (perusdatatyypit) jakautuvat luonnollisesti numeerisiin ja tekstuaalisiin tyyppeihin: numeeriset Byte, Short, Int, Long, Float, Double tekstuaaliset Char, String
Sana, sananpituus Tietokone on rakennettu käsittelemään dataa palasissa, joissa on kiinteä määrä bittejä (esimerkiksi 8, 16, 32, 64, tai 128 bittiä) Tällaisia palasia kutsutaan sanoiksi ( word ) Prosessoriarkkitehtuurin sananpituus tai sananleveys ( word length ) on pisin sanan bittimäärä, jota prosessori tukee käskykannassaan Esimerkiksi ilmaisu 64-bittinen prosessori tyypillisesti viittaa siihen, että prosessoriarkkitehtuurin sananleveys on 64 bittiä
Scala-perustietotyyppien pituudet biteissä Scala on suunniteltu laitteistoriippumattomaksi (käytettäväksi eri laitteistoalustoilla) Scalan perustietotyypeillä on seuraavat kiinteät mitat biteissä: Byte (8 bittiä) Short (16 bittiä) Int (32 bittiä) Long (64 bittiä) Char (16 bittiä) Jos laitteisto ei tue suoraan jotakin edellisistä, tuki on toteutettu ohjelmallisesti (Scala-)ohjelmoijalle näkymättömällä tavalla
Bitit näkyviin Scalalla [ demo ]
Kuinka esittää kokonaislukuja? Luku 754 voidaan esittää monella tavalla Roomalaisessa lukujärjestelmässä DCCLIV Desimaalilukujärjestelmässä 754 Binäärilukujärjestelmässä 1011110010... Zorp-planeetalla on päädytty esitykseen [verkkolukemistossa laajemmin, ml. rationaaliluvut ja liukuluvut]
Binäärilukujärjestelmä Binäärilukujärjestelmässä (= 2-kantaisessa lukujärjestelmässä) on helppo laskea Vrt. kerro kaksi roomalaista numeroa keskenään, tai opiskele ulkoa 10-järjestelmän yhteen- ja kertolaskutaulut Tietokoneet käyttävät binäärilukujärjestelmää Binääriluvut (ja 16-kantaiset heksadesimaaliluvut) kuuluvat ohjelmoijan yleissivistykseen
Heksadesimaaliluvut Yksi heksadesimaalinumero vastaa 4 bitin jonoa: Esimerkki (25257):
Binääriluvun bittipaikat eniten merkitsevä numero bittipaikka vähiten merkitsevä numero
Desimaalista binääriksi Syöte: 10-kantainen 2 Z 0 Alusta lopputuloksen kaikki bitit pois päältä (arvoon 0) Toista kunnes Vähennä luvusta siten, että = 0 2 j 2 j 0 suurin mahd. Aseta bitti j päälle (arvoon 1) 2 0 = 1 2 1 = 2 2 2 = 4 2 3 = 8 2 4 = 16 2 5 = 32 2 6 = 64 2 7 = 128 2 8 = 256 2 9 = 512 2 10 = 1024.
Binääristä desimaaliksi Syöte: 2-kantainen 2 Z 0 Alusta lopputulos arvoon 0 Toista jokaiselle bittipaikalle j Jos bitti j on päällä (arvossa 1), lisää lopputulokseen 2 j 2 0 = 1 2 1 = 2 2 2 = 4 2 3 = 8 2 4 = 16 2 5 = 32 2 6 = 64 2 7 = 128 2 8 = 256 2 9 = 512 2 10 = 1024.
Harjoituksissa Muunnoksia kantalukujen 2 ja 10 välillä Sanan bittien käsittelyä bitin arvo? bitti päälle (arvoon 1, set ) bitti pois (arvoon 0, reset, clear, mask ) bitin kytkeminen (vastakkaiseen arvoon, toggle ) sanan vieritys vasemmalle ( left shift ) sanan vieritys oikealle ( right shift ) sanan aritmeettinen vieritys oikealle ( arithmetic right shift ) Liukulukujen ( floating point number ) alkeet
Boolen operaatiot biteille JA TAI POIS- SULKEVA EI TAI (minimi) (maksimi) (summa, (käännä pariteetti) arvo)
Arvojen pakottaminen ja kytkeminen
Boolen operaatiot sanoille bittioperaatiot monibittisille sanoille toimivat jokaiselle bittipaikalle erikseen
Sanan arvojen pakottaminen ja kytkeminen
Bittipaikkojen vieritys ( shift )
Esimerkki: Heksadesimaalisyöte Scalalla scala> val y = 0x3E7 y: Int = 999
Esimerkki: Heksadesimaalituloste Scalalla def tohexstring(v: Int): String = "0x%X".format(v) scala> tohexstring(754) res: String = 0x2F2 scala> tohexstring(999) res: String = 0x3E7 scala> tohexstring(0x3e7) res: String = 0x3E7
Esimerkki: bittipaikan arvo scala> val x = 0x3A // 111010 in binary x: Int = 58 scala> (x >> 0)&1 // value of bit at position 0 res: Int = 0 scala> (x >> 1)&1 // value of bit at position 1 res: Int = 1 scala> (x >> 2)&1 // value of bit at position 2 res: Int = 0 scala> (x >> 3)&1 //... res: Int = 1 scala> (x >> 4)&1 res: Int = 1 scala> (x >> 5)&1 res: Int = 1 scala> (x >> 6)&1 res: Int = 0
Esimerkki: täsmälleen bittipaikka j on arvossa 1 1 << j (32-bittinen sana; Int) 1L << j (64-bittinen sana; Long)
Entäpä liukuluvut? scala> 0.3-0.1 res: Double = 0.19999999999999998 Miksi tulos ei ole 0.2?
Liukulukustandardi IEEE Std 754 2008 http://dx.doi.org/10.1109%2fieeestd.2008.4610935 Float = IEEE 754-2008 binary32 Double = IEEE 754-2008 binary64
IEEE 754-2008 binary64 -liukuluku lähimpänä 0.3 scala> tellaboutdouble(0.3) I am a 64-bit word that Scala views as having format 'Double'...... my bits are, in binary, (0011111111010011001100110011001100110011001100110011001100110011)_2... or equivalently, in hexadecimal, 0x3FD3333333333333... Scala prints me out as 0.3... indeed, my bits acquire meaning as specified in the binary interchange format 'binary64' in the IEEE Std 754-2008 IEEE Standard for Floating-Point Arithmetic http://dx.doi.org/10.1109%2fieeestd.2008.4610935... this format is a bit-packed format with three components: (0011111111010011001100110011001100110011001100110011001100110011)_2 a) the sign (bit 63): 0 b) the biased exponent (bits 62 to 52): 01111111101 c) the trailing significand (bits 51 to 0): 0011001100110011001100110011001100110011001100110011... my biased exponent 1021 indicates that I am a _normalized_ number with a leading 1-digit in my significand and an unbiased exponent -2 = 1021-1023... that is, in _binary radix point notation_, I am exactly (1.0011001100110011001100110011001100110011001100110011)_2 * 2^{-2}... or what is the same in _decimal radix point notation_, I am exactly 0.299999999999999988897769753748434595763683319091796875 52 radiksipisteen jälkeistä bittiä tarkkuutta
IEEE 754-2008 binary64 -liukuluku lähimpänä 0.1 scala> tellaboutdouble(0.1) I am a 64-bit word that Scala views as having format 'Double'...... my bits are, in binary, (0011111110111001100110011001100110011001100110011001100110011010)_2... or equivalently, in hexadecimal, 0x3FB999999999999A... Scala prints me out as 0.1... indeed, my bits acquire meaning as specified in the binary interchange format 'binary64' in the IEEE Std 754-2008 IEEE Standard for Floating-Point Arithmetic http://dx.doi.org/10.1109%2fieeestd.2008.4610935... this format is a bit-packed format with three components: (0011111110111001100110011001100110011001100110011001100110011010)_2 a) the sign (bit 63): 0 b) the biased exponent (bits 62 to 52): 01111111011 c) the trailing significand (bits 51 to 0): 1001100110011001100110011001100110011001100110011010... my biased exponent 1019 indicates that I am a _normalized_ number with a leading 1-digit in my significand and an unbiased exponent -4 = 1019-1023... that is, in _binary radix point notation_, I am exactly (1.1001100110011001100110011001100110011001100110011010)_2 * 2^{-4}... or what is the same in _decimal radix point notation_, I am exactly 0.1000000000000000055511151231257827021181583404541015625
0.3 0.1 suoritettuna binary64 -liukuluvuilla
Tulosta lähin binary64 -liukuluku scala> tellaboutdouble(0.3-0.1) I am a 64-bit word that Scala views as having format 'Double'...... my bits are, in binary, (0011111111001001100110011001100110011001100110011001100110011001)_2... or equivalently, in hexadecimal, 0x3FC9999999999999... Scala prints me out as 0.19999999999999998... indeed, my bits acquire meaning as specified in the binary interchange format 'binary64' in the IEEE Std 754-2008 IEEE Standard for Floating-Point Arithmetic http://dx.doi.org/10.1109%2fieeestd.2008.4610935... this format is a bit-packed format with three components: (0011111111001001100110011001100110011001100110011001100110011001)_2 a) the sign (bit 63): 0 b) the biased exponent (bits 62 to 52): 01111111100 c) the trailing significand (bits 51 to 0): 1001100110011001100110011001100110011001100110011001... my biased exponent 1020 indicates that I am a _normalized_ number with a leading 1-digit in my significand and an unbiased exponent -3 = 1020-1023... that is, in _binary radix point notation_, I am exactly (1.1001100110011001100110011001100110011001100110011001)_2 * 2^{-3}... or what is the same in _decimal radix point notation_, I am exactly 0.1999999999999999833466546306226518936455249786376953125
Liukuluvut IEEE Std 754 2008 http://dx.doi.org/10.1109%2fieeestd.2008.4610935 Float = IEEE 754-2008 binary32 Double = IEEE 754-2008 binary64 Liukuluvut ovat rationaalilukuja, joilla on merkitseviltä numeroiltaan ja eksponentiltaan kiinteään määrään bittejä katkaistu normalisoitu kantaluvun 2 radiksipiste-esitys [lisää lukemistossa] Liukuluvuilla ammattimaisesti laskettaessa on hyvä olla tietoinen liukulukujen ominaisuuksista tutustu standardiin ja muista, että lasket kiinteästi valituilla 2 32 (2 64 ) rationaaliluvulla, jotka ovat sitä harvemmassa mitä isommaksi luvut itseisarvoltaan tulevat
Tehtävät bitsquiz muunnamme 2-kannan ja 10-kannan välillä wordops bittioperaatioita sanoille (montako 1-bittiä sanassa jne.) parity pariteettibitin laskeminen ja tarkistaminen float liukulukuihin tutustumista ja sudenkuoppia base64 64-kantainen koodaus binääristä tekstiksi errorcorrect (haastetehtävä) yhden bitin virheenkorjaus, esimerkiksi Hamming-koodilla rationaldecompose (haastetehtävä) rationaaliluvun jaksollinen radiksipistehajotelma