übungsblatt 3, java aufgabe

Disclaimer: Dieser Thread wurde aus dem alten Forum importiert. Daher werden eventuell nicht alle Formatierungen richtig angezeigt. Der ursprüngliche Thread beginnt im zweiten Post dieses Threads.

übungsblatt 3, java aufgabe
hab die rechnerübung 4 gemacht, zwar nicht als applet mit eingabemaske oder sowas, aber es funzt :slight_smile:

public class Rational extends Number {
	int zaehler, nenner;
	Rational(int zaehler, int nenner){
	  this.zaehler=zaehler;
	  this.nenner=nenner; 
	}
	 
	int getzaehler(Rational rational){
		return zaehler;
	}
	
	int getnenner(Rational rational ){
		return nenner;
	}
	
	static Rational mult(Rational rational1, Rational rational2){
		int reszaehler,resnenner;
		reszaehler = rational1.getzaehler(rational1) * rational2.getzaehler(rational2);
		resnenner = rational1.getnenner(rational1) * rational2.getnenner(rational2);
		Rational resRationalmult = new Rational(reszaehler, resnenner);
		return resRationalmult.kuerze(resRationalmult);
	}
	
	static Rational div(Rational rational1, Rational rational2){
		int reszaehler,resnenner;
		reszaehler = rational1.getzaehler(rational1) * rational2.getnenner(rational2);
		resnenner = rational1.getnenner(rational1) * rational2.getzaehler(rational2);
		Rational resRationaldiv = new Rational(reszaehler, resnenner);
		return resRationaldiv.kuerze(resRationaldiv);
	}
	
	static Rational add(Rational rational1, Rational rational2){
		int reszaehler,resnenner,zaehler1,nenner1,
		zaehler2,nenner2,hauptnenner,erweiter1,erweiter2;
		zaehler1 = rational1.getzaehler(rational1);
		nenner1 = rational1.getnenner(rational1);
		zaehler2 = rational2.getzaehler(rational2);
		nenner2 = rational2.getnenner(rational2);
		hauptnenner = nenner1 * nenner2;
		erweiter1 = hauptnenner / nenner1;
		erweiter2 = hauptnenner / nenner2;
		resnenner = hauptnenner;
		reszaehler = (erweiter1 * zaehler1) + (erweiter2 * zaehler2);
		Rational resRationaladd = new Rational(reszaehler, resnenner);
		return resRationaladd.kuerze(resRationaladd);
		}
		
	static Rational sub(Rational rational1, Rational rational2){
		int reszaehler,resnenner,zaehler1,nenner1,
		zaehler2,nenner2,hauptnenner,erweiter1,erweiter2;
		zaehler1 = rational1.getzaehler(rational1);
		nenner1 = rational1.getnenner(rational1);
		zaehler2 = rational2.getzaehler(rational2);
		nenner2 = rational2.getnenner(rational2);
		hauptnenner = nenner1 * nenner2;
		erweiter1 = hauptnenner / nenner1;
		erweiter2 = hauptnenner / nenner2;
		resnenner = hauptnenner;
		reszaehler = (erweiter1 * zaehler1) - (erweiter2 * zaehler2);
		Rational resRationalsub = new Rational(reszaehler, resnenner);
		return resRationalsub.kuerze(resRationalsub);
		}
	
	Rational kuerze(Rational rational){
		int zaehler,nenner;
		zaehler = rational.getzaehler(rational);
		nenner = rational.getnenner(rational);
		int ggt = 0;
		ggt = gcd(zaehler, nenner);
		rational = new Rational(zaehler/ggt, nenner/ggt);
		return rational;
	}
	
	static String printrational(Rational rational){
		String prirat = rational.getzaehler(rational)+"/"+rational.getnenner(rational);
		return prirat;
	}

