bc : tetszôleges pontosságú számokkal dolgozó kalkulációs nyelv
bc[ -lws ] [ file ... ]
Ebben a dokumentumban a GNU bc 1.03 -as verzió leírása szerepel.
A bc lehetôséget nyújt a tetszôleges pontosságú számokkal való interaktív utasítások végrehajtására. Van néhány szintaktikai hasonlósága a C nyelvvel. Az alap matematikai könyvtár a parancssorból hívható meg. Kívánság szerint a matematikai könyvtár a file-okon végzett mûveletek elôtt átdefiniálható. A bc indulásakor feldolgozza a parancssorban megadott file-okban levô utasításokat ( a file-nevek sorrendjében ) majd ezután a standard inputról olvas. Minden utasítást rögtön a beolvasás után végrehajt ( így pl. ha egy file egy olyan utasítást tartalmaz amely megállítja a process-t akkor a bc nem olvas tovább a standard inputról. )
Ez a verzió a szokásos bc-hez és az egyszerû POSIX bc-hez képest számos kiegészítô szolgáltatással szolgál, így lehetséges, hogy más bc verziókkal megírt programok futtatásakor hibaüzenetet kapunk. A megfelelô helyen majd erre vonatkozó megjegyzéseket találhatunk.
A legalapvetôbb egység a szám. A számok tetszôleges pontosságúak ( mind az egész, mind a tört rész ). A számok tárolása és a velük végzett mûveletek mind decimálisan történnek. ( Ez a verzió szorzás és osztás esetén végezhet esetleges (lefele-)kerekítéseket ). A számoknak két attribútuma a hossz és a pontosság ( scale ): a hossz az összes tizedes jegy, míg a pontosság pedig a tizedespont mögött álló jegyek számát jelenti. Pl. :
.000001 hossza 6, pontossága 6; 1935.000 hossza 7, pontossága 3.
A számokat kétféle változóban tárolhatjuk: egyszerû változókban ill. tömbökben ( mindkét fajtára nevekkel hivatkozhatunk ). A nevek betûvel kezdôdnek, majd tetszôleges számú betû, szám vagy aláhúzás (_) karakter szerepelhet. A betûk kisbetûsek kell, hogy legyenek. ( Egy betûkbôl és számokból álló kifejezések használata plusz szolgáltatás. A POSIX-ben a nevek csak kisbetûket tartalmazhatnak). Egy változó típusa a környezetébôl rögtön kideríthetô, mivel a tömbváltozók nevét [ ] követi.).
4 speciális változó van a bc-ben: scale, ibase, obase és a last. A scale változó a tizedespont után álló jegyekkel végzett néhány utasítás végrehajtását szabályozza ( kezdeti értéke 0 ). Az ibase ill. obase adja meg, hogy hányas számrendszerben kezeli a ki- ill. bemenô adatokat ( mindkettô kezdeti értéke 10 ). A last értéke mindig az éppen kiirt szám értéke ( Ennek részletesebb tárgyalását lásd késôbb. ). Ezen változóknak is a megszokott módon adhatunk értéket.
A megjegyzéseket /* ill. */ karakterek határolják; bárhol kezdôdhetnek és egyetlen szóközként jelennek meg a bemeneten. ( Ez viszont az utasításokat némiképp megváltoztathatja, ezért pl. egy változó nevén belül nem szerepelhet megjegyzés. ). Egy megjegyzésen belül azonban akárhány sortörés szerepelhet.
A számok általában kifejezésekben és utasításokban fordulnak elô. A nyelv interaktív mivoltából kifolyólag az utasításokat és kifejezések a lehetô leghamarabb kifejti a bc. Itt nincs "fôprogram" . Az utasítások rögtön a kiadásuk után végrehajtásra kerülnek. ( A függvények definiálását ld. késôbb ).
Egyszerû kifejezés pl. egy konstans. A konstansokat az ibase értékének megfelelôen alakítja át decimális számokká a bc. ( A függvényeknél van ez alól kivétel ). Az ibase lehetséges értéke 2 .. 16 (F). Ha ezen az intervallumon kívüli számot adunk meg akkor az ibase értéke egy 2..16 beli számot vesz fel. A bemenô adatok a 0..9 ill. A-F karaktereket tartalmazhatják. ( Megjegyzés: Fontos, hogy nagybetût használjunk, mivel a kisbetûk változókat jelölnek ). Az egyjegyû számok értéke mindig a decimális érték az ibase-tôl függetlenül. (pl. A = 10 ). Többjegyû számok esetén az ibase értékénél nem kisebb jegyeket ibase-1 -é alakítja. Így az FFF szám az ibase értékétôl függetlenül mindig a legnagyobb értékû 3-jegyû számot jelenti ( abban a számrendszerben ).
A összetett kifejezések számos más magas szintû nyelvbelihez hasonlítanak. Mivel egyetlen típusú szám létezik, így a típuskonverziókra nincs is szabály;nem úgy a kifejezések pontosságára. Minden kifejezés adott pontosságú. Ez az eredeti számoktól, az elôforduló operandusoktól és sok esetben a változók pontosságától függ. A változók pontosságának értéke 0-tól a C nyelv beli integer felsô határáig terjedhet.
A következô példákban az "expr" egy teljes kifejezésre, míg a "var" egy egyszerû vagy tömbváltozóra utal. ( Egy egyszerû változó pl. name, ill. tömbváltozó name[expr] ).
Minden specialitás nélkül az eredmény pontossága a kifejezésben szereplô tagok pontosságának a maximuma.
A relációk speciális kifejezések melyek értéke 0 vagy 1, attól függôen, hogy a reláció hamis ill. igaz( tetszôleges kifejezésekben elôfordulhatnak ). A POSIX bc-ben a relációk csak if, while vagy for kifejezésekben szerepelhetnek és ott is csak egyszer . A megengedett relációk a következôk:
Logika mûveletek szintén megengedettek. (a POSIX bc-nek nincsenek logikai mûveletei. A logikai mûveletek eredménye 0 vagy 1 (a hamis vagy igaz helyett) akárcsak a relációs kifejezéseknél. A logikai mûveletek a következôk:
A mûveleti sorrend a következô (az utolsótól az elsôig):
|| mûvelet, balról asszociatív && mûvelet, balról asszociatív ! mûvelet, nem asszociatív Relációs mûveletek, balról asszociatívak Értékadás mûvelet, jobbról asszociatív + és - mûveletek, balról asszociatívak *, / és % mûveletek, balról asszociatívak ^ mûvelet, jobbról asszociatív unary - mûvelet, nem asszociatív ++ és -- mûveletek, nem asszociativak
A sorrend azért lett így választva, hogy a POSIX szerinti bc programok helyesen fussanak. Emiatt a relációs és logikai mûveletek értékadással való használata, néhány szokatlan eredményt hozhat. Nézzük például a következô kifejezést:
a = 3 < 5
A legtöbb C programozó azt várná, hogy az "a" változóba a "3 < 5" (1) értékét tesszük. Itt viszont az történik, hogy a bc a 3-at adja értékül "a" -nak, majd ezt összehasonlítja az 5-tel. Jobb zárójelet használni, mikor relációs, vagy logikai mûveletket használunk értékadással együtt.
A bc még néhány különleges kifejezéssel szolgál. Ezeket a felhasználó által definiált, vagy beépített eljárásokkal együtt használjuk. Mind úgy tûnik fel, mint "név(paraméterek)". Lásd az eljárások felhasználó által definiált eljárásokhoz fejezetet. A beépített eljárások a következôk:
Az állítások (mint a legtöbb algebrai nyelvben) elkészítik a kifejezés sorrendjének kiértékelését. A bc-ben olyan gyorsan hajtódnak végre az állítások, amennyire csak lehet. A végrehajtás akkor történik,amikor egy új sor következik és egy, vagy több állítás szerepel. Az azonnali végrehajtás következtében az új sorok, nagyon fontosak a bc-ben. Valójában mindkettô, mind a pontosvesszô, mind az új sor hasznalható állítás szeparátorként. Mivel az új sorok állítás szeparátorok, ezért egy új sort a backslash karakter használatával lehetséges elrejteni. A számsor "\<nl>", ahol <nl> egy új sor, a bc-nek whitespacenek tünik újsor helyett.Egy állítás lista vesszôkkel és újsorokkal elkülönített állítások sorozata.Bc állítások listája következik, és hogy mire használhatók, azokat a dolgokat, melyek nem kötelezô részei az állításoknak, zárójel veszi körül ([]).
kif11; while (kif2) { állítás; kif3; }
A paraméterek számok vagy tömbok (ez egy bôvítés). A függvény definícióban nulla vagy több paramétert a nevük vesszôvel elválasztott listájával adunk meg. A számokat csak érték szerinti paraméterrel hivhatunk, tömböket csak változóval. Tömböket a paraméter definícióban specifikálunk a "name[]" jelöléssel. A függvény hívásában az aktuális paraméterek teljes kifejezések szám paraméterek számára. Ugyanez a jelölés használatos tömbök beillesztésére definíciós tömb paraméterekként. A megnevezett tömb változóval illesztôdik be a függvénybe. Mióta a függvénydefiníciók dinamikusak, a paraméterszámok és típusok ellenôrzôdnek, mikor egy függvényt meghívunk. Bármi eltérés a paraméterek számában vagy típusában futáshibát okoz. Futási hiba keletkezik akkor is, ha egy definiálatlan függvényt hívunk meg.
Az auto_list egy opcionális lista olyan változóknak, amiket "helyben" használunk. Az auto_list (ha létezik) szintaxisa "auto név, ... ;". (A pontosvesszô opcionális.) Minden név egy auto változó neve. Tömböket hasonló jelöléssel lehet specifikálni, mint a paramétrereknél. A függvény kezdetekor a változók értékei bekerülnek egy verembe, ezután az változók nulla értékkel indulnak, és használódnak a futtatás alatt. A használat befejeztével ezek a változók kikerülnek a verembôl, így a függvény hívásakori eredeti értékek állítódnak vissza. A paraméterek auto változók, amelyek beállítódnak egy függvényhíváskori értékre. Az auto változók különböznek a hagyományos lokális változóktól abban, hogy ha A függvény meghívja B függvényt, a B B elfogadhatja az A auto változóit azáltal, hogy ugyanazokat a neveket használja, hacsak B nem az ô auto változóiként hívta meg ôket. Annak megfelelôen, hogy az auto változók és a paraméterek egy verembe kerülnek, bc támogatja a rekurzív függvényeket.
A függvény törzse egy lista bc parancsokbol. A parancsok most is pontosvesszôvel vagy újsor karakterrel vannak elválasztva. A visszatérési parancsok gondoskodnak a függvény befejeztérôl és egy érték visszaadásáról. Kétfajta visszatérési parancs létezik. Az elsô formája "return" visszaadja a 0 értéket a hívó kifejezésnek. A második forma, "return ( kifejezés )", kiszámolja a kifejezés értékét, és azt az értéket adja vissza. Minden függvény végén egy "return (0)" van. Ez engedélyezi a függvénynek, hogy megálljon és 0-t adjon vissza explicit visszatérési utasítás nélkül.
A függvények különböznek az ibase változó használatában is. Minden függvénytörzsbeli konstans átalakítódik az ibase meghíváskori értékének használatával a függvény meghívásakor. Az ibase változásai figyelmen kívül lesznek hagyva a függvény futása alatt, kivéve a read alapfüggvényt, amely mindig az ibase aktuális értékét használja számok konvertálásához.
A /bin/sh-ban a következôképpen adhatjuk át "pi" értéket a pi shell változónak.
pi=$(echo "scale=10; 4*a(1)" | bc -l)
A következô példa az exponenciális függvényt definálja, ahogyan az a matematikai könyvtárban található. Ezt a függvényt POSIX bc-ben írták.
scale = 20
/* Azt a tényt felhasználva, hogy e^x = (e^(x/2))^2 Amikor
az x eléggé kicsi, sorozatokat használunk: e^x = 1
+ x + x^2/2! + x^3/3! + ... */
define e(x) { auto a, d, e, f, i, m, v, z
/* Az x elôjelét vizsgálja meg. */ if (x<0) { m
= 1 x = -x }
/* x elôfeltétel. */ z = scale; scale = 4 + z + .44*x; while
(x > 1) { f += 1; x /= 2; }
/* Változók inicalizálása. */ v = 1+x a = x
d = 1
for (i=2; 1; i++) { e = (a *= x) / (d *= i) if (e == 0) { if (f>0) while
(f--) v = v*v; scale = z if (m) return (1/v); return (v/1); } v += e }
}
A következí példa a bc kiterjesztett tulajdonságait használja fel ahhoz, hogy egy egyszerû programmal elvégezze egy csekkönyv egyenlegének kiszámítását. Legcélszerûbb ezt a programot egy fájlban tartani, hogy többször fel lehessen használni újragépelés nélkül.
scale=2 print "\nCsekkonyv program!\n"
print " Emlekeztetoul, a betet negativ tranzakcio.\n" print "
Kilepes 0-s tranzakcioval.\n\n"
print "Kezdo egyenleg? "; bal = read() bal /= 1 print "\n"
while (1) { "Jelenlegi egyenleg = "; bal "tranzakcio? ";
trans = read() if (trans == 0) break; bal -= trans bal /= 1 } quit
A következô példa a rekúrzív faktoriális függvény definiciója.
define f (x) { if (x <= 1) return (1); return (f(x-1) * x); }
A bc-nek ez a verziója a POSIX P1003.2/D11-tól van bevezetve és tartalmaz néhány különbséget és bôvítést a hagyományos kivitelezéshez képest. Nem a hagyományos módon van bevezetve a dc(1) felhasználásával. Ez a verzió egy egyszerû feldolgozó, amelyik elemzi és futtatja a programnak egy byte kódú fordítását. Van egy "nem dokumentált" opció, aminek hatására a program az alapértelmezett kimenetre küldi a byte kódot ahelyett, hogy lefuttatná. Ezt fôként az elemzés debuggolásához és a matematikai könyvtár elôkészítéséhez használták.
Egy nagyobb különbségek forrása a fejlesztés maga, amikor egy jellemzôjét kibôvítették, több funkcióval látták el. A következô lista tartalazza a különbségeket és a bôvítéseket.
a = 1 b = 2
has two execution blocks and
{ a = 1 b = 2 }
has one execution block. Any runtime error will terminate the execution of the current execution block. A runtime warning will not terminate the current execution block.
The following are the limits currently in place for this bc processor. Some of them may have been changed by an installation. Use the limits statement to see the actual values.
In most installations, bc is completely self-contained. Where executable size is of importance or the C compiler does not deal with very long strings, bc will read the standard math library from the file /usr/local/lib/libmath.b. (The actual location may vary. It may be /lib/libmath.b.)
If any file on the command line can not be opened, bc will report that the file is unavailable and terminate. Also, there are compile and run time diagnostics that should be self-explanatory.
Error recovery is not very good yet.
Philip A. Nelson phil@cs.wwu.edu
The author would like to thank Steve Sommars (Steve.Sommars@att.com) for his extensive help in testing the implementation. Many great suggestions were given. This is a much better product due to his involvement.
Fordították:
Simon János György | redoak@valerie.inf.elte.hu |
KatonaEszter | keszter@valerie.inf.elte.hu |
Adamcsek Balázs | face@valerie.inf.elte.hu |
Kiszlinger Ildikó | kiszi@valerie.inf.elte.hu |
Sildó Csaba István | zorro@valerie.inf.elte.hu |
Somogyvári Tamás | halihow@ludens.elte.hu |