Programování v systému



Základní koncepty

Vybavenost nástroji, umožňujícími tvorbu vlastních programů - aplikací, je jedním z důležitých kriterií při hodnocení výpočetních systémů. Z tohoto pohledu je linuxový systém THUNDER více než uspokojující. K dispozici je obrovské množství jazyků skriptovacích (viz dále) i jazyků kompilovaných. Prakticky pro každý jazyk podchycený normou existuje interpreter nebo překladač, obvykle mnohem kvalitnější, než poskytují komerční firmy pro platformu DOS/Windows. Díky jejich GNU původu je také snadno dostupná dokumentace a zdrojové kódy. Rozsáhlá základna vývojářů a uživatelů představuje záruku včasného odhalení a opravy potenciálních chyb.

To, co obvykle nazýváme programováním, je zápis algoritmu pomocí jazyka s přesně (často normou) definovanými lexikálními strukturami a syntaxí. Stejný problém (například výpočet faktoriálu) lze uchopit rozdílnými algoritmy (například rekurzivním a iterativním) a ty dále zapsát pomocí různých programovacích jazyků (například C, Pascal, Fortran, Basic, bc, Perl a další). Tento takzvaný "zdrojový text/kód" (source code) lze zpracovat překladačem (compiler) na spustitelný program v případě kompilovaných jazyků (C, Pascal, Fortran) nebo vykonávat "řádku po řádce" interpretem v případě jazyků interpretovaných/skriptovacích (Basic). K mnoha programovacím jazykům existuje překladač i interpreter, ale je preferováno použití jednoho z nich, například kvůli rychlosti, přenositelnosti a podobně. Hranice mezi jazyky interpretovanými a kompilovanými je neostrá. Mnoho interpretů ve skutečnosti překládá zdrojový text do jakéhosi mezikódu v paměti a ten posléze provádí (Perl). Pro jeden jazyk mohou existovat v systému různé překladače nebo interprety.

Rychlost výsledné aplikace (programu) závisí na cestě, kterou vznikla. Rozhodující je většinou algoritmus, avšak pro stejný algoritmus hraje důležitou roli i volba jazyka a překladače. Výběr jazyka by měl sledovat kompromis mezi "obtížností" programování a potřebnou rychlostí programu. Pokud doba běhu programu bude typicky sekundy, je i 500%-ní rozdíl v rychlosti pro různé jazyky a překladače prakticky irelevantní. Pro výpočet trvající typicky hodiny a více je už rozdíl řádově desítek procent podstatný. Také druh aplikace hraje roli při výběru programovacího jazyka. Pro práci s textem a například CGI skripty se mnohem více hodí Perl, než C. Pro numerické výpočty je naopak vhodnější jazyk C, případně Fortran nebo Pascal. K symbolickým manipulacím se zase více hodí funkcionální jazyky, například Scheme. Vzhledem k předpokládanému využití serveru THUNDER k numerickým výpočtům, se budeme dále až na výjimky věnovat trojici kompilovaných jazyků: C, Fortran, Pascal.

Imperativní kompilované jazyky - C, Fortran, Pascal