	public static void main(String[] args) {
		Rational z1 , z2, erg0, erg1, erg2, erg3;
		String az1,az2,aerg0,aerg1,aerg2,aerg3;
		z1 = new Rational(2, 7);
		z2 = new Rational(1, 8);
		az1 = printrational(z1);
		az2 = printrational(z2);
		erg0 = mult(z1, z2);
		erg1 = div(z1, z2);
		erg2 = add(z1, z2);
		erg3 = sub(z1, z2);
		aerg0 = printrational(erg0);
		aerg1 = printrational(erg1);
		aerg2 = printrational(erg2);
		aerg3 = printrational(erg3);
		
		System.out.println("Die Ergebnisse lauten: ");
		System.out.println(az1+" * "+az2+"= "+ aerg0);
		System.out.println(az1+" / "+az2+"= "+ aerg1);
		System.out.println(az1+" + "+az2+"= "+ aerg2);
		System.out.println(az1+" - "+az2+"= "+ aerg3);

	}
}

…ach ja die methode zur bestimmung des GGT wird bei mir aus der klasse Number vererbt, muss man halt noch in die Klasse Rational einbinden wenn mans nich irgendwoher vererben kann, aber das is ja klar
:finger:


darf ich da auch mal meinen senf dazugeben? :smiley:
also ich hab jetzt nur die klasse an sich, keine ein/ausgabe-funktionen. macht mir ja alles bluej, deshalb hab ich’s net gebraucht…

public class rational
{
    private int m_z;
    private int m_n;

    // konstruktor ----------

    public rational()
    {
        m_z = 0;
        m_n = 1;   // nenner darf nie null sein
    }

    // private funktionen ----------

    private int ggt(int a, int b)
    {
        if (b == 0) return a;
        if (b > a) return ggt(b, a);
        return ggt(b, a - b);
    }

    private void kuerzen()
    {
        int g = ggt(m_z, m_n);
        if (g == 0) return;
        m_z /= g;
        m_n /= g;
    }

    // setzen/lesen ----------

    public rational set(int z, int n)
    {
        // neue werte zuweisen
        m_z = z;
        m_n = n;
        // kuerzen
        kuerzen();

        return this;
    }

    public double get()
    {
        return (double) m_z / (double) m_n;
    }

    public int get_z()
    {
        return m_z;
    }

    public int get_n()
    {
        return m_n;
    }

    // operationen fuer 2 integer ----------

    public rational add(int z, int n)
    {
        int i = m_n;
        // 1. zahl erweitern
        m_z *= n;
        m_n *= n;
        // 2. zahl erweitern
        z *= i;
        n *= i;
        // zahlen addieren
        m_z += z;
        // zahl kuerzen
        kuerzen();

        return this;
    }

    public rational sub(int z, int n)
    {
        int i = m_n;
        // 1. zahl erweitern
        m_z *= n;
        m_n *= n;
        // 2. zahl erweitern
        z *= i;
        n *= i;
        // zahlen subtrahieren
        m_z -= z;
        // zahl kuerzen
        kuerzen();

        return this;
    }

    public rational mult(int z, int n)
    {
        // zahl multiplizieren
        m_z *= z;
        m_n *= n;
        // zahl kuerzen
        kuerzen();

        return this;
    }

    public rational div(int z, int n)
    {
        if (z != 0 && n != 0)
        {
            // zahl dividieren
            m_z *= n;
            m_n *= z;
            // zahl kuerzen
            kuerzen();
        }

        return this;
    }

    // operationen fuer rationale argumente ----------

    public rational add(rational r)
    {
        return add(r.get_z(), r.get_n());
    }

    public rational sub(rational r)
    {
        return sub(r.get_z(), r.get_n());
    }

    public rational mult(rational r)
    {
        return mult(r.get_z(), r.get_n());
    }

    public rational div(rational r)
    {
        return div(r.get_z(), r.get_n());
    }

}

in meinen relativ ausgedehnten tests hat alles problemlos funktioniert. wenn jemand nen fehler findet…
ich hoff auch einfach mal, dass die zugrundeliegende algebra nicht noch irgendwelche fehler aufweist :-/

Rechnerübung 5
Hi there…

ich hab mich an der R5 meine ersten kargen Java-Kenntnisse geübt. Über Verbesserungen (und v.a. Abkürzungen!!!) wäre ich sehr dankbar! funzen tut es jedenfalls… :wink:

import java.io.*;

class Syntax
{
	private int anzahlA;
	private int anzahlB;
	private int anzahlC;
	private String[] wort;
	
	public Syntax(int a, int b, int c, String[] wort) {
		this.anzahlA = a;
		this.anzahlB = b;
		this.anzahlC = c;
		this.wort = wort;
	}
		
