Konzolos Mandelbrot - mar megint

Van ugye ez a bejegyzes. (Amugy nyugodjek bekeben.) Itt ketfele, konzolos parancssori Mandelbrot-halmaz rajzolo is feltunt. Az elso perl-ben, es mint iroja meg is jegyezte, egy twitbe belefer. Nyilvan ez is szep teljesitmeny.

A masodik, amelyik shell-scriptkent szerepel, felcsigazta a fantaziamat. (Ez az eredeti helye.) Eloszor az merult fel bennem, hogy ha esetleg kevesebbszer hivna meg a bc-t, azzal esetleg fel lehetne gyorsitani, aztan a kovetkezo gondolat az lett, hogy esetleg ugy ahogy van lehetne inkabb bc-ben csinalni. Nyilvan igy meg gyorsabb lenne. (Nyilvan? Valoszinunek tunt.)

Elso korben az olvashatatlanra tordelt kodot szepen megformaztam. Eztan szepen kicsereltem a "$e" hivasokat "echo"-ra, meg persze a "$b"-ket "bc"-re - egyszeruen csak azert, hogy en atlassam (ha mar egyszer ez is egy alkalmazott obfuscator technika volt). Szepeszet utan elkezdtem az eredmenyt tanulmanyozni. Feltuntek a bash-specifikus dolgok (for i in {1..24}, vagy az echo '\Eakarmi'). Aztan baromi sokat elszoszmotoltem az "eval" resszel a vege fele, mire nagy nehezen leesett, hogy ott egy folosleges(nek tuno) valtozohivatkozas szerepel (egy nem letezo valtozora az erdekesseg kedveert). (Mashol inicializalatlan valtozohivatkozas is van az eredeti kodban - a legelso helyen, ahol a C-re hivatkozik). De lassan kepben lettem.

