diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6f5ab43 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Build output +out/ + +# IDE +.idea/ +*.iml + +# OS +.DS_Store +Thumbs.db \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index ab1f416..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Ignored default folder with query files -/queries/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml -# Editor-based HTTP Client requests -/httpRequests/ diff --git a/.idea/Aufgabenblatt1.iml b/.idea/Aufgabenblatt1.iml deleted file mode 100644 index d6ebd48..0000000 --- a/.idea/Aufgabenblatt1.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/copilot.data.migration.ask2agent.xml b/.idea/copilot.data.migration.ask2agent.xml deleted file mode 100644 index 1f2ea11..0000000 --- a/.idea/copilot.data.migration.ask2agent.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index be7226b..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 5784362..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/aufgabenblatt1/src/solution.md b/aufgabenblatt1/src/solution.md index e140a11..a4bf207 100644 --- a/aufgabenblatt1/src/solution.md +++ b/aufgabenblatt1/src/solution.md @@ -57,3 +57,48 @@ Beide Lösungen verwenden den **gleichen Algorithmus**: Sortieren der Zeichen un - **Null-Check:** Die KI prüft auf `null`-Werte (`if (word0 == null || word1 == null)`). Meine Lösung tut dies nicht, würde also bei `null`-Eingaben eine `NullPointerException` werfen. - **Vergleichsmethode:** Meine Lösung erstellt neue Strings und vergleicht mit `String.equals()`. Die KI vergleicht die char-Arrays direkt mit `Arrays.equals()`, was einen unnötigen String-Allokationsschritt spart. - **Hilfsmethode:** Meine Lösung lagert das Sortieren in eine eigene `sortString()`-Methode aus. Die KI schreibt alles inline in `isAnagram()`. + +# Task 5 + +## Ergebnisse + +| maximum | Anzahl Primzahlen (Algorithmus) | maximum/ln(maximum) (Schätzung) | +|--------:|-------------------------------:|-------------------------------:| +| 100 | 25 | 21,7 | +| 500 | 95 | 80,5 | +| 1.000 | 168 | 144,8 | +| 2.000 | 303 | 263,1 | +| 5.000 | 669 | 587,0 | +| 10.000 | 1.229 | 1.085,7 | +| 20.000 | 2.262 | 2.019,5 | +| 50.000 | 5.133 | 4.621,2 | +| 100.000 | 9.592 | 8.685,9 | +| 200.000 | 17.984 | 16.385,3 | + +## Kurvenvergleich + +![Primzahlen-Kurvenvergleich](./task5.png) + +Die Schätzung durch maximum/ln(maximum) (Primzahlsatz) liegt durchgehend etwas **unter** der tatsächlichen Anzahl der Primzahlen, nähert sich aber mit steigendem maximum proportional an. Beide Kurven zeigen den gleichen sublinearen Wachstumsverlauf. + +## Aufwandsvergleich: Algorithmus vs. Formel + +- **Algorithmus (Zählen durch Sieben):** Für jede Zahl bis `maximum` wird geprüft, ob sie prim ist. Die naive Implementierung hat eine Laufzeitkomplexität von **O(n²)** — für jede der n Zahlen wird im schlimmsten Fall bis n dividiert. Bei maximum = 200.000 sind das potenziell Milliarden von Divisionen. +- **Formel maximum/ln(maximum):** Eine einzige Division und ein Logarithmus — **O(1)**, also konstanter Aufwand, unabhängig von der Größe von maximum. + +**Fazit:** Die Formel ist um Größenordnungen schneller, liefert aber nur eine Schätzung. Der Algorithmus liefert das exakte Ergebnis, braucht dafür aber erheblich mehr Rechenzeit. Für große Werte ist die Formel eine sehr gute Approximation. + +## Vergleich: Eigene Lösung vs. KI-Lösung + +Beide Lösungen liefern **identische Ergebnisse** für alle getesteten Werte. Der zentrale Unterschied liegt in der `isPrime()`-Methode: + +**Gemeinsamkeiten:** +- Gleiche Gesamtstruktur: Klasse mit `maximum`-Feld, `isPrime()`, `countPrimes()`, `printPrimeNumbers()` +- Gleicher Brute-Force-Ansatz: Jede Zahl einzeln auf Primeigenschaft prüfen + +**Unterschiede:** +- **Schleifengrenze:** Meine Lösung prüft Teiler bis `number - 1` (O(n) pro Zahl). Die KI prüft nur bis `√number` (`i * i <= number`), was O(√n) pro Zahl ergibt — mathematisch ausreichend, da ein Teiler > √n immer einen Gegenteiler < √n hat. +- **Gerade Zahlen:** Die KI schließt gerade Zahlen > 2 sofort aus (`if (number % 2 == 0) return false`) und prüft danach nur ungerade Teiler (`i += 2`). Das halbiert die Anzahl der Divisionen nochmals. +- **Sonderfälle:** Die KI behandelt Zahlen < 2 und die Zahl 2 explizit als Sonderfälle. + +**Bewertung:** Die KI-Lösung ist **besser**. Durch die Optimierung der Schleifengrenze auf √n und das Überspringen gerader Zahlen sinkt die Gesamtkomplexität von O(n²) auf ca. O(n√n) — bei maximum = 200.000 ein erheblicher Geschwindigkeitsvorteil. Die Ergebnisse sind trotzdem identisch. diff --git a/aufgabenblatt1/src/task5.png b/aufgabenblatt1/src/task5.png new file mode 100644 index 0000000..2c9aacd Binary files /dev/null and b/aufgabenblatt1/src/task5.png differ diff --git a/aufgabenblatt1/src/task5/PrimeNumberGenerator.java b/aufgabenblatt1/src/task5/PrimeNumberGenerator.java new file mode 100644 index 0000000..e77b020 --- /dev/null +++ b/aufgabenblatt1/src/task5/PrimeNumberGenerator.java @@ -0,0 +1,45 @@ +package task5; + +public class PrimeNumberGenerator { + private int maximum; + + public PrimeNumberGenerator(int maximum) { + this.maximum = maximum; + } + public void printPrimeNumbers() { + for (int i = 2; i <= maximum; i++) { + if (isPrime(i)) { + System.out.println(i); + } + } + } + private boolean isPrime(int number) { + for (int i = 2; i < number; i++) { + if (number % i == 0) { + return false; + } + } + return true; + } + private int countPrimes() { + int count = 0; + for (int i = 2; i <= maximum; i++) { + if (isPrime(i)) { + count++; + } + } + return count; + } + + public static void main(String[] args) { + int[] testValues = {100, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000}; + + System.out.println("maximum,Anzahl Primzahlen (Algorithmus),maximum/ln(maximum) (Schätzung)"); + for (int max : testValues) { + PrimeNumberGenerator generator = new PrimeNumberGenerator(max); + int counted = generator.countPrimes(); + double estimated = max / Math.log(max); + System.out.printf("%d,%d,%.1f%n", max, counted, estimated); + } + } +} diff --git a/aufgabenblatt1/src/task5/PrimeNumberGeneratorAI.java b/aufgabenblatt1/src/task5/PrimeNumberGeneratorAI.java new file mode 100644 index 0000000..1e95b3c --- /dev/null +++ b/aufgabenblatt1/src/task5/PrimeNumberGeneratorAI.java @@ -0,0 +1,51 @@ +package task5; + +public class PrimeNumberGeneratorAI { + private final int maximum; + + public PrimeNumberGeneratorAI(int maximum) { + this.maximum = maximum; + } + + public void printPrimeNumbers() { + for (int i = 2; i <= maximum; i++) { + if (isPrime(i)) { + System.out.println(i); + } + } + } + + private boolean isPrime(int number) { + if (number < 2) return false; + if (number == 2) return true; + if (number % 2 == 0) return false; + for (int i = 3; i * i <= number; i += 2) { + if (number % i == 0) { + return false; + } + } + return true; + } + + public int countPrimes() { + int count = 0; + for (int i = 2; i <= maximum; i++) { + if (isPrime(i)) { + count++; + } + } + return count; + } + + public static void main(String[] args) { + int[] testValues = {100, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000}; + + System.out.println("maximum,Anzahl Primzahlen (Algorithmus),maximum/ln(maximum) (Schätzung)"); + for (int max : testValues) { + PrimeNumberGeneratorAI generator = new PrimeNumberGeneratorAI(max); + int counted = generator.countPrimes(); + double estimated = max / Math.log(max); + System.out.printf("%d,%d,%.1f%n", max, counted, estimated); + } + } +} \ No newline at end of file diff --git a/aufgabenblatt1/src/task5/primzahlen_ergebnisse.csv b/aufgabenblatt1/src/task5/primzahlen_ergebnisse.csv new file mode 100644 index 0000000..57b1d7c --- /dev/null +++ b/aufgabenblatt1/src/task5/primzahlen_ergebnisse.csv @@ -0,0 +1,11 @@ +maximum,Anzahl Primzahlen (Algorithmus),maximum/ln(maximum) (Schätzung) +100,25,21.7 +500,95,80.5 +1000,168,144.8 +2000,303,263.1 +5000,669,587.0 +10000,1229,1085.7 +20000,2262,2019.5 +50000,5133,4621.2 +100000,9592,8685.9 +200000,17984,16385.3 \ No newline at end of file diff --git a/out/production/aufgabenblatt1/solution.md b/out/production/aufgabenblatt1/solution.md deleted file mode 100644 index 10503f8..0000000 --- a/out/production/aufgabenblatt1/solution.md +++ /dev/null @@ -1,6 +0,0 @@ -# Task 1 -![](./task1.png) - -# Task 2 -![](./task2.png) - diff --git a/out/production/aufgabenblatt1/task1.png b/out/production/aufgabenblatt1/task1.png deleted file mode 100644 index 94f2a61..0000000 Binary files a/out/production/aufgabenblatt1/task1.png and /dev/null differ diff --git a/out/production/aufgabenblatt1/task2.png b/out/production/aufgabenblatt1/task2.png deleted file mode 100644 index 65ff825..0000000 Binary files a/out/production/aufgabenblatt1/task2.png and /dev/null differ diff --git a/out/production/aufgabenblatt1/task3/NumberGuesser.class b/out/production/aufgabenblatt1/task3/NumberGuesser.class deleted file mode 100644 index bc3ceb8..0000000 Binary files a/out/production/aufgabenblatt1/task3/NumberGuesser.class and /dev/null differ diff --git a/out/production/aufgabenblatt1/util/ArrayTester.class b/out/production/aufgabenblatt1/util/ArrayTester.class deleted file mode 100644 index 289f88e..0000000 Binary files a/out/production/aufgabenblatt1/util/ArrayTester.class and /dev/null differ diff --git a/out/production/aufgabenblatt1/util/Util.class b/out/production/aufgabenblatt1/util/Util.class deleted file mode 100644 index b4a7c87..0000000 Binary files a/out/production/aufgabenblatt1/util/Util.class and /dev/null differ