	public boolean test() {
		if (this.anzahl(wort) && this.reihenfolge(wort)) {
			return true;
		} else {
			return false;
		}
	}
	
	public boolean reihenfolge(String[] wort) {
		for (int i = 0; i < wort.length; i++) {
			if (i == 0) {
				if (wort[i].equals("b")) {
					return false;
				}
			} else {
				if (i == (wort.length - 1)) {
					if (wort[i].equals("a")) {
						return false;
					}
				} else {
					if ((wort[i].equals("a") &&
						 wort[i + 1].equals("b")) ||
						 
						(wort[i].equals("b") &&
						 wort[i + 1].equals("a")) ||
						 
						(wort[i].equals("b") &&
						 wort[i + 1].equals("c")) ||
						 
						(wort[i].equals("c") &&
						 wort[i + 1].equals("a"))) {
						 	
						 	return false;
						 }
					}
				}
		}
		return true;
	}

	public boolean anzahl(String[] wort) {
		for (int i = 0; i < wort.length; i++) {
			if (wort[i].equals("a")) {
				anzahlA++;
			} else {
				if (wort[i].equals("b")) {
					anzahlB++;
				} else {
					if (wort[i].equals("c")) {
						anzahlC++;
					} else {
						return false;
					}
				}
			}
		}
		if ((anzahlC >= 2) && (anzahlB == (2 * anzahlA))) {
				return true;
			} else {
				return false;
			}
	}
				
	public static void main(String[] args) {
		
		boolean weiter = true;
		
		while (weiter) {
		
			BufferedReader console =
					new BufferedReader
						(new InputStreamReader(System.in));
					
			String wortString = new String("");
			String frage = new String("");
		
			try {
				System.out.print ("\n\nWort eingeben: ");
				wortString = console.readLine();
			} catch (IOException e) {};
		
			String[] wort = new String[wortString.length()];
			
			for (int i = 0; i < wortString.length(); i++) {
				wort[i] = (wortString.substring(i, i + 1));
			}
		
			Syntax myWord = new Syntax(0, 0, 0, wort);
		
			if (myWord.test()) {
				System.out.println ("\nDas Wort wurde akzeptiert!");
								
				try {
					System.out.print ("\n\nSoll noch ein Wort überprüft " +
									  "werden? (j/n)");
					frage = console.readLine();
				} catch (IOException e) {};
				
				if (frage.equals("n")) {
					weiter = false;
				}
			} else {
				System.out.println ("\nDas Wort wurde nicht akzeptiert!");
			
				try {
					System.out.print ("\n\nSoll noch ein Wort ueberprueft " +
                                      "werden? (j/n)");
					frage = console.readLine();
				} catch (IOException e) {};
				
				if (frage.equals("n")) {
					weiter = false;
				}
			}
		}
	}
}

ich hoffe nicht zuviel mist zu verzapfen :cool:
ansonsten bitte folgenden code ausführen:

this.ordentlich_zur_sau_machen();

[line]
rekursiver abstieg? :finger:
war da nicht was mit pro produktion eine methode?
[line]

in der methode anzahl:
du kannst einfach die blöcke um die else zweige weglassen, da du danach direkt ein if setzt, also

if (blubb) {
} else if (blabb) {
} else {
}

oder einfacher per switch statement http://java.sun.com/docs/books/tutorial/java/nutsandbolts/switch.html
da die methode wohl nur intern gebraucht wird, private deklarieren.
das gleiche gilt für reihenfolge ().

in der funktion main:
das einzige, was die pfade am schluss unterscheidet, ist das print statement. den rest kannst du einfach rausziehen und nach dem if einfügen. dadurch ist es nicht doppelt, und das sieht schwer nach copy’n’paste aus … :wink:

if (myWord.test()) {
   System.out.println ("nDas Wort wurde akzeptiert!");
} else {
   System.out.println ("nDas Wort wurde nicht akzeptiert!");
}            
try {
   System.out.print ("nnSoll noch ein Wort ueberprueft " +
      "werden? (j/n)");
   frage = console.readLine();
} catch (IOException e) {};
                
if (frage.equals("n"))
   weiter = false;

in der methode test:

this.anzahl(wort)

da test eine methode ist, reicht zu schreiben

anzahl(wort)