Szepen sorban kezdtem atirni bc-re. Celom volt, hogy ha valami GNU-bc specifikus, azt ne hasznaljam. Mondjuk a POSIX-bc csak egykarakteres, kisbetus valtozoneveket ismer - ez meg nem volna gond, hisz nem kellett a kodba 26-nal tobb valtozo. (Mondjuk a kenyelem kedveert ezzel nem foglalkoztam, mondvan ha mar keszen vagyunk, egy vi-beli :%s///g megoldana az ilyen valtozonevekkel kapcsolatos gondokat.) Vagy. A POSIX-bc-ben nincs az "if"-nek "else" aga, ez mondjuk kicsit olvashatatlanna tenne a kodot, de az egy darab if/else meg siman szetszedheto ket if-re, ha nagyon kell. Szoval ez a POSIX-kompatibilis dolog nem latszott nagyon remenytelennek. Ez sajnos a vegere bukott.

Az atiras nagyresze konnyu, persze nem volt minden trivialis. Utolag baromi egyszeru (meg a doksiban is benne van), de amikor az ember irja, akkor nem jut eszebe, hogy bizony a bc-ben baromi nagy a kulonbseg, hogy a++, vagy a += 1 szerepel a "for" ciklus lepteto utasitasaban. Az ilyesmikkel jol elment az ido. Baromi sokaig tartott, mire rajottem arra, hogy azert nem szines, hanem iszonyatosan kriksz-krakszos a vegeredmeny, mert a bc sztring-kiirasra hasznalt parancsa ( "sztring" ) nem tesz ugyan Enter-t a szoveg moge (ami nagyon jo), ellenben a szamok kiirasanal tesz Entert (ami kb logikus is). Sajnos ez itt jol bekavar, mert a szinezeshez a szekvenciat harom reszbol rajta ossze az eredeti kod, aminek a kozepe egy szep kis shell-valtozo helyettesites. Erre nem is jottem ra, hogy mi modon lehetne megoldani, igy maradt a print. (Ez volt az a pont, amikor kenytelen-kelletlen feladtam a remenyt, hogy hordozhatora - POSIX-bc - megirom.)

Es amikor vegre minden mukodik, akkor se megy minden tokeletesen. Vannak szovegek, meg latszik a szinezes, de egy osszevisszasag az egesz. Jo darabig eltartott, mire rajottem az okara. A bc ugyanis, amikor kiirja a szamitasok (esetleg) baromi hosszu eredmenyet, a 70 karakternel hosszabb sorokat szepen tordeli. Eddig semmi gond, hiszen en (marmint az eredeti szerzo) gyakorlatilag karakterenkent irja ki a szoveget. Igen am, de a bc (legalabbis a GNU-fele) minden nyomorult kiirasnal ellenoriz, es szamontartja hogy hol vagyok. Es mivel a karakterek szinezese betunkent kb 6-7 plusz karakter (a ESC-vezerloszekvencia) kiirasat eredmenyezi, itt bizony 8-10 karakterenkent "hosszu a sor, tordelni kell" lett az eredmeny. Ezen egy darabig gorcsoltem, aztan itt feladtam, es elovettem inkabb az eredeti elkepzelest, hogy maradjon az sh-script, csak kevesebb bc-vel.

Eloszor is kidobtam a bash-specifikus dolgokat es atirtam "rendes" sh-ra. Kidobtam a felesleges valtozohivatkozast, inicializaltam az inicializalatlan valtozot, kicsereltem a bash-fele \E sztringet valodi ESC-re (ez nem tul szep, de micsinaljak), majd megneztem, mit lehetne tenni a gyorsitasert. Hat az eredeti kodban ugye minden valtozo ertekenek kiszamitasahoz a=`echo a+b|bc` format hasznal. A belso ciklus elejen van is harom + ketto bc hivas (meg kozben egy shellbeli szamolas). No ezt egy kis tunodes utan le lehet egyszerusiteni 2 db-ra, ez akarhogy is nezem, 60%-kal kevesebb. (Mindez egy 24*80*33-szor lefuto ciklusban.) Aztan meg egy-ket finomitas, es eloallt a mukodo eredmeny. Jott a teszt, es szepen latszott is, hogy gyorsult a dolog - no a regi laptopon amin teszteltem, nem lett latvanyosan gyorsabb, viszont meg az eredetinel is sokkal olvashatatlanabb (lenne, ha az eredeti tordelest en is alkalmaznam).

Miutan ezzel megvoltam, csak nem hagyott nyugodni a bc-s verzio. (Az egesz azert volt fontos, mert szerettem volna latni, hogy mennyivel lenne ugy gyorsabb.) Es egy kis fejvakaras utan be is ugrott a megoldas: mivel a bc itt mar nem okosithato, nincs mas dolgom, mint a bc altal kiirt szoveget meg egy kis atalakitasnak alavetni - erre jo pl. egy kis sed. No nekiindultam annak is, es eleg hamar meglettem vele. Immar mukodik a dolog. Sajnos miutan megcsinaltam, akkor jottem ra, hogy egy szepsege elveszik. Mivel gyakorlatilag mindegyik sor vegen realisan varhato a Backslash-Enter kombo, ezert a sednek be kell olvasni az egesz adatot, es feldolgozas utan egyszerre fog megjelenni az abra - nem ugy mint az eredetiben, ahol szepen nyomonkovetheto a rajzolas folyamata. No mindegy.

Vegul az eredmenyek:

Az eredeti bash-specifikus kod az en oreg laptopomon a time parancs szerint fut 1046,25 sec ideig.
Az altalam modositott verzio, amiben kidobtam a bash-specifikus dolgokat, es lecsokkentettem a bc-hivasok szamat (ellenben meg olvashatatlanabba tettem az egeszet), az pedig 473,04 sec ideig fut. Azert latszik, hogy szinte teljesen meg van a 60% nyereseg, amit a 60%-kal kevesebb bc-bol azert lehetett sejteni. (Ez utobbi igy ahogy van mar fut a FreeBSD nativ sh-javal is, azzal meg egy kicsit gyorsabb lett.)
Vegul pedig a bc-ben megirt verzio, ahol sajnos kell a kimenet finomitasa seddel, az 0,53 sec idot birt produkalni :-)

