C99 základní informace o standardu programovacího jazyka C Výpočty v přesné aritmetice

Podobné dokumenty
C99 základní informace o standardu programovacího jazyka C Výpočty v přesné aritmetice

Preprocesor. Karel Richta a kol. katedra počítačů FEL ČVUT v Praze. Karel Richta, Martin Hořeňovský, Aleš Hrabalík, 2016

Operační systémy. Cvičení 4: Programování v C pod Unixem

IUJCE 07/08 Přednáška č. 1

PROGRAMOVÁNÍ V C++ CVIČENÍ

Programování v C++ 1, 1. cvičení

Algoritmizace a programování

ZPRO v "C" Ing. Vít Hanousek. verze 0.3

Úvod do jazyka C. Ing. Jan Fikejz (KST, FEI) Fakulta elektrotechniky a informatiky Katedra softwarových technologií

VÝUKOVÝ MATERIÁL. Bratislavská 2166, Varnsdorf, IČO: tel Číslo projektu

C++ objektově orientovaná nadstavba programovacího jazyka C

Základní datové typy, proměnné - deklarujeme předem - C je case sensitive rozlišuje malá a velká písmena v názvech proměnných a funkcí

Operační systémy. Cvičení 3: Programování v C pod Unixem

Příkazy preprocesoru - Před překladem kódu překladačem mu předpřipraví kód preprocesor - Preprocesor vypouští nadbytečné (prázdné) mezery a řádky -

Jazyk C++, některá rozšíření oproti C

2 Základní funkce a operátory V této kapitole se seznámíme s použitím funkce printf, probereme základní operátory a uvedeme nejdůležitější funkce.

Martin Flusser. Faculty of Nuclear Sciences and Physical Engineering Czech Technical University in Prague. October 17, 2016

Programovací jazyk C++ Hodina 1

Př. další použití pointerů

Základy programování (IZP)

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

C++ objektově orientovaná nadstavba programovacího jazyka C

Ukazatele, dynamická alokace

8. lekce Úvod do jazyka C 3. část Základní příkazy jazyka C Miroslav Jílek

9. lekce Úvod do jazyka C 4. část Funkce, rekurze Editace, kompilace, spuštění Miroslav Jílek

Pokročilé programování v jazyce C pro chemiky (C3220) Pokročilá témata jazyka C++

2 Datové typy v jazyce C

for (i = 0, j = 5; i < 10; i++) { // tělo cyklu }

Preprocesor a koncepce (větších) programů. Úvod do programování 2 Tomáš Kühr

Odvozené a strukturované typy dat

Abstraktní třídy, polymorfní struktury

IUJCE 07/08 Přednáška č. 4. v paměti neexistuje. v paměti existuje

C++ Akademie SH. 2. Prom nné, podmínky, cykly, funkce, rekurze, operátory. Michal Kvasni ka. 20. b ezna Za áte níci C++

Obsah. Předmluva 13 Zpětná vazba od čtenářů 14 Zdrojové kódy ke knize 15 Errata 15

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

Množina čísel int stl-set-int.cpp

přetížení operátorů (o)

PB161 Programování v jazyce C++ Přednáška 10

Dílčí příklady použití jazykových konstrukcí v projektu. Jazyk C Příklady. Pravidla překladu v gmake. Zadání

Lekce 6 IMPLEMENTACE OPERAČNÍHO SYSTÉMU LINUX DO VÝUKY INFORMAČNÍCH TECHNOLOGIÍ JAZYK C

Úvod do programovacích jazyků (Java)

Koncepce (větších) programů. Základy programování 2 Tomáš Kühr

Algoritmizace a programování. Ak. rok 2012/2013 vbp 1. ze 44

Střední škola pedagogická, hotelnictví a služeb, Litoměříce, příspěvková organizace

IUJCE Přednáška č. 11. další prvky globální proměnné, řízení viditelnosti proměnných, funkcí

Úvod do programování. Lekce 1

Základy C++ I. Jan Hnilica Počítačové modelování 18

Základy jazyka C. Základy programování 1 Martin Kauer (Tomáš Kühr)

Základy programování (IZP)

PROGRAMOVÁNÍ V C++ URČENO PRO VZDĚLÁVÁNÍ V AKREDITOVANÝCH STUDIJNÍCH PROGRAMECH ROSTISLAV FOJTÍK

přetížení operátorů (o)

Dědění, polymorfismus

Datové typy pro reálná čísla

int => unsigned int => long => unsigned long => float => double => long double - tj. bude-li:

Základy programování (IZP)

Systém je citlivý na velikost písmen CASE SENSITIVE rozeznává malá velká písmena, např. PROM=1; PROm=1; PRom=1; Prom=1; prom=1; - 5 různých proměnných

Třídy a struktury v C++

PROMĚNNÉ, KONSTANTY A DATOVÉ TYPY TEORIE DATUM VYTVOŘENÍ: KLÍČOVÁ AKTIVITA: 02 PROGRAMOVÁNÍ 2. ROČNÍK (PRG2) HODINOVÁ DOTACE: 1

DTP Základy programování Úvod do předmětu

VÝUKOVÝ MATERIÁL. Bratislavská 2166, Varnsdorf, IČO: tel Číslo projektu

Pokročilé programování v jazyce C pro chemiky (C3220) Operátory new a delete, virtuální metody

Program převod z desítkové na dvojkovou soustavu: /* Prevod desitkove na binarni */ #include <stdio.h>

IUJCE 07/08 Přednáška č. 6

Programování v C++, 2. cvičení

Funkce, intuitivní chápání složitosti

6. lekce Úvod do jazyka C knihovny datové typy, definice proměnných základní struktura programu a jeho editace Miroslav Jílek

7 Formátovaný výstup, třídy, objekty, pole, chyby v programech

PB161 Programování v jazyce C++ Přednáška 10

Programování v jazyce C pro chemiky (C2160) 12. Specifické problémy při vývoji vědeckého softwaru

Algoritmizace a programování

Základy programování (IZP)

Konstruktory překladačů

Pole a Funkce. Úvod do programování 1 Tomáš Kühr

Programování v jazyce C pro chemiky (C2160) 3. Příkaz switch, příkaz cyklu for, operátory ++ a --, pole

Zápis programu v jazyce C#

for (int i = 0; i < sizeof(hodnoty) / sizeof(int); i++) { cout<<hodonoty[i]<< endl; } cin.get(); return 0; }