weiter. wort ist eine instanzvariable, muss also nicht explizit übergeben werden, sondern anzahl hat direkten zugriff auf sie!

anzahl()

HTH


Vielen Dank@Kabel dass Du Dich da durchgekämüft hast… :smiley:

das mit switch funzt hier aber nicht… habs zumindest net hingekriegt. Ich glaube auch gelesen zu haben dass den case-Ausrücken immer nur ganze feste Integerzahlen (und keine variablen) als “Case”-Werte zugeordnet werden dürfen. “wort.length - 1” darf hinter case als wert für i somit net stehen… also doch mit if! :-/
Oder hab ich nur was falsch gemacht?!

ansonsten: deine Kritik zu rekursivem Abstieg ist natürlich berechtigt. Ich wüsste aber nicht wie ich das mit einer Kontextsensitiven Grammatik hinkriegen soll… weiss Du / jemand Rat!?


wer sagt denn, dass die grammatik kontextsensitiv ist? die linken seiten sind einfache variablen, also ist der “kontext” leer, d.h. die produktionen sind kontextfrei. ich hab da so ein komisches gefühl, dass kontextsensitive grammatiken nicht einfach zu implementieren sind :cool:

mit dem String[] array hast du zugriff auf die einzelnen buchstaben des eingabestrings.
die aufspaltung

for (int i = 0; i < wortString.length(); i++) {
   wort[i] = (wortString.substring(i, i + 1));
}

gehört meines erachtens aber in den “konstruktor” aka initialisator, da das ein detail deiner implementierung ist.

andererseits verbrätst du hier einiges, mit der methode charAt(index) kannst du direkt einen buchstaben aus einem string extrahieren. du müsstest also nur das wort und einen index in das wort in der instanz speichern. der aktuell zu betrachtende buchstabe ist dann

TheWord.charAt(TheWordIndex)

:slight_smile: so isses jedenfalls bei meiner implementation. versteh’ mich nicht falsch, deine methode funktioniert genauso; sie ist nur ineffizienter.

[m]zum thema switch[/m]
die beschränkung ist sinnfrei :vogel:
http://yost.com/computers/java/string-switch/
workaround, das hier funktioniert:

switch(wort[i].charAt(0)) {
   case 'a': anzahlA++; break;
   case 'b': anzahlB++; break;
   case 'c': anzahlC++; break;
   default : return false;
}

der “trick” ist von http://forum.java.sun.com/thread.jsp?thread=107707&forum=54&message=283790
und funktioniert nur dann, wenn der erste buchstabe als unterscheidungsmerkmal genügt.

wenn nicht, dann gibts da ein problem :smiley:


hi,

hier mein parsercode fuer die rechneruebung 5. die varnamen hab ich aus dem skript uebernommen und die funktionalitaet insofern erweitert, als dass er jetzt am schluss explizit sagt, ob das wort element der grammatik ist oder nicht.
bei fragen einfach fragen :smiley: ! das ganze ist jetzt schon recht universal, so dass eine veraenderung der grammatik keine grosse veraenderung des codes bewirkt.

import java.io.*;

public class Parser2 {
	private static char currentSymbol; //der aktuelle Buchstabe
	private static int anzahlFehler = 0; //Fehlercounter
	
	private static void s () { //Startsymbol
		if (currentSymbol == 'a') {
			getSymbol ();
			s ();
			for (int i = 0; i < 2; i++) {
				if (currentSymbol == 'b') {
					getSymbol ();
				} else {
					fehler ();
				}
			}
		} else if (currentSymbol == 'c') {
			getSymbol ();
			a ();
		} else {
			fehler ();
		}
	}
	
	private static void a () { //A-Symbol
		if (currentSymbol == 'c') {
			getSymbol ();
			while (currentSymbol == 'c') {
				getSymbol ();
			}
		} else {
			fehler ();
		}
		while (currentSymbol == 'c') {
			getSymbol ();
		}
	}
	
	private static void getSymbol () { //naechsten Buchstaben in den Speicher holen
		int c = -1;
		try {
			c = System.in.read ();
		} catch (IOException e) {}
		currentSymbol = (char) c;
	}
	
