Summor i PostScript

Jag missbrukar nu PostScript. Detta språk används ju normalt för att generera text och grafik, inte att räkna med (vid utskrift av en textfil på vårt system omvandlas texten till ett PostScript-program, som skickas till skrivaren. När programmet exekveras av datorn i skrivaren så genereras utskriften). PostScript är stackbaserat (så det liknar Javas bytekod en del), men den enda stacken jag kommer att nämna är operandstacken där man lagrar funktionsargument och resultat.

Så här kan ett PostScriptprogram för att beräkna 5 (2 + 3) se ut. Vi kan låta skrivaren exekvera programmet, men enklare är att köra PostScript-interpretatorn, gs. För att slippa få upp ett textfönster och för att slippa diverse utskrifter ger jag några flaggor till gs. GS> är gs-prompten.

% gs -q -dNODISPLAY        starta gs
GS>%!                     
GS>2 3 add 5 mul ==
25
GS>5 2 3 add mul ==
25
GS>quit

Några kommentarer. %! är ett så kallat magic number som identifierar filen som en PostScriptfil (gör man file för detaljer). Varje PostScriptfil skall inledas med %!
 
2 3 "pushar" termerna 2 och 3 på stacken. Additionsoperatorn, add, tar, "poppar", de två översta elementen från stacken, adderar dessa och lägger summan överst på stacken. Jag pushar sedan talet 5 på stacken, multiplikationsoperatorn mul tar de två översta elementen från stacken och multiplicerar dessa och lägger produkten överst på stacken. == poppar det översta elementet från stacken och skriver ut detta (talet 25) följt av ett nyradstecken.

Nästa rad, 5 2 3 add mul ==, visar ett annat sätt att utföra samma beräkning. quit avslutar sessionen med interpretatorn.

Nu till vår summa. Först visar jag ett program (lägg detta på en fil och exekvera med gs -q -dNODISPLAY fil) där jag använder "variabler", s för summan och k för loopindex. % är kommentartecken.

%!
/s 0 def % s = 0 (ungefär) /k 0 def % k = 0 1000000 { % repetera allt inom { } 1000000 gånger /k 1 k add def % k := k + 1 (k är värdet) /s 1 k div s add def % s := s + 1 / k } repeat s == % skriv ut s quit

Lite roligare är att försöka beräkna summan utan att använda andra variabler än de som lagras på stacken. Här är en kod. Kan Du skriva en kortare?

%!
0 % 0 -> stacken, svarar mot s = 0 0 % 0 -> stacken, svarar mot k = 0 1000000 { % stackens utseende efter att raden exekverats 1 add % k+1 s dup % k k s k är nya k, (dup = duplicate) 1 % 1 k k 1 1 -> stacken exch % k 1 k s (exch = exchange) div % 1/k k s 3 -1 roll % s 1/k k (roll = cirkulärt skift) add % s+1/k k exch % k s s är nya uppdaterade s } repeat pop % s poppa k == % poppa och skriv ut s quit

Uppdelningen i rader är inte nödvändig, man kan t.ex. även skriva:

%!
0 0
1000000 {
1 add dup 1 exch div 3 -1 roll add exch}
repeat
pop ==
quit

Slutligen följer ett program där jag skriver ut summan (1/1 + ...  + 1/10) och visar lite av styrkan med PostScript. Exekvera med gs fil denna gång.

%!
0 0
10 { % Summera till 10 1 add dup 1 exch div 3 -1 roll add exch} repeat pop % summan, s, ligger nu på stacken /str 20 string def % ungefär char str[20] str cvs % s konverteras till en sträng som läggs % både i str och på stacken (ungefär) /gray 0 def % sätt gråvärdet till 0, svart /incgray % öka gråvärdet (incgray är en procedur) {/gray gray 0.1 add def} def % Hitta, skala och sätt typsnitt /Times-BoldItalic findfont 26 scalefont setfont 150 150 translate % Translatera origo till (150, 150) punkter. 10 { 0 0 moveto % Flytta insättningspunkten till origo 36 rotate % Rotera 36 grader moturs % Sätt gråvärdet och öka det sedan gray setgray incgray % Skriv strängen " s = ". Insättningspunkten flyttas till slutet % av strängen. Skriv sedan textrepresentationen av vår summa. ( s = ) show str show } repeat % "Skriv ut" showpage quit

Programmet producerar följande bild:

Summor


Back