Unveraenderliche Klasse - Collatz Problem

donsao

Mitglied
So juten Abend freunde 😀

Ich habe hier eine Aufgabenstellung und komme partout nicht weiter, vllt. kann mir ja jemand von euch weiterhelfen.

Die Klasse Collatz repräsentiert eine solche Zahlenfolge.
Der Konstruktor legt den Startwert fest,
die Methode getNumber liefert die aktuelle Zahl und next wechselt zur nächsten Zahl.
Schließlich gibt isInLoop Auskunft darüber, ob der (vermutlich einzige)
Zyklus erreicht ist oder noch nicht.
Die Anwendung CollatzMain liest eine Zahl von der
Kommandozeile, initialisiert ein Collatz-Objekt und berechnet damit die Zahlenfolge,
bis der Zyklus erreicht ist.

Modifizieren Sie Collatz zu einer „stark unveränderlichen“ Klasse und passen Sie
das Hauptprogramm an.
Äußerlich funktioniert das neue Programm genauso wie das alte.

Hier ist der Collatz und der Collatz Main Code.

Java:
 public class Collatz
{
	/** Die aktuelle Zahl der Folge. */
	private int number;

	/** Ctor zum Start einer neuen Folge.
	 * @param number Erste Zahl der Folge.
	 */
	public Collatz(final int number)
	{
		this.number = number;
	}

	public int getNumber()
	{
		return number;
	}

	/** Wechselt zur nächsten Zahl der Folge.
	 */
	public void next()
	{
		if(number % 2 == 0)
			number /= 2;
		else
			number = 3 * number + 1;
	}

	/** Gibt Auskunft, ob die Folge in einem Zyklus steckt,
	 * das heißt, ab jetzt nur noch Zahlen liefert, die schon
	 * früher geliefert wurden.
	 * @return true = Folge läuft in einer Schleife; false andernfalls.
	 */
	public boolean isInLoop()
	{
		return number == 1 || number == 2 || number == 4;
	}

}

Java:
public class CollatzMain
{
	/** Hauptprogramm.
	 * @param args Kommandozeilenargumente.
	 * Erste Zahl der Folge.
	 * Alle weiteren bis zum Erreichen eines Zyklus werden ausgegeben.
	 */
	public static void main(final String... args)
	{
		final Collatz collatz = new Collatz(Integer.parseInt(args[0]));
		while(!collatz.isInLoop())
		{
			collatz.next();
			System.out.println(collatz.getNumber());
		}
	}

}

Nun habe ich die Objektvariable Number als final deklariert, und hab Collatz Next wie folgt veraendert.

Java:
public Collatz next()
	{
		int n = number;
		if(n % 2 == 0)
			n /= 2;
		else
			n = 3 * n + 1;
		Collatz result = new Collatz(n);
		return result;
	
	}

Nun weiss ich leider nicht weiter wie ich bei "isInLoop" nun auf dieses neue n zugreifen kann, da es mit number ja nichtmehr funktioniert.
Ich hoffe mir kann jemand helfen, vielen Dank schonmal dafuer 🙂
 
Nun weiss ich leider nicht weiter wie ich bei "isInLoop" nun auf dieses neue n zugreifen kann, da es mit number ja nichtmehr funktioniert.
Ich hoffe mir kann jemand helfen, vielen Dank schonmal dafuer
Fachlich habe ich zwar offen gestanden nicht verstanden, was dahinter steckt, aber programmiertechnisch müsstest Du in isInLoop() die Methode next() aufrufen
 
Es geht auch nur um diese Umstellung auf eine unveraenderliche Klasse, das ganze hat irgendwas mit dieser Collatz-Folge zu tun, welcher aber nicht wirklich relevant (da Formel schon gegeben) ist.

Das hatte ich auch schon probiert, bloss next() hat ja als return-Wert ein Collatz-Typ und kein Int-Typ, weswegen die Boolean Vergleiche dann nicht hinhauen.

EDIT: Nun gebe ich int n als return Wert bei der Next-Methode zurueck, womit "isInLoop" nun auch funktioniert.
Nur leider ist nun das Problem das mein n immer wieder mit number ueberschrieben wird und daher logischerweise jedes mal das selbe Ergebnis rauskommt.
 
Zuletzt bearbeitet:
ein neues Collatz-Objekt zurückzugeben klingt schon richtig im Sinne unveränderlicher Objekte, dort kann man dann ja die neue Number abfragen

was dich an isInLoop() zögern läßt ist nicht verständlich,
für das alte Collatz-Objekt arbeitet die Methode nach dem next()-Aufruf wie zuvor, das ist auch richtig so,
für das neue Collatz-Objekt wird selbstverständlich das neue n, das dann dortige number angeschaut,
arbeitet also wie nach dem next()-Aufruf in der alten Klasse, das ist doch auch gut