	private static void fehler () { //Fehlerausgaberoutine
		anzahlFehler++;
		System.out.println ("Symbol \"" + String.valueOf(currentSymbol) +
						"\" ist an dieser Stelle nicht erlaubt!");
	}
	
	public static void main (String args []) {
		getSymbol (); //ersten Buchstaben in den Speicher holen
		s (); //Startsymbol aufrufen
		if (currentSymbol != (char) 13) { //Terminierung mit Carriage Return
			fehler ();
			System.out.println ("Das eingegebene Wort ist KEIN Element der Grammatik!");
		} else {
			if (anzahlFehler == 0) {
				System.out.println ("Das eingegebene Wort IST Element der Grammatik!");
			} else {
				System.out.println ("Das eingegebene Wort ist KEIN Element der Grammatik!");
			}
		}
	}
}

@tsunami:

ich hab mir jetzt auch mal deinen code angeschaut und krampfhaft versucht, ein gegenbeispiel zu finden, das deine klasse nicht akzeptiert :smiley: . hab aber nix gefunden ;-). besonders uebersichtlich und effizient ist das ganze natuerlich nicht, das ist ja aber nicht so schlimm. aber wie das (? :smiley: ) kabel schon gesagt hat, ist das kein rekursiver abstieg. das ganze konzept hat den vorteil, dass man eine einmal erstellte implementierung nur wenig aendern muss, wenn man die grammatik etwas abaendert.
fuer dieses beispiel hat man z. b. auch ueberhaupt keine objektorientierung gebraucht - ein c-code wuerde fast gleich aussehen. ich hatte vor diesem semester keine ahnung von oo - bin aber echt begeistert davon, macht einen haufen spass. deshalb hoffe ich, dass mehr oo-aufgaben kommen…


:finger: gerade bei so länglichen codebeispielen sollten wir für jede aufgabe wenigstens einen eigenen thread aufmachen…

thread-splitting is ja leider noch nicht im forum drin, hab wenig zeit im moment :frowning:


naja,
sind ja jetzt auch nur zwei aufgaben: rational und parser. man wird es ueberleben, denke ich. bei der laenge der codes sollte man fuer jedes posting einen neuen thread aufmachen :wink: .


öhh, ok, :smiley: hab da ne funktion übersehen. vielleicht im benutzerprofil eine option, der code-blöcke versteckt, wenn sie mehr als eine (ebenfalls einstellbare) länge haben?!

stichwort länglich: bei den perlmonks http://www.perlmonks.org/index.pl?node_id=17558 gibt es readmore-tags (der link führt zur beschreibung). damit werden teile des posting ausgeschnitten; an die stelle des eigentlichen inhalts tritt ein link, der dann zum ganzen posting führt.

IMO ziemlich sinnvoll! :cool:


scnr, die prolog implementierung:

s --> [a], s, [b], [b].
s --> [c], a.

a --> [c], a2.
a2 --> [c], a2.
a2 --> [].

sehr nahe an der grammatik, nicht?! :cool:


Also Steppenwolf, ich hab jetzt mal Dein Programm getestet, und festgestellt, dass es z.B. “aaccbb” NICHT akzeptiert, genau wie bei mir. Das Problem ist der rekursive Aufruf von s(). Meiner Meinung nach erwartet das Programm nach jedem Aufruf von s() zwei “b”, eigentlich sollte er das aber nur beim LETZTEN Aufruf von s() machen. D.h. alle Wörter die mit mehr als einem “a” anfangen werden nicht akzeptiert - die Grammatik verlangt das aber.

if (currentSymbol == 'a') {
            getSymbol ();
            s ();
            for (int i = 0; i < 2; i++) {
                if (currentSymbol == 'b') {
                    getSymbol ();
                } else {
                    fehler ();
                }
            }
}

hi gandalf,

leider ist es zwar eine ewigkeit her, dass ich mich damit beschaeftigt habe, aber

das ist kein wunder! aaccbb SOLL es auch gar nicht akzeptieren, da die zugrundeliegende grammatik laut vorgabe folgende ist:

S → aSb² | cA
A → c{c}*

er koennte also hoechstens accbb oder aaccbbbb akzeptieren.

hth, steppenwolf


oh mann, is klar, und ich schlag mir die Nacht damit um die Ohren :rolleyes:


oh je, diese hitze… (siehe passender thread)