VÝUKOVÝ MATERIÁL. Bratislavská 2166, Varnsdorf, IČO: tel Číslo projektu

Programování v jazyce C pro chemiky (C2160) 4. Textové řetězce, zápis dat do souboru

Opakování programování

Šablony, kontejnery a iterátory

Výrazy a operátory. Operátory Unární - unární a unární + Např.: a +b

8 Třídy, objekty, metody, předávání argumentů metod

Abstraktní datové typy, moduly

Základy programování (IZP)

Objektově orientované programování

Datové typy pro reálná čísla

Funkce pokročilé možnosti. Úvod do programování 2 Tomáš Kühr

Základy programování. Úloha: Eratosthenovo síto. Autor: Josef Hrabal Číslo: HRA0031 Datum: Předmět: ZAP

Iterační výpočty. Dokumentace k projektu č. 2 do IZP. 24. listopadu 2004

- jak udělat konstantu long int: L long velka = 78L;

Střední škola pedagogická, hotelnictví a služeb, Litoměříce, příspěvková organizace

Základy programování (IZP)

Assembler - 5.část. poslední změna této stránky: Zpět

Lekce 19 IMPLEMENTACE OPERAČNÍHO SYSTÉMU LINUX DO VÝUKY INFORMAČNÍCH TECHNOLOGIÍ JAZYK C

Jazyk C++ 1. Blok 3 Objektové typy jazyka C++ Třída. Studijní cíl. Doba nutná k nastudování. Průvodce studiem

Šablony, kontejnery a iterátory

PŘEDNÁŠKA KURZU BPC2A

Např.: // v hlavičkovém souboru nebo na začátku // programu (pod include): typedef struct { char jmeno[20]; char prijmeni[20]; int rok_nar; } CLOVEK;

Mělká a hluboká kopie

Transkript:

C99 základní informace o standardu programovacího jazyka C Výpočty v přesné aritmetice Josef Dobeš Katedra radioelektroniky (13137), blok B2, místnost 722 dobes@fel.cvut.cz 15. května 2017 Strana 1 z 18 Praktické programování v C/C++ (České vysoké učení technické v Praze, Fakulta elektrotechnická)

1. Standardizace prvků jazyka ne dříve vždy povinných V nejrůznějších překladačích jazyka C se dříve víceméně dobrovolně dodržovaly určité obvyklé rysy, které sice striktně nebyly stanoveny standardy (jako je např. ANSI), nicméně většina překladačů je dodržovala. V důsledku toho se ovšem občas objevovaly problémy s přenositelností kódu odladěného v jednom překladači k použití pro překladač jiný. Standard C99 je poměrně rozsáhlý (texty standardu výrazně překračují 100 stran) a řeší tak mnoho problémů s kompatibilitou překladačů. Jako typický příklad lze uvést formátové konverze v standardních funkcích printf, fprintf, sprintf apod. Většina formátových konverzí jako jsou např. %d, %f pracuje samozřejmě stejně, ovšem časté potíže nastávaly v dodatečných specifikacích, např. pro long double apod. Strana 2 z 18

