Operácie

Typy premenných v avr-gcc: Rozdiel medzi revíziami

Z SensorWiki

(Aritmetické operácie so základnými typmi)
Riadok 65: Riadok 65:
  
 
   
 
   
Ako to potom vyzerá s jednoduchými aritmetickými operáciami?
+
Pozrime sa podrobnejšie, aká je výpočtová náročnosť pre jednoduché aritmetické operácie. Ak by ste si to chceli vyskúšať, je potrebné deklarovať premenné ako volatile, inak kompilátor (vcelku rozumne) usúdi, že premenné, s ktorými nič nerobíme nie sú potrebné a z kódu ich vyhodí. V komentároch na každom riadku uvádzame okrem veľkosti premennej v pamäti aj na koľko inštrukcií sa preloží daný riadok a koľko bude trvať jeho vykonávanie. Nepočítali sme presne počet strojových cyklov, uspokojili sme sa s odčítaním času v simulátore. Hodnoty platia pre kryštál 16 MHz. Veľkosť kódu je len orientačná, tam kde sa volali špecifické podprogramy uvádzame CALL.
+
 
                      //  S vypnutou optimalizaciou
+
<source lang="c++" style="background: LightYellow;">
                      //      Premenna:           Kod:
+
 
  //  Miesto v pamati    Velkost a Rychlost
+
                    //      Premenna:               Kod:                                Poznamka:
   int_y =    int_x + 3;   //      2 Byte          5 instrukcii / 18 Byte   0,63 us    - 2Byte vyber z pamati, scitaj (s vyhodou ADIW R24,0x03 Add immediate to word) a vrat do pamati
+
                            //  Miesto v pamati    Počet inštrukcií  Veľkosť kódu  Rýchlosť
   char_y =  char_x + 3;   //      1 Byte          3 instrukcie / 10 Byte   0,01 us
+
  log_y =  !log_x;        //      1 Byte          5 instrukcii      14 Bytov      0,44 us 
   long_y =  long_x + 3;   //      4 Byte        11 instrukcii /38 Byte   1,25 us   - lebo uz tahame a ukladame 4 bajty z pamati a do pamate
+
   int_y =    int_x + 3;   //      2 Byte          5 instrukcii       18 Byte       0,63 us    - 2 Byte vyber z pamati, scitaj (s vyhodou ADIW - Add immediate to word) a vrat do pamati
  float_y =  float_x + 3;   //      4 Byte        17 instrukcii + CALL / ?? Byte 8,06 us - volame podprogram pre floaty
+
   char_y =  char_x + 3;   //      1 Byte          3 instrukcie       10 Byte       0,31 us
double_y = double_x + 3;   //      4 Byte        17 instrukcii + CALL / ?? Byte 8,06 us - volame podprogram pre floaty
+
   long_y =  long_x + 3;   //      4 Byte        11 instrukcii       38 Byte       1,25 us   - lebo tu uz tahame a ukladame 4 bajty z pamati a do pamate
 +
  float_y =  float_x + 3;   //      4 Byte        17 instrukcii       + CALL         8,06 us   - volame podprogram pre floaty
 +
double_y = double_x + 3;   //      4 Byte        17 instrukcii       + CALL         8,06 us   - toto je presne to iste ako float
 +
 
 +
</source>
 +
 
 +
No a takto to vyzerá zasa s tými zložitejšími operáciami
  
 +
<source lang="c++" style="background: LightYellow;">
  
No a takto zasa s tými zložitejšími
+
                    //      Premenna:                Kod:                                Poznamka:
 +
                            //  Miesto v pamati    Počet inštrukcií  Veľkosť kódu  Rýchlosť
 
   
 
   
//  S vypnutou optimalizaciou
 
                      //      Premenna:          Kod:
 
  //  Miesto v pamati    Velkost a Rychlost
 
 
   int_y =    int_x / 3;  //      2 Byte        10 instrukcii + CALL / 18 Byte  15,19 us    - lebo na / uz nie je instrukcia!
 
   int_y =    int_x / 3;  //      2 Byte        10 instrukcii + CALL / 18 Byte  15,19 us    - lebo na / uz nie je instrukcia!
 
   int_y =    int_x / 2;  //      2 Byte        10 instrukcii + CALL / 18 Byte  0,81 us    - lebo /2 je >> !
 
   int_y =    int_x / 2;  //      2 Byte        10 instrukcii + CALL / 18 Byte  0,81 us    - lebo /2 je >> !
Riadok 90: Riadok 95:
 
double_y = double_x + 3;  //      4 Byte        17 instrukcii + CALL / ?? Byte 8,06 us - volame podprogram pre floaty
 
double_y = double_x + 3;  //      4 Byte        17 instrukcii + CALL / ?? Byte 8,06 us - volame podprogram pre floaty
  
 
+
</source>
 
 
  
 
== Potrebujem vo svojom programe pracovať s reálnymi číslami! ==
 
== Potrebujem vo svojom programe pracovať s reálnymi číslami! ==

Verzia zo dňa a času 14:48, 13. máj 2021

Základné[1] typy premenných v avr-gcc

K dispozícii máme všetky bežné typy, ktoré sa používajú v jazyku C.

                 Veľkosť             Rozsah
                  
  (signed) char  1 Byte (8 bitov)    <−127, +127>
  unsigned char  1 Byte (8 bitov)    <0, 255>  
  
    signed int   2 Byty (16 bitov)   <−32,767, +32,767>
  unsigned int                       <0, 65,535>
   
   signed long   4 Byty (32 bitov)   <−2,147,483,647, +2,147,483,647>
 unsigned long                       <0, 4,294,967,295>
  
         float   4 Byty (32 bitov)    IEEE-754  https://en.wikipedia.org/wiki/Single-precision_floating-point_format    
   
        double    =float[2]