das scheint mir also ohne noch nötige Veränderung genausogut wie vorher zu funktionieren

-------

man könnte überlegen, die Funktionalität dieser Methode grundsätzlich aufzubohren,

sie erkennt nur 1, 2, 4, wenn eine solche Zahl einmal da war, die Methode vielleicht gar ausgeführt wurde und true zurückgegeben hat,
und auf die alte oder neue Weise zu einer anderen Zahl in der Folge gewechselt wird,
dann gibt die Methode wieder nur false zurück, merkt sich nicht dass nun dauerhaft in einer Schleife vorhanden

dafür könnte man, wenn man will, einen boolean einfügen, in der alten Klasse schnell gemacht,
bei dem neuen unveränderlichen Ansatz müsste man darauf achten,
1) diese Eigenschaft sofort im Konstruktor zu berechnen, darf sich nicht später verändern,
wobei man darüber streiten kann ob nicht Berechnung erst vor erstmaliger Rückgabe ausreicht,
hängt ja nur von unveränderlichen Daten ab
2) wichtig ist noch, dass der boolean dann, falls einmal true, an weitere neue next-Objekte übergeben wird,
denn die könnten mit anderen Zahlen als 1, 2, 4 ja nicht mehr selber wissen ob schon eine Schleife festgestellt wurde

wie gesagt nur falls man insgesamt will, dass diese Information erhalten bleibt,
falls die erste gepostete Klasse vorgegeben war, dann dort nicht vorhanden und anscheinend nicht nötig
 
Ich verstehe leider immer noch nicht ganz, warscheinlich steh ich richtig aufm Schlauch 🙁.

Ich versuche durch

Java:
public boolean isInLoop()
	{
		return  number.next() == 1 || number.next() == 2 || number.next() == 4;
	}

das neue n mit den verschiedenen Zahlen zu vergleichen, doch bekomme stets die Fehlermeldung

mein Collatz Next sieht inzwischen wieder so aus

Java:
public Collatz next()
	{
		int n = number;
		if(n % 2 == 0)
			n /= 2;
		else
			n = 3 * n + 1;
		Collatz result = new Collatz(n);
		return result;
	
	}

Cannot invoke next() on the primitive type int Collatz.java /Collatz/src line 35 Java Problem

Vllt. stelle ich mich auch einfach nur etwas bloed an. ^^
 
next() ist eine Methode von Collatz, kann also nicht an number aufgerufen werden, höchstens an this, am eigenen Objekt,
in der Hinsicht ist bloed wahrlich eine richtige Bezeichnung, wenn man das sagen darf 😉 ,

noch grundsätzlicher ist aber die Frage, warum du überhaupt irgendwas mit next() in dieser Methode versucht?
steht in dessen Beschreibung dass sie die nächste Zahl in der Folge untersuchen soll?
das hat sie doch vorher auch nicht gemacht, isInLoop() ist unverändert eine korrekte Methode
oder was genau stört dich am Verhalten von isInLoop(), wenn du die Methode NICHT kaputt machst sondern wie vorher beläßt?

wie gesagt hat das von next() erzeugte neue Collatz-Objekt eine neue number,
dort liefert der isInLoop() vielleicht ein anderes Ergebnis als im alten Collatz-Objekt,
das ist alles gut so, ohne dass du auch nur eine Zeile programmieren musst
 
Nur überflogen, aber... warum sollte an isInLoop überhaupt was geändert werden? Auch die Immutable klasse hat doch das field "number"?!
 
[c]next[/c] lässt sich auch ganz ohne veränderliche Variablen schreiben:
Java:
    public Collatz next() {
        return new Collatz( number % 2 == 0 ? number / 2 : 3 * number + 1);
    }

Allerdings musst du mit dem Ergebnis auch etwas tun:

Java:
    public static void main(final String... args) {
        Collatz collatz = new Collatz(Integer.parseInt(args[0]));
        while(!collatz.isInLoop())
        {
            collatz = collatz.next(); 
            System.out.println(collatz.getNumber());
        }
    }

Kaum macht man es richtig, geht's...
 
Interessanterweise lässt sich die "unveränderliche" Version auch fast 1:1 nach Haskell übersetzen - nur die while-Schleife des Hauptprogramms muss etwas umformuliert werden.

Code:
data Collatz = Collatz { getNumber :: Int }

isInLoop (Collatz n) = n `elem` [1,2,4]

next (Collatz n) = Collatz $ if even n then n `div` 2 else 3*n+1 

main = print $ map getNumber $ takeWhile (not.isInLoop) $ iterate next (Collatz 27)
 
Wow, im Prinzip hing es bei mir nur an diesem

Java:
            collatz = collatz.next();

in der Main Methode. Danach hatte ich viel zu kompliziert gedacht.


Vielen vielen Dank 🙂
 

Zurück
Oben