Volba překladače jazyků C, Fortran a Pascal je v linuxových GNU systémech prakticky jednoznačná. Program gcc (GNU Compiler Collection) zde přestavuje základní prostředek vývoje. Spolu s různými standardními parsery dokáže překládat zdrojové texty v jazycích C, C++, Objective C, Java, CHILL a Fortran. Volitelné parsery rozšiřují množinu jazyků o Pascal, Ada95 a další. Viz dokumentaci programu GCC. Další existující překladače (vyjma klonů GCC) zmíněných jazyků obvykle nedosahují kvality GCC, mohou však poskytovat jiné výhody. Příkladem je překladač Pascalu `ppc386' zachovávající vysoký stupeň kompatibility s Borland TURBO Pascal mutací jazyka Pascal. Rozpětí podporovaných jazyků je dáno koncepcí systému GCC, jenž obsahuje pouze malou část (parser) jazykově závislou provádející lexikální analýzu příslušného jazyka a jeho převod do mezikódu RTL (register transfer language). Všechny další operace a optimalizace jsou již jazykově nezávislé. RTL má charakter seznamů, vzdáleně připomíná Lisp. Teprve až v posledních krocích zpracování se rozhoduje o fyzickém umístění proměnných v paměti a manipulaci s registry. Ukázky RTL mezikódu, stručný popis optimalizací, ukázky generovaného assembleru a srovnání s jinými kompilátory lze nalézt například na adrese http://www.gnu.cz/gcc.html.

Předchozí diskuse o parserech nás nutně přivádí k otázce norem a verzí implementovaných jazyků. Zhruba řečeno, GCC nabízí až na poslední verze standardů jazyků kompletní podporu. Poslední verze jsou obvykle podporovány částečně. Navíc jsou obvykle podporována různá nestandardizovaná rozšíření, třeba GNU rozšíření. Například pro jazyk C jsou podporovány následující standardy: částečně traditional (pre-ISO) C, ANSI C standard (X3.159-1989), respektive ISO/IEC 9899:1990 (C89/C90), AMD1 1990 (C94/C95) a částečně ISO/IEC 9899:1999 (C9X/C99). Pro numerické programování může být zajímavá podpora koplexních proměnných a funkcí (dle C9X/C99). Podobně pro jazyk Fortran jsou podporovány normy: kompletně ANSI FORTRAN 77, částečně ANSI FORTRAN 90, některá rozšíření populární mezi uživateli UNIXového `f77' a konvertoru `f2c', některá rozšíření populární mezi uživateli dalších překladačů, například Digital Fortran a některá GNU rozšíření. Podrobnosti viz INFO dokumentace k příkazu `g77'. Pro úplnost doplňme podporované jazykové standardy pro Pascal: kompletně Pascal standard (ISO 7185:1990, ANSI/IEEE 770X3.160-1989), částečně Extended Pascal standard (ISO/IEC 10206:1991), částečně UCSD Pascal, Borland Pascal 7 (včetně mnoha unitů), Pascal-SC a některá GNU rozšíření. Pro podrobnosti nejen o podporovaných standardech viz INFO dokumentaci ke GNU Pascalu `gpc' a domovskou stránku GNU Pascal. Tolik GNU Compiler Collection. Jiné překladače mohou poskytovat jinou jazykovou podporu. Například Free Pascal Compiler `ppc386' (Portable Pascal Compiler) udává kompatibilitu s Turbo Pascal a Delphi (2.0). Příslušná dokumentace je v adresáři `/usr/share/doc/fp-docs'. Viz Dokumentace, literatura, vyhledávání souborů.

Všechny zmíněné překladače gcc, g77, gpc, ppc386 a další pracují podobným způsobem, v podobných fázích. První předloží zdrojový text foo.c (foo.f, foo.pas) parseru daného jazyka, poté optimalizují mezikód a řeší "mapování" abstraktních struktur jazyka na fyzické zdroje počítače. Výsledkem překladu je takzvaný objektový soubor foo.o. GNU Compiler Collection může na požádání poskytnout také odpovídající kód v asembleru foo.a. Vzhledem k tomu, že drtivá většina programů využívá knihovní funkce, musí být objektový soubor dán do kontextu s potřebnými knihovnami. Ne nutně to musí znamenat zahrnutí knihovního kódu do našeho programu. Rozdíly jsou mezi statickými a sdílenými knihovnami. Speciálně jazyk C neobsahuje například ani "jednoduché" funkce pro vstup a výstup a používá obsáhlé sdílené knihovny GNU C Library (glibc). Program zajišťující obecně spojení s knihovnami a vlastní sestavení binárního spustitelného programu se nazývá linker a v UNIXových systémech jej reprezentuje program ld. Závislost libovolného programu na sdílených knihovnách může uživatel zjistit pomocí příkazu ldd...

  ldd example
  libc.so.6 => /lib/libc.so.6 (0x40018000)
  /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
  
Informace o druhu binárního souboru lze podobně zjistit příkazem file...
  file example
  example: ELF 32-bit LSB executable, Intel 80386, version 1,
           dynamically linked (uses shared libs), stripped
  

Pro úplnost poznamenejme, že často je před vlastním překladem (parsováním) prováděno jakési předzpracování, preprocessing. Například zdrojový text v jazyku C může obsahovat, a také často obsahuje, instrukce pro překladač. Například definice konstant, maker, pokyny pro podmíněný překlad a další informace. Preprocesor jazyka C zpracuje tyto instrukce a teprve následně probíhá vlastní překlad.


Překlad C, Fortranu a Pascalu;  Srovnání

Pro demostraci předchozích informací a srovnání jednotlivých jazyků ukážeme v tomto odstavci překlad, jednoduché druhy optimalizačních parametrů a měření doby běhu programu paralelně pro stejný algoritmus zapsaný v C, Fortranu a Pascalu.

Jako ukázku jsem napsal dvojitý cyklus 100000x10000 průběhů, který provádí jednoduché celočíselné operace sčítání, odčítání a násobení, avšak některé mezivýsledky a finální součet ukládá do reálné proměnné, pro niž jsem zvolil nejvyšší přesnost v daném jazyce (o které vím). Nevylučuji, že například fortran disponuje nejakou větší přesností, než je double precision. Budu vděčný za opravy a připomínky, které mi pomohou provést objektivní testy. Kvůli otestování rychlosti přístupu k prvkům pole je součin i*j ukládán a načítán do/z pole. Zbývá vyřešit problém rozdílného indexování prvků pole v C a ostatních jazycích. Jazyk C indexuje od nultého indexu, fortran a pascal od prvního indexu. Jelikož jsou "v přesile", přepočítávám indexy v programu zapsaném v C. Tím ho samozřejmě rychlostně znevýhodňuji. Použitý algoritmus je záměrně velmi neefektivní a je ponecháno na překladači, jak si s ním poradí.

Následuje zdrojový kód zapsaný jazykem C...
#include <stdio.h>

int main (void)
{
  int i, j, a[10000];
  long double x, y, z, sum=0.0L;
  a[0] = 0;

  for (i=1;i<=100000;i++)
    for (j=1;j<=10000;j++)
    {
      z = a[0]*10000;
      a[j-1] = i*j;
      x = i + j;
      y = i - j;
      sum += a[j-1] + x + y + z;
    }
  printf ("%Lf\n",sum);

  return 0;
}
... jazykem fortran...
      integer i, j
      integer a(10000)
      double precision x, y, z, sum;

      sum = 0.0;
      a(1) = 0;

      loop1: do i = 1,100000
      loop2:   do j = 1,10000
                 z = a(1) * 10000
                 a(j) = i * j
                 x = i + j
                 y = i - j
                 sum = sum + a(j) + x + y + z;
               end do loop2
             end do loop1

      write (*, 100) sum
100   format (f26.6)
      end
... a jazykem pascal...
program example (input,output);

var
     i, j : longint;
        a : array [1..10000] of longint;
  x, y, z : double;
      sum : double;

begin
  sum := 0.0;
  a[1] := 0;

  for i:=1 to 100000 do
    for j:=1 to 10000 do
    begin
      z := a[1] * 10000;
      a[j] := i * j;
      x := i + j;
      y := i - j;
      sum := sum + a[j] + x + y + z;
    end;

  writeln(sum);
end.
Předcházející zdrojové kódy jsou uloženy v souborech example.c, example.f, example.pas. Spustitelné programy vytvoříme pomocí příkazů...
gcc -o example_c -Wall example.c

gcc -o example_c_opt -Wall -O6 -ffast-math -fexpensive-optimizations
    -march=pentiumpro -malign-double -fomit-frame-pointer -funroll-loops
    -finline-functions -fmove-all-movables example.c

g77 -o example_f -Wall example.f

g77 -o example_f_opt -Wall -O6 -ffast-math -fexpensive-optimizations
    -march=pentiumpro -malign-double -fomit-frame-pointer -funroll-loops
    -finline-functions -fmove-all-movables example.f

gpc -o example_pas -Wall example.pas

gpc -o example_pas_opt -Wall -O6 -ffast-math -fexpensive-optimizations
    -march=pentiumpro -malign-double -fomit-frame-pointer -funroll-loops
    -finline-functions -fmove-all-movables example.pas

ppc386 -oexample_pas_ppc example.pas

ppc386 -oexample_pas_ppc_opt -O3 -Op3 example.pas

Pomocí GNU Compiler Collection jsme získali programy example_c, example_c_opt, example_f, example_f_opt, example_pas, example_pas_opt a pomocí překladače Free Pascal Compiler programy example_pas_ppc, example_pas_ppc_opt. Programy s _opt ve jménu značí, že při překladu byly použity nekteré základní optimalizační volby. Pro jejich vysvětlení viz INFO stránky a další dokumentaci k programům gcc, g77, gpc, ppc386. Viz také Optimalizační volby překladače GNU Compiler Collection. Pro srovnání velikosti výsledných programů je treba z nich odstranit ladící informace (informace použitelné pro symbolický debugger, viz dále) a některé další zbytečnosti. To provedeme příkazem strip...

strip example_*

Nyní se můžeme podívat na zmíněné délky.
-rw-r--r--    1 nathan   users         324 Feb 21 21:04 example.c
-rw-r--r--    1 nathan   users         435 Feb 21 21:02 example.f
-rw-r--r--    1 nathan   users         383 Feb 21 21:10 example.pas

-rwxr-xr-x    1 nathan   users        3316 Feb 21 21:52 example_c
-rwxr-xr-x    1 nathan   users        3428 Feb 21 21:52 example_c_opt

-rwxr-xr-x    1 nathan   users       30732 Feb 21 21:52 example_f
-rwxr-xr-x    1 nathan   users       30860 Feb 21 21:52 example_f_opt

-rwxr-xr-x    1 nathan   users      111448 Feb 21 21:52 example_pas
-rwxr-xr-x    1 nathan   users      111320 Feb 21 21:52 example_pas_opt

-rwxr-xr-x    1 nathan   users       34500 Feb 21 21:52 example_pas_ppc
-rwxr-xr-x    1 nathan   users       34484 Feb 21 21:52 example_pas_ppc_opt

Vidíme, že rozdíl v délce mezi programy odpovídající zdrojovým textům v jazyku C a jazyku fortran je řádový. Rozdíl mezi fortranem a pascalem je téměř čtyřnásobný. Jazyk C se tedy v tomto konkrétním srovnání jeví jako (délkově) nejvýhodnější. Obrovskou délku programu přeloženého z textu zapsaného pascalem si vysvětluji tím, že pascal (dle ISO norem) provádí v běžícím programu mnoho kontrol, například kontroly na nepřekročení meze polí a podobně. Tento nadbytečný kód samozřejmě zabírá místo. Navíc nemohu vyloučit různý objem textu přilinkovaného (linkerem) z knihoven. Pro přesný rozbor obsahu, a také rychlosti, jednotlivých programů by bylo nutné si nechat vygenerovat prekladačem také zdrojový text v assembleru. Dodejme pro úplnost, že assembler je jednoduše řečeno symbolický zápis binárního kódu programu, tedy symbolický zápis instrukcí pro procesor počítače. Překladač Free Pascal Compiler generuje kratší (a také rychlejší) programy, než gpc. Vzhledem k tomu, že pascal je po parsování do mezikódu RTL překládán v GNU Compiler Collection stejným způsobem jako C, GNU Compiler Collection je podle testů jedním z nejefektivnějších kompilátorů a dokumentace k Free Pascal Compiler _neuvádí_ kompatibilitu s ISO normou, ale pouze Borland Pascal pseudonormou, usuzuji, že Free Pascal Compiler prostě obchází některé neefektivity pascalu (vyplývající z jeho definice) a to mu umožnuje produkovat kratší a rychlejší programy.

Následující sekvence příkazů vypíše jméno programu a následně ho spustí a změří dobu jeho běhu...
echo example_c:
time ./example_c

echo example_c_opt:
time ./example_c_opt

echo example_f:
time ./example_f

echo example_f_opt:
time ./example_f_opt

echo example_pas:
time ./example_pas

echo example_pas_opt:
time ./example_pas_opt

echo example_pas_ppc from ppc386:
time ./example_pas_ppc

echo example_pas_ppc_opt from ppc386:
time ./example_pas_ppc_opt

Uvedená sekvence vyprodukovala výstup uvedený v prvním sloupci následující tabulky. Další dva sloupce jsou vytvořeny opětovným spuštěním předchozích příkazů. Na UNIXovém serverovém systému mohou totiž z důvodu mnoha démonů a na pozadí běžících aplikací mírně kolísat přidělované systémové zdroje.


example_c:                    example_c:                     example_c:
750132500250000000.000000     750132500250000000.000000      750132500250000000.000000

real    1m28.711s             real      1m28.422s            real       1m28.424s
user    1m28.460s             user      1m28.420s            user       1m28.330s
sys     0m0.020s              sys       0m0.000s             sys        0m0.100s


example_c_opt:                example_c_opt:                 example_c_opt:
750132500250000000.000000     750132500250000000.000000      750132500250000000.000000

real    0m13.704s             real      0m13.693s            real       0m13.695s
user    0m13.710s             user      0m13.690s            user       0m13.690s
sys     0m0.000s              sys       0m0.000s             sys        0m0.000s


example_f:                    example_f:                     example_f:
 750132500249889536.000000     750132500249889536.000000      750132500249889536.000000

real    0m53.080s             real      0m53.059s            real       0m53.070s
user    0m53.070s             user      0m53.060s            user       0m53.070s
sys     0m0.010s              sys       0m0.000s             sys        0m0.000s


example_f_opt:                example_f_opt:                 example_f_opt:
 750132500249562624.000000     750132500249562624.000000      750132500249562624.000000

real    0m22.764s             real      0m22.772s            real       0m22.766s
user    0m22.760s             user      0m22.770s            user       0m22.760s
sys     0m0.000s              sys       0m0.000s             sys        0m0.000s


example_pas:                  example_pas:                   example_pas:
 7.501325002498895e+17         7.501325002498895e+17          7.501325002498895e+17

real    2m21.205s             real      2m21.228s            real       2m21.261s
user    2m21.170s             user      2m21.230s            user       2m21.260s
sys     0m0.020s              sys       0m0.000s             sys        0m0.000s


example_pas_opt:              example_pas_opt:               example_pas_opt:
 7.501325002497242e+17         7.501325002497242e+17          7.501325002497242e+17

real    2m4.742s              real      2m4.743s             real       2m4.746s
user    2m4.720s              user      2m4.740s             user       2m4.730s
sys     0m0.020s              sys       0m0.000s             sys        0m0.020s


example_pas_ppc               example_pas_ppc                example_pas_ppc
from ppc386:                  from ppc386:                   from ppc386:
 7.501325002498895E+017        7.501325002498895E+017         7.501325002498895E+017

real    0m36.737s             real      0m36.746s            real       0m36.755s
user    0m36.740s             user      0m36.750s            user       0m36.760s
sys     0m0.000s              sys       0m0.000s             sys        0m0.000s


example_pas_ppc_opt           example_pas_ppc_opt            example_pas_ppc_opt
from ppc386:                  from ppc386:                   from ppc386:
 7.501325002498895E+017        7.501325002498895E+017         7.501325002498895E+017

real    0m35.088s             real      0m35.104s            real       0m35.084s
user    0m35.090s             user      0m35.100s            user       0m35.080s
sys     0m0.000s              sys       0m0.000s             sys        0m0.000s

První zhodnotíme rychlost. Důležité jsou pro nás optimalizované verze programů. Srovnání neoptimalizavaných verzí hodnotí jednak spíš optimalizační schopnosti parserů, ale především "nulovou" hladinu prováděných optimalizací, která může být u různých překladačů různá. V tomto konkrétním případě vykazuje jazyk C téměř dvakrát větší rychlost než jazyk fortran a třikrát větší rychlost než jazyk pascal kompilovaný překladačem Free Pascal Compiler. Jazyk pascal přeložený systémem GNU Compiler Collection je řádově pomalejší než jazyk C. Je možné, že fortran bude pro jiný příklad nebo na jiné platformě efektivnější - buď jako jazyk C, nebo více. To samé lze však stěží říci o jazyku pascal. Ten je navržen jako výukový vysokoúrovňový jazyk, z principu nevhodný k numerickým výpočtům. Dalším zajímavým srovnáním je vlastní výsledek výpočtu. Asi díky vysoké přesnosti (18 platných cifer, viz soubor /usr/lib/gcc-lib/i386-linux/2.95.2/include/float.h) typu long double je jazyk C jako jediný schopen poskytnout korektní výsledek, a to i při rychlostních optimalizacích. Fortran a pascal vykazují v neoptimalizovaných a optimalizovaných verzích rozdíly od 13-té platné cifry. Typ double (double precision) by měl asi poskytovat 16 platných cifer, ale je to buď nedostačující pracovní přesnost, nebo je počet cifer menší (nechce se mi probírat normy fortranu, pascalu a příslušnou dokumentaci k překladačům). Pokud jde o ověření správnosti výsledku získaného C programem, můžeme provést odpovídající výpočet v celočíselné oblasti. Vzhledem k tomu, že proměnná sum nabývá větších hodnot, než je povoleno pro typ integer (typ long int je se svými 20 ciframi právě na hranici) a v zájmu nezávislosti ověření můžeme použít například GNU Multiple Precision arithmetic library (GMP, viz INFO dokumentace ke GMP). Zdrojový text...


#include <stdio.h>
#include "gmp.h"

int main (void)
{
  long int i, j, a[10000];
  long int final;
  mpz_t sum;

  a[0] = 0;
  mpz_init (sum);

  for (i=1;i<=100000;i++)
    for (j=1;j<=10000;j++)
    {
      final = i*j + 2*i + a[0]*10000;
      a[j-1] = i*j;
      if (final>=0)
        mpz_add_ui (sum, sum, (unsigned long int)final);
      if (final<0)
      {
        final *= -1;
        mpz_sub_ui (sum, sum, (unsigned long int)final);
      }
    }

  mpz_out_str (stdout, 10, sum);
  printf ("\n");
  mpz_clear (sum);
  return 0;
}

uložíme do souboru example.gmp.c, přeložíme příkazem
gcc -o example_gmp_opt -Wall -O6 -ffast-math -fexpensive-optimizations
    -march=pentiumpro -malign-double -fomit-frame-pointer -funroll-loops
    -finline-functions -fmove-all-movables example.gmp.c -lgmp
a spustíme  time ./example_gmp_opt

example_gmp_opt:              example_gmp_opt:               example_gmp_opt:
750132500250000000            750132500250000000             750132500250000000

real    1m12.933s             real      1m12.765s            real       1m12.764s
user    1m12.810s             user      1m12.760s            user       1m12.760s
sys     0m0.020s              sys       0m0.010s             sys        0m0.010s

Pro úplnost dodejme, že všechny prezentované výsledky byly získány na serveru THUNDER. Byl použit systém GNU Compiler Collection verze 2.95.2 (Debian GNU/Linux), a systém Free Pascal Compiler verze 0.99.13. Na jiné hardwarové architektuře nebo pro jiné verze překladačů mohou být výsledky odlišné. To ukážeme pro dvouprocesorový server Alpha 21064 firmy DEC s operačním systémem Digital UNIX V4.0D

bash$ cc -o example_c_opt -O5 example.c
Warning: Type long double has the same representation as type double
         on this platform and is treated as a synonym for type double
         in this compilation mode.
bash$ time ./example_c_opt

750132500249889540.000000

real   93.4                          #  asi 1.56 min
user   91.8
sys    0.2


bash$ f90 -o example_f_opt -O5 example.f
bash$ time ./example_f_opt

 750132500220702080.000000

real   111.5                         #  asi 1.86 min
user   109.4
sys    0.2


bash$ f90 -o example_f_opt -O5 -double_size 128 example.f
bash$ time ./example_f_opt

 750132500250000000.000000

real   2372.5                        #  asi 39.5 min
user   2352.2
sys    3.2

a pracovní stanici Apollo 9000/715 firmy HP s operačním systémem HP-UX 10.20
pro typ LONG DOUBLE:
cc -o example_c_opt -Ae +O4 example.c
time ./example_c_opt

750132500250000000.000000

real  4:36:35.5                      #  asi 4 a půl hodiny
user  4:33:22.2
sys         6.8


pro typ DOUBLE:
cc -o example_c_opt -Ae +O4 example.c
time ./example_c_opt

750132500249889536.000000

real     3:34.5                      #  asi 3.5 min
user     3:31.2
sys         0.1


pro Fortran a typ DOUBLE PRECISION:
f90 -o example_f_opt +O3 +Oall example.f
time ./example_f_opt

 750132500220702080.000000

real     3:34.3                      #  asi 3.5 min
user     3:31.0
sys         0.1

Z předchozích výsledků usuzuji, že v systému ALPHA (a podobně APOLLO) chybí hardwarově podporovaný typ long double, tedy 12-ti nebo 16-ti bajtové reálné číslo. Nicméně kompilátor Fortranu 90 (respektive jazyka C v systému APOLLO) podporuje tento číselný typ softwarově, přitom však prudce vzrůstá doba výpočtu. Pro ostatní kompilátory nevylučuji podporu long double, pouze jsem ji nenašel při zběžné prohlídce manuálových stránek. Rychlost programů zapsaných C a Fortranem je pro stejný číselný typ prakticky stejná. Není tedy důvod obracet se na  Fortran a naopak můžeme využít výhody "moderního" jazyka C. Ani existence fortranovských knihoven LINPACK, EISPACK, LAPCAK, LAPACK90, ScaLAPACK a dalších není důvodem pro upřednostnění Fortranu před C, neboť funkce z těchto knihoven lze obvykle volat i z C programů. Některé knihovny byly dokonce konvertovány z Fortranu do C nebo C++, například CLAPACK, LAPACK++. Při srovnávání je také třeba uvážit velké množství rozličných C knihoven dostupných standardně (a zdarma) nejen pro operační sytém Linux.