Okrem toho má programátor k dispozíci aj nové typy podľa štandardu C99, ktoré majú pevne definovanú veľkosť a tým pádom je zdrojový kód prenositeľnejší. Tieto typy nájdete v knižnici <inttypes.h> a sú dostupné aj cez hlavičkový súbor (header) <stdint.h>.

        int8_t  1 Byte (8 bitov)      je to alias pre signed char
       uint8_t                        8-bit unsigned type
     
       int16_t  2 Byty (16 bitov)     = signed int /  16-bit signed type
      uint16_t                        16-bit unsigned type. 
      
       int32_t  4 Byty (32 bitov)     32-bit signed type
      uint32_t                        32-bit unsigned type
     
       int64_t  8 Bytov (64 bitov)    64-bit signed type[3]
      uint64_t                        64-bit unsigned type


Okrem vyššieuvedených pridáva C99 aj typ bool definovaný v <stdbool.h> headri. Okrem toho sú tam aj makrá pre hodnoty true and false.

Má zmysel používať tento nový typ, keď aj tak zeberie 1 bajt podobne ako unsigned char? Rozdiel je vidieť v nasledovnom príklade. Používame v ňom aj deklaráciu volatile, aby nám pri pokusoch kompilátor nevyhodnotil tento kód ako nevyužitý a nevyhodil ho celkom z výsledného programu.

 #include <stdbool.h>

 volatile bool  log_x; 
 volatile char char_x;
 
 main(void)
 {
    log_x = 255;            // obsahuje true
   char_x = 255;	    // obsahuje 255, cize true
 
    log_x =  log_x + 1;     // stale obsahuje true, pretoze 1+1 = 2 a to je nenulova hodnota, cize true
   char_x = char_x + 1;     // tu bude 0, cize false, pretoze 255+1=256, hodnota pretecie a dostaneme nulu, cize false

 }


Poznámky:

  1. Zatiaľ vynechávame polia, smerníky a typy Enum, Union a pod.
  2. Anywhere the compiler sees "double", it says to itself, "Aha! The puny human said double. But I know better, so I'll replace it with float. Muwahahaha!"
  3. Note: This types are not available when the compiler option -mint8 is in effect.


Aritmetické operácie so základnými typmi

Pozrime sa podrobnejšie, aká je výpočtová náročnosť pre jednoduché aritmetické operácie. Ak by ste si to chceli vyskúšať, je potrebné deklarovať premenné ako volatile, inak kompilátor (vcelku rozumne) usúdi, že premenné, s ktorými nič nerobíme nie sú potrebné a z kódu ich vyhodí. V komentároch na každom riadku uvádzame okrem veľkosti premennej v pamäti aj na koľko inštrukcií sa preloží daný riadok a koľko bude trvať jeho vykonávanie. Nepočítali sme presne počet strojových cyklov, uspokojili sme sa s odčítaním času v simulátore. Hodnoty platia pre kryštál 16 MHz. Veľkosť kódu je len orientačná, tam kde sa volali špecifické podprogramy uvádzame CALL.

	                    //      Premenna:                Kod:                                 Poznamka:
                            //   Miesto v pamati    Počet inštrukcií   Veľkosť kódu   Rýchlosť 
   log_y =   !log_x;        //       1 Byte          5 instrukcii       14 Bytov       0,44 us  
   int_y =    int_x + 3;    //       2 Byte          5 instrukcii       18 Byte        0,63 us    - 2 Byte vyber z pamati, scitaj (s vyhodou ADIW - Add immediate to word) a vrat do pamati
  char_y =   char_x + 3;    //       1 Byte          3 instrukcie       10 Byte        0,31 us
  long_y =   long_x + 3;    //       4 Byte         11 instrukcii       38 Byte        1,25 us    - lebo tu uz tahame a ukladame 4 bajty z pamati a do pamate
 float_y =  float_x + 3;    //       4 Byte         17 instrukcii       + CALL         8,06 us    - volame podprogram pre floaty
double_y = double_x + 3;    //       4 Byte         17 instrukcii       + CALL         8,06 us    - toto je presne to iste ako float

No a takto to vyzerá zasa s tými zložitejšími operáciami

	                    //      Premenna:                Kod:                                 Poznamka:
                            //   Miesto v pamati    Počet inštrukcií   Veľkosť kódu   Rýchlosť 
 
   int_y =    int_x / 3;   //       2 Byte         10 instrukcii + CALL / 18 Byte  15,19 us    - lebo na / uz nie je instrukcia!
   int_y =    int_x / 2;   //       2 Byte         10 instrukcii + CALL / 18 Byte  0,81 us    - lebo /2 je >> !
  char_y =   char_x / 3;   //       1 Byte         5 instrukcie + CALL	/ 10 Byte   5,38 us
  long_y =   long_x / 3;   //       4 Byte         11 instrukcii /38 Byte  39,37 us   - lebo uz tahame a ukladame 4 bajty z pamati a do pamate
 float_y =    int_x / 3;   //       ZLE: tu je vysledok 0, lebo celociselne delenie len ulozime do float 4 Byte         17 instrukcii + CALL / ?? Byte 17,38 us - volame podprogram pre floaty
 float_y =  float_x / 3.0; //       4 Byte         17 instrukcii + CALL / ?? Byte 30,81 us - volame podprogram pre floaty
double_y = double_x + 3;   //       4 Byte         17 instrukcii + CALL / ?? Byte 8,06 us - volame podprogram pre floaty

Potrebujem vo svojom programe pracovať s reálnymi číslami!

Aj tak potrebujem reálne čísla!

Literatúra