Szoval fel masodperc a ~500 illetve a ~1000 elleneben :-)

Ja, a kodok: az altalam modositott shell+bc verzio (rendesen tordelve)


#!/bin/sh
S0=S;S1=H;S2=E;S3=L;S4=L;e=echo;b=bc;I=-1
C=0
x=1 ; while [ "$x" -le 24 ] ; do
	R=-2
	y=1 ; while [ "$y" -le 80 ] ;do
		B=0;r=0;i=0
		while [ $B -le 32 ];do
			eval `$e '"r2=";'"$r*$r;"'"i2=";'"$i*$i;"'"i=";'"2*$i*$r+$I;"|$b`
			eval `$e '"r=";'"$r2-$i2+$R;"'"B=";'"$B+1;"'"V=";'"($r2+$i2)>4;"|$b`
			if [ "$V" -eq 1 ];then break;fi
			done;
		if [ $B -ge 32 ];then 
			$e -n " "
		else
			U=$(( ( $B * 4 ) / 15 + 30 ))
			$e -n "^[[01;$U""m"
			C=$(( $C % 5 ));
			eval "$e -n \$S$C"
			C=$(( $C + 1 ))
		fi
		R=`$e "$R+0.03125"|$b`
		y=$(( $y + 1 ))
		done
	$e "^[[m"
	I=`$e "$I+0.08333"|$b`
	x=$(( $x + 1 ))
done

(Sajnos a szinezes ki es bekapcsolasahoz ESC-szekvencia kell, amit hordozhatoan csak ugy lehet begepelni, hogy a sztringbe valoban ESC-karakter kerul. Ellenben szerintem igen olvasmanyosra sikeredett az eredetiben szereplo sok-sok ertekadasnak az eval-ositasa ;-) )

Es a masik, a bc-s kod:


#!/usr/bin/bc
ii = -1
for ( x = 1; x <= 24; x += 1 ) {
	rr = -2
	for ( y = 1; y <= 80; y += 1 ) {
		bb = 0 ; r = 0 ; i = 0
		while ( bb <= 32 ) {
			r2 = r * r ; i2 = i * i ; i  = 2 * i * r + ii
			r  = r2 - i2 + rr ; bb  += 1 ; vv  = ( ( r2 + i2 ) > 4 )
			if ( vv == 1 ) break
			}
		if ( bb >= 32 )	{
			" "
			} else	{
			uu = ( bb * 4 ) / 15 + 30
			"^[[01;" ; print uu ; "m"
			cc %= 5
			if ( cc == 0 ) "S"
			if ( cc == 1 ) "H"
			if ( cc == 2 ) "E"
			if ( cc == 3 ) "L"
			if ( cc == 4 ) "L"
			cc += 1
			}
		rr += 0.03125
		}
	print "^[[m^[(\r\n"
	ii += 0.08333
	}
quit

Itt szinten vannak ESC-ek, de ennek meg a hivasa is gyonyoru:


$ bc Mandelbrot.bc | sed -n -e 1h -e '2,$H' -e '${
g
s/\\\n//gp
}'

Vegul: es akkor mi van? Semmi, csak jatszottam egyet.

Hozzászólások

végre egy érdekes topic, már ki voltam "száradva" :)

Nem teljesen parancssoros, viszont tömör és szép:

gnuplot -persist -e 'se sa 200;se isos 200;se vi map;c(a,b)=a*{1,0}+b*{0,1};m(z,a,n)=n<=0||abs(z)>100?1:m(z*z+a,a,n-1)+1;sp [-2:1][-1.5:1.5] m({0,0},c(x,y),30) w pm3d'

jo, hogy meg vannak ilyen jatekos hangulatu blogok :)