1. Standardizace prvků jazyka ne dříve vždy povinných V nejrůznějších překladačích jazyka C se dříve víceméně dobrovolně dodržovaly určité obvyklé rysy, které sice striktně nebyly stanoveny standardy (jako je např. ANSI), nicméně většina překladačů je dodržovala. V důsledku toho se ovšem občas objevovaly problémy s přenositelností kódu odladěného v jednom překladači k použití pro překladač jiný. Standard C99 je poměrně rozsáhlý (texty standardu výrazně překračují 100 stran) a řeší tak mnoho problémů s kompatibilitou překladačů. Jako typický příklad lze uvést formátové konverze v standardních funkcích printf, fprintf, sprintf apod. Většina formátových konverzí jako jsou např. %d, %f pracuje samozřejmě stejně, ovšem časté potíže nastávaly v dodatečných specifikacích, např. pro long double apod. Jako příklad zde uvedeme konverzi %Lf pro výstup long double, která již před přijetím standardu C99 fungovala ve většině překladačů. Nepracovala však správně v překladači GNU GCC (od jistých verzí) GCC totiž přejal kódy od Microsoft a ten (stejně jako Borland) standard C99 dosud plně nepodporuje (obě firmy jsou v současnosti zaměřeny především na C++). Pokud tedy chceme konverzí %Lf vypisovat long double, musíme jako option v překladači dát option -std=c99 (viz nastavení Code::Blocks), jinak se long double vypisuje nesprávně. Strana 2 z 18

1. Standardizace prvků jazyka ne dříve vždy povinných V nejrůznějších překladačích jazyka C se dříve víceméně dobrovolně dodržovaly určité obvyklé rysy, které sice striktně nebyly stanoveny standardy (jako je např. ANSI), nicméně většina překladačů je dodržovala. V důsledku toho se ovšem občas objevovaly problémy s přenositelností kódu odladěného v jednom překladači k použití pro překladač jiný. Standard C99 je poměrně rozsáhlý (texty standardu výrazně překračují 100 stran) a řeší tak mnoho problémů s kompatibilitou překladačů. Jako typický příklad lze uvést formátové konverze v standardních funkcích printf, fprintf, sprintf apod. Většina formátových konverzí jako jsou např. %d, %f pracuje samozřejmě stejně, ovšem časté potíže nastávaly v dodatečných specifikacích, např. pro long double apod. Jako příklad zde uvedeme konverzi %Lf pro výstup long double, která již před přijetím standardu C99 fungovala ve většině překladačů. Nepracovala však správně v překladači GNU GCC (od jistých verzí) GCC totiž přejal kódy od Microsoft a ten (stejně jako Borland) standard C99 dosud plně nepodporuje (obě firmy jsou v současnosti zaměřeny především na C++). Pokud tedy chceme konverzí %Lf vypisovat long double, musíme jako option v překladači dát option -std=c99 (viz nastavení Code::Blocks), jinak se long double vypisuje nesprávně. V následujícím zdrojovém souboru si povšimněme obvyklého způsobu získání přesnosti epsilon porovnáváním její postupně se zmenšující velikosti přičtené k jedné s jednou. Dále si povšimněme, že aby konstanta byla chápána jako long double, musí mít příponu (suffix) L (jinak je chápána jako double). Pro výpočet π si rovněž všimněme nezbytnosti použít long double verze funkce arkus tangens atanl, pro kterou je vstupem a výstupem číslo long double. Strana 2 z 18

Zdrojový soubor pro test přesnosti, který funguje pro Digital Mars i GNU GCC (a i pro jiné): #include <stdio.h> #include <math.h> typedef long double real; int main() { real a = 1, b1 = 3.1415926535897932384626434, // from Wikipedia to 25 decimal places b2 = 3.1415926535897932384626434L; // b1 is double, b2 is long double // epsilon computing while (1 + a/2!= 1) a /= 2; printf("length of 'long double' = %d, epsilon = %Lg\n", sizeof(a), a); // pi computing printf("pi to 23 decimal places = 3.14159265358979323846264 " "(Wikipedia)\n"); a = 4 * atanl((real)1); // atanl always gets 'long double' printf("pi to 23 decimal places = %25.23Lf\n(computed by ", a); #ifdef GNUC printf("gnu GCC Compiler with '-std=c99' option)\n"); #elif defined( DMC ) printf("digital Mars C Compiler)\n"); #else printf("another compiler)\n"); #endif printf("'double' - pi = %Lg, 'long double' - pi = %Lg\n", b1 - a, b2 - a); return b1!= b2? 0 : 1; Strana 3 z 18