Nekem nem Mandelbrot-fraktált rajzol ki, csak efféléket irkál ki:

vz@Csiszilla /Depot/Letolt]sh ./mandelbrot
^[[01;30mS^[[01;30mH^[[01;30mE^[[01;30mL^[[01;30mL^[[01;30mS^[[01;30mH^[[01;30mE^[[01;30mL^[[01;30mL^[[01;30mS^[[01;30mH^[[01;30mE^[[01;30mL^[[01;30mL^[[01;30mS^[[01;30mH^[[01;31mE^[[01;31mL^[[01;31mL^[[01;31mS^[[01;31mH^[[01;31mE^[[01;31mL^[[01;31mL^[[01;31mS^[[01;31mH^[[01;31mE^[[01;31mL^[[01;31mL^[[01;31mS^[[01;31mH^[[01;31mE^[[01;31mL^[[01;31mL^[[01;31mS^[[01;31mH^[[01;31mE^[[01;31mL^[[01;31mL^C

és így tovább.

Mi lehet a hiba nálam?
-------------
Használj GoboLinuxot!
http://mek.oszk.hu/05800/05895/
:::A #86-os sorszámú hivatalosan bejegyzett GoboLinux felhasználó

íEz a sok ocsmánysáh képernyő színezésére hazsnálható ESC-szekvencia. Az, hogy nálad nem a színváltás a következménye, ez annyit jelent, hogy a használt terminálemulátor nem ismeri ezeket a szekvenciákat. Próbáld bekapcsolni a DEC VT100 (vagy valami ennél komolyabb) terminál emulációját a használt eszközben.

Én az Mrxvt terminálemulátort használom, és fogalmam sincs, hogyan lehetne bekapcsolni rajta valami más terminál emulációját. De azt tudom, hogy az Mrxvt-ben is vannak színek, mert számos parancsnak szines output az eredménye benne, plusz természetesen a promptom is színes.
-------------
Használj GoboLinuxot!
http://mek.oszk.hu/05800/05895/
:::A #86-os sorszámú hivatalosan bejegyzett GoboLinux felhasználó

Rajottem. En a fenti kodban ^[ formaban irtam ki az ESC karaktereket, te meg ha copy'n'paste-tel raktad be, termeszetesen nemlesz belole ESC. Szoval a forrasban minden helyen ahol ^[ all, ezt csereld ki egy ESC karakterre. Ez vi-ban trivialis. (Es figyelj, az ESC csak ^[, a mogotte levo [ - vagy barmi egyeb - mar kell!)

Igazán kezdőhöz "méltó" kérdést teszek akkor most fel neked kedves Zahy:

Hogyan kell ESC karaktert bevinni (mondjuk az MC editorában)? Ugyanis még sosem fordult elő velem, hogy ezt kellett volna beütnöm, márpedig ha csak úgy simán Esc-t nyomok, akkor semmit nem ír be, ha meg az Esc után megnyomok egy másik billentyűt, akkor ki akar lépni a dokumentumból!
-------------
Használj GoboLinuxot!
http://mek.oszk.hu/05800/05895/
:::A #86-os sorszámú hivatalosan bejegyzett GoboLinux felhasználó

Sajnos erre nem tudok válaszolni, mert soha (értsd az elmúlt 10 évben biztosan nem) használtam MC-t, épp ezért feltelepítve sincs, így nem tudom. (vi-ban speciel szövegbevitel közben kell Ctrl-V -t beütni, majd utána az ESC-et - így került be a szövegbe valóban ESC, mégha ^[ formában jelzi is ki.)

azóta kipróbáltam, érdekes, nálam működik, szimplán a "ctrl+q esc esc" (így egymás után) egyetlen esc (dec27) karaktert szúr be, F4 után a replace is működik hiába a replace all előtt még csak pontnak látszik, utána már jó

mcedit --version
GNU Midnight Commander 4.7.0.6