Modul vytvořený překladačem Digital Mars (je dostupný z Code::Blocks) poskytne výsledek: length of 'long double' = 10, epsilon = 1.0842e-19 pi to 23 decimal places = 3.14159265358979323846264 (Wikipedia) pi to 23 decimal places = 3.14159265358979323850000 (computed by Digital Mars C Compiler) 'double' - pi = -1.22515e-16, 'long double' - pi = -2.1684e-19 Povšimněme, že proměnná long double je umístěna v deseti bytech. Z výsledné hodnoty epsilon je vidět, že lze počítat s přesností zhruba na devatenáct až dvacet platných cifer. Z výsledku na třetím řádku je dále vidět, že překladač Digital Mars dbá o to, aby se nevypisovala desetinná místa, která z principu nemohou být správně (požadovaná zbylá místa jsou doplněna nulami). Strana 4 z 18

Modul vytvořený překladačem Digital Mars (je dostupný z Code::Blocks) poskytne výsledek: length of 'long double' = 10, epsilon = 1.0842e-19 pi to 23 decimal places = 3.14159265358979323846264 (Wikipedia) pi to 23 decimal places = 3.14159265358979323850000 (computed by Digital Mars C Compiler) 'double' - pi = -1.22515e-16, 'long double' - pi = -2.1684e-19 Povšimněme, že proměnná long double je umístěna v deseti bytech. Z výsledné hodnoty epsilon je vidět, že lze počítat s přesností zhruba na devatenáct až dvacet platných cifer. Z výsledku na třetím řádku je dále vidět, že překladač Digital Mars dbá o to, aby se nevypisovala desetinná místa, která z principu nemohou být správně (požadovaná zbylá místa jsou doplněna nulami). Modul vytvořený překladačem GNU GCC (standardní v Code::Blocks) poskytne výsledek: length of 'long double' = 12, epsilon = 1.0842e-019 pi to 23 decimal places = 3.14159265358979323846264 (Wikipedia) pi to 23 decimal places = 3.14159265358979323851281 (computed by GNU GCC Compiler with '-std=c99' option) 'double' - pi = 0, 'long double' - pi = 0 Povšimněme, že proměnná long double je tentokrát umístěna v dvanácti bytech, což je dáno organizací paměti překladače GNU GCC. Mantisa a tedy přesnost výpočtu je ovšem stejná, o čemž svědčí vypočtená hodnota epsilon. Dále je zjevné, že překladač GNU GCC vypisuje i bity na konci, které z principu nemusí být správné (tj. více než dvacet platných cifer.) Strana 4 z 18

2. Některé z nových rysů standardu C99 byly převzaty z C++. Týká se to inline funkcí, komentářů uvedených //, rozptýlené příkazy a deklarace a proměnná viditelná pouze v rozsahu cyklu. 2.1. Funkce inline Nové klíčové slovo inline indikuje, že funkce by měla být rozvinuta inline, je-li to možné (záleží to na překladači; při rozvinutí inline nedochází k předávání parametrů a běh úlohy by tak měl být rychlejší). Moderní překladače však dokáží velmi dobře optimalizovat kód a deklarace inline tak postupně pozbývá svůj původní význam. Klasickým příkladem užití je alokování paměti: #include <sys/types.h> #include <malloc.h> inline void *allocate(size_t sz) { return malloc(sz); Strana 5 z 18

2. Některé z nových rysů standardu C99 byly převzaty z C++. Týká se to inline funkcí, komentářů uvedených //, rozptýlené příkazy a deklarace a proměnná viditelná pouze v rozsahu cyklu. 2.1. Funkce inline Nové klíčové slovo inline indikuje, že funkce by měla být rozvinuta inline, je-li to možné (záleží to na překladači; při rozvinutí inline nedochází k předávání parametrů a běh úlohy by tak měl být rychlejší). Moderní překladače však dokáží velmi dobře optimalizovat kód a deklarace inline tak postupně pozbývá svůj původní význam. Klasickým příkladem užití je alokování paměti: #include <sys/types.h> #include <malloc.h> inline void *allocate(size_t sz) { return malloc(sz); 2.2. Komentáře uvedené // Vedle tradičního užití komentářů /*... */ lze používat // jako v C++, přičemž konec řádku za // je chápán jako komentář. Většina překladačů jazyka C používala tento rys již řadu let, nyní se toto ovšem už stalo závaznou normou. Prostředí jako je Code::Blocks používají různé barvy k vytvoření hierarchie komentářů, např. Strana 5 z 18

#include <iostream> // Digital Mars C allows "#include <iostream.h>", too using namespace std; /** * This is a documentation comment block * @param xxx does this (this is the documentation keyword) * @authr some user (this is the documentation keyword error) */ int main(int argc, char **argv) { /// This is a documentation comment line int numbers[20], total = 0; double average; char ch = '\n'; for (int i = 0; i < 20; ++i) // a breakpoint is set { numbers[i] = i; total += i; average = total / 20.; std::cout << numbers[0] << ch << "..." << ch << numbers[19] << ch; /// cout without std:: is only allowed with 'using namespace std;' cout << "total: " << total << ", average: " << average << ch; std::cout << "put any character and press Enter... "; std::cin >> ch; std::cout << ch << " has been entered" << '\n'; Strana 6 z 18

2.3. Rozptýlené příkazy a deklarace V starších verzích jazyka C se deklarace mohly vyskytovat pouze na začátku bloku před všemi příkazy. V standardu C99 lze deklarace umísťovat do libovolného místa kódu stejně jako je tomu v C++ a jako je tomu např. v následujícím fragmentu kódu splňujícím standard C99: typedef struct { int age; double salary; Employee; void compensations(employee *emp) { double bonus = 155.25; double salary; salary = emp->salary + bonus; int rank; // povoleno pouze v C99 rank = emp->age - 25; //... zbytek kódu Strana 7 z 18

2.3. Rozptýlené příkazy a deklarace V starších verzích jazyka C se deklarace mohly vyskytovat pouze na začátku bloku před všemi příkazy. V standardu C99 lze deklarace umísťovat do libovolného místa kódu stejně jako je tomu v C++ a jako je tomu např. v následujícím fragmentu kódu splňujícím standard C99: typedef struct { int age; double salary; Employee; void compensations(employee *emp) { double bonus = 155.25; double salary; salary = emp->salary + bonus; int rank; // povoleno pouze v C99 rank = emp->age - 25; //... zbytek kódu 2.4. Proměnné viditelné v rozsahu cyklu Fragment kódu (i tento kód je v Code::Blocks možné přeložit pouze s option -std=c99) for (int n = 0; n < 10; ++n) { // příkazy Strana 7 z 18

je ekvivalentní klasickému kódu { int n = 0; for (; n < 10; ++n) { // příkazy Strana 8 z 18

3. Novými rysy C99 jsou pole s proměnnou délkou, přiřazené inicializátory, datový typ long long, variadická makra a identifikátor func. 3.1. Pole s proměnnou délkou jde o nejvýznamnější nový rys C99: int sentvla(int [*], int ); int createvla(int size, int *sumquad) { int arr[size]; // size isn't const; allowed only in C99 for (int i = 0; i < size; i++) arr[i] = i * i; *sumquad = sentvla(arr, size); return sizeof(arr); #if defined( GNUC ) int sentvla(int vla[], int size) { // GNU C allows "[*]" in prototypes only #elif defined( DMC ) int sentvla(int vla[*], int size) { // Digital Mars C also allows "[*]" here #else int sentvla(int *vla, int size) { // another possible way of compilation #endif int suma = 0; for (int i = 0; i < size; i++) suma += vla[i]; return suma; Strana 9 z 18

Ve všech předchozích verzích jazyka C nebylo možné, aby délka pole (size) byla proměnná, tj. známá až v okamžiku běhu programu (nikoliv v okamžiku kompilace, jak tomu bylo dříve) ve výše uvedeném příkladu délka dynamicky alokovaného pole v proceduře vstupuje jako parametr procedury. Tato možnost neexistuje ani v C++ zde je nutné pole dynamicky alokovat pomocí operátorů new a delete[], což rozhodně není tak elegantní jako v C99. Strana 10 z 18

Ve všech předchozích verzích jazyka C nebylo možné, aby délka pole (size) byla proměnná, tj. známá až v okamžiku běhu programu (nikoliv v okamžiku kompilace, jak tomu bylo dříve) ve výše uvedeném příkladu délka dynamicky alokovaného pole v proceduře vstupuje jako parametr procedury. Tato možnost neexistuje ani v C++ zde je nutné pole dynamicky alokovat pomocí operátorů new a delete[], což rozhodně není tak elegantní jako v C99. K podpoře polí s proměnnou délkou C99 zavádí notaci [*] v parametrech funkce ovšem některé překladače toto umožňují jen v deklaraci prototypu funkce (jako GNU GCC) a jiné i v konkrétní definici funkce (jako Digital Mars). Strana 10 z 18

Ve všech předchozích verzích jazyka C nebylo možné, aby délka pole (size) byla proměnná, tj. známá až v okamžiku běhu programu (nikoliv v okamžiku kompilace, jak tomu bylo dříve) ve výše uvedeném příkladu délka dynamicky alokovaného pole v proceduře vstupuje jako parametr procedury. Tato možnost neexistuje ani v C++ zde je nutné pole dynamicky alokovat pomocí operátorů new a delete[], což rozhodně není tak elegantní jako v C99. K podpoře polí s proměnnou délkou C99 zavádí notaci [*] v parametrech funkce ovšem některé překladače toto umožňují jen v deklaraci prototypu funkce (jako GNU GCC) a jiné i v konkrétní definici funkce (jako Digital Mars). Běžné debuggery mají potíže se zobrazováním obsahu dynamicky alokovaných polí (např. klasické verze WinDbg), nové verze debuggeru GDB pro GNU GCC však zobrazují dynamicky alokovaná pole správně. Rovněž vícerozměrná pole lze v standardu C99 alokovat dynamicky. Strana 10 z 18

Ve všech předchozích verzích jazyka C nebylo možné, aby délka pole (size) byla proměnná, tj. známá až v okamžiku běhu programu (nikoliv v okamžiku kompilace, jak tomu bylo dříve) ve výše uvedeném příkladu délka dynamicky alokovaného pole v proceduře vstupuje jako parametr procedury. Tato možnost neexistuje ani v C++ zde je nutné pole dynamicky alokovat pomocí operátorů new a delete[], což rozhodně není tak elegantní jako v C99. K podpoře polí s proměnnou délkou C99 zavádí notaci [*] v parametrech funkce ovšem některé překladače toto umožňují jen v deklaraci prototypu funkce (jako GNU GCC) a jiné i v konkrétní definici funkce (jako Digital Mars). Běžné debuggery mají potíže se zobrazováním obsahu dynamicky alokovaných polí (např. klasické verze WinDbg), nové verze debuggeru GDB pro GNU GCC však zobrazují dynamicky alokovaná pole správně. Rovněž vícerozměrná pole lze v standardu C99 alokovat dynamicky. Výše uvedené funkce lze např. použít v následujícím testovacím hlavním programu: #include <stdio.h> #include "variablesize_func.c" void main() { int size, nbytes, sumquad; printf("enter array's size: "); scanf("%d", &size); nbytes = createvla(size, &sumquad); printf("nbytes = %d, sumquad = %d\n", nbytes, sumquad); Strana 10 z 18

3.2. Přiřazené inicializátory Přiřazené inicializátory umožňují elegantním způsobem přiřazovat počáteční hodnoty prvkům polí, struktur a unionů podle následujícího příkladu: #include <stdio.h> int vec[5] = {[1]=10, [3]=20; typedef struct { char name[20]; int ID; int age; FILE *record; Employee; Employee emp = {.ID=0,.record=NULL; Strana 11 z 18

3.2. Přiřazené inicializátory Přiřazené inicializátory umožňují elegantním způsobem přiřazovat počáteční hodnoty prvkům polí, struktur a unionů podle následujícího příkladu: #include <stdio.h> int vec[5] = {[1]=10, [3]=20; typedef struct { char name[20]; int ID; int age; FILE *record; Employee; Employee emp = {.ID=0,.record=NULL; 3.3. Datový typ long long Tento datový typ musí podle standardu mít nejméně 64 bitů (důležité např. pro náhodná čísla) #include <stdio.h> void main() { long long molecules=10000000000000ll; printf("%lld\n", molecules); Strana 11 z 18

3.4. Variadická makra Standard C99 podporuje kromě variadických funkcí (printf funkce s proměnným počtem parametrů) i variadická makra, přičemž proměnný seznam argumentů makra reprezentuje ellipsis (... ): #include <stdio.h> #define DoLogFile(...) fprintf(stderr, VA_ARGS ) #define MakeName(...) # VA_ARGS int main() { char *p; p = MakeName(Mary); p = MakeName(Doe, John); DoLogFile("MakeName=%s\n", p); // kombinace dvou variadických maker: DoLogFile("MakeName=%s\n", MakeName(Martin Luther King, Jr.)); Strana 12 z 18

3.5. Identifikátor func Identifikátor func vrací jméno funkce, v které byl tento identifikátor použit. Jméno funkce je tedy poskytováno podobným způsobem jako pracují např. makra FILE nebo DATE : #include <stdio.h> void moje_funkce() { printf("you're in %s\n", func ); void main() { moje_funkce(); Strana 13 z 18

3.5. Identifikátor func Identifikátor func vrací jméno funkce, v které byl tento identifikátor použit. Jméno funkce je tedy poskytováno podobným způsobem jako pracují např. makra FILE nebo DATE : #include <stdio.h> void moje_funkce() { printf("you're in %s\n", func ); void main() { moje_funkce(); 3.6. Komplexní čísla Standard C99 přináší nová klíčová slova _Complex a _Imaginary a je přípustná deklarace long double _Complex a (přirozená) práce s komplexními čísly s přesností na 19 až 20 platných cifer je tedy možná. Na následující straně je uveden příklad kódu použitelného pro překladače Digital Mars C i GNU GCC. Strana 13 z 18

#include <stdio.h> //nebyl použit complex.h, aby bylo jasné co je generické inline long double creall(long double _Complex z) { return (long double)z; //nebo *(long double *)&z, reálná část je první inline long double cimagl(long double _Complex z) { return ((long double *)&z)[1]; //realná a imaginární jsou tedy za sebou long double _Complex csinl(long double _Complex); //csinl je v knihovnách #ifdef DMC //pozor, I je definováno jiným typem v Digital Mars a GNU C! #define I ((const float _Imaginary) imaginary) //DMC má typ _Imaginary #elif defined( GNUC ) //DMC tedy definuje I jako typ standardu _Imaginary #define I (0.0F + 1.0iF) //v MinGW, GCC totiž NEMÁ dosud typ _Imaginary #endif //oba nejprve definují standard _Complex_I a oba rovn ěž definují i I /* GCC ovšem umožňuje psát i za číslem, tj. např. a = 1.3L+2.5iL */ void main() { long double _Complex a = 1.3L+2.5L*I, b = -2.7L-0.3L*I, sum, mul, foo, t; printf("a = %Lg + %Lgi (size(a)=%d)\n", creall(a), cimagl(a), sizeof(a)); printf("b = %Lg + %Lgi\n", creall(b), cimagl(b)); sum = a + b; mul = a * b; printf("a + b = %Lg + %Lgi\n", creall(sum), cimagl(sum)); printf("a * b = %Lg + %Lgi\n", creall(mul), cimagl(mul)); foo = csinl(a); t = csinl(1.5707963267948966192l + 1.3169578969248167086L*I); printf("sin(a) = %.20Lg + %.20Lgi\nsin(pi/2 + ln(2+sqrt(3))i) = " "%.20Lg + %.20Lgi", creall(foo), cimagl(foo), creall(t), cimagl(t)); Strana 14 z 18

Program vytvořený překladačem Digital Mars poskytne výsledek (je vidět, že jedno komplexní číslo zabírá v tomto případě 20 bytů): a = 1.3 + 2.5i (size(a)=20) b = -2.7 + -0.3i a + b = -1.4 + 2.2i a * b = -2.76 + -7.14i sin(a) = 5.9088177234776839696 + 1.618422611617372858i sin(pi/2 + ln(2+sqrt(3))i) = 2 + 1.4084199363160870024e-19i a program vytvořený překladačem GNU GCC poskytne obdobný výsledek (v tomto případě ovšem komplexní číslo zabere 24 bytů): a = 1.3 + 2.5i (size(a)=24) b = -2.7 + -0.3i a + b = -1.4 + 2.2i a * b = -2.76 + -7.14i sin(a) = 5.9088177234776838326 + 1.6184226116173728588i sin(pi/2 + ln(2+sqrt(3))i) = 2 + 1.4434466152095499672e-019i Strana 15 z 18

Program vytvořený překladačem Digital Mars poskytne výsledek (je vidět, že jedno komplexní číslo zabírá v tomto případě 20 bytů): a = 1.3 + 2.5i (size(a)=20) b = -2.7 + -0.3i a + b = -1.4 + 2.2i a * b = -2.76 + -7.14i sin(a) = 5.9088177234776839696 + 1.618422611617372858i sin(pi/2 + ln(2+sqrt(3))i) = 2 + 1.4084199363160870024e-19i a program vytvořený překladačem GNU GCC poskytne obdobný výsledek (v tomto případě ovšem komplexní číslo zabere 24 bytů): a = 1.3 + 2.5i (size(a)=24) b = -2.7 + -0.3i a + b = -1.4 + 2.2i a * b = -2.76 + -7.14i sin(a) = 5.9088177234776838326 + 1.6184226116173728588i sin(pi/2 + ln(2+sqrt(3))i) = 2 + 1.4434466152095499672e-019i 3.7. Použití knihovny s čtyřnásobnou délkou slova Ještě mnohem větší přesnosti dosáhneme při použití nově vytvořené knihovny libquadmath pro překladač GNU GCC (tuto knihovnu musíme zatím při procesu sestavování ručně připojovat, což ovšem není velký problém). Způsob použití je zjevný z následujícího kódu, který je přesnější variantou dříve demonstrovaného testu přesnosti. Strana 15 z 18

#include <stdio.h> #include <quadmath.h> typedef float128 real; int main() { real a = 1, b1 = 3.14159265358979323846264338327950288, //bude v GCC long double b2 = 3.14159265358979323846264338327950288Q; //bude v GCC float128 // epsilon computing while (1 + a/2!= 1) a /= 2; printf("length of ' float128' = %d, epsilon = %.4g\n", sizeof(a), (double)a); // pi computing printf("pi to 35 decimal digits = 3.14159265358979323846264338327950288 " "(Wikipedia)\n"); a = 4 * atanq((real)1); //atanq má parametr typu float128 char s[40]; quadmath_snprintf (s, sizeof(s), "%39.36Qf", a); //speciální tisk v quad printf("pi to 36 decimal digits =%s (computed\nby ", s); #ifdef GNUC printf("gnu GCC Compiler with '-std=c99' option and " "libquadmath.a library)\n"); #else printf("another compiler)\n"); #endif printf("'long double' - pi = %.4g, ' float128' - pi = %.4g", (double)(b1 - a), (double)(b2 - a)); return b1!= b2? 0 : 1; Strana 16 z 18

a v tomto případě můžeme počítat s přesností výpočtu až na 35 platných cifer (viz epsilon): length of ' float128' = 16, epsilon = 1.926e-034 pi to 35 decimal digits = 3.14159265358979323846264338327950288 (Wikipedia) pi to 36 decimal digits = 3.141592653589793238462643383279502797 (computed by GNU GCC Compiler with '-std=c99' option and libquadmath.a library) 'long double' - pi = 5.017e-020, ' float128' - pi = 0 Strana 17 z 18

a v tomto případě můžeme počítat s přesností výpočtu až na 35 platných cifer (viz epsilon): length of ' float128' = 16, epsilon = 1.926e-034 pi to 35 decimal digits = 3.14159265358979323846264338327950288 (Wikipedia) pi to 36 decimal digits = 3.141592653589793238462643383279502797 (computed by GNU GCC Compiler with '-std=c99' option and libquadmath.a library) 'long double' - pi = 5.017e-020, ' float128' - pi = 0 Knihovna libquadmath umožňuje ve stejné přesnosti pracovat i s komplexními čísly: #include <quadmath.h> #include <stdio.h> int main() { complex128 t; t = csinq(1.570796326794896619231321691639751399q + 1.316957896924816708625046347307968481Qi); printf("sin(pi/2 + ln(2+sqrt(3))i) = %.20Lg + %Lgi", (long double)crealq(t), (long double)cimagq(t)); return 0; což poskytne výsledek sin(pi/2 + ln(2+sqrt(3))i) = 2 + 7.51001e-035i který opět potvrzuje přesnost přibližně na 34 platných cifer. Strana 17 z 18

4. Účelnost aritmetiky v čtyřnásobné přesnosti lze názorně dokumentovat následujícím příkladem v C: #include <quadmath.h> #include <stdio.h> int main (void) { float128 a = sinq(1e22q); float128 b = logq(17.1q); float128 c = expq(0.42q); float128 d = 173746*a + 94228*b - 78487*c; char s[45]; quadmath_snprintf(s, sizeof(s), "%44.35Qe", d); // bez Q nefunguje printf("result to 36 decimal digits: %s\n", s); printf("non-precise standard printing:%44.35e\n", (double)d); printf("interesting precise printing: %44.35Le", (long double)d); // Le je v c99! nebo v Fortran90: program cise implicit none real(16) a, b, c, d a = sin(1e22_16) b = log(17.1_16) c = exp(0.42_16) d = 173746*a + 94228*b - 78487*c print *, d end program cise Oba programy dávají (správný výsledek) -1.34181895782961954211800625066264897e-012. Pokud bychom to provedli v long double, výsledek by byl -1.3145040611561853e-012 a v double dokonce úplně špatný výsledek 2.9103830456733704e-011. Strana 18 z 18