MINT lernen

Übung — AFB II (Zusammenhänge herstellen)

Zehn mehrschrittige Aufgaben: von Zeiteinheiten im Compiler-Modell über SQL-Abfragen und PHP-Ausgaben bis zu Rust-Besitz und Laufzeitfaktoren.

Dein Fortschritt:
0 / 0 Aufgaben
2

Aufgabenblock — AFB II

Zehn Aufgaben, in denen du mehrere Schritte verbinden musst: Zeiteinheiten im Compiler-Modell zählen, Typumwandlungen in zwei Sprachen verfolgen, SQL-Abfragen auswerten, PHP-Ausgaben vorhersagen, Rust-Besitz prüfen und Laufzeiten vergleichen. Jede Aufgabe hat zwei Teile a) und b). Wenn du nicht weiterkommst, helfen dir zwei gestufte Tipps — erst der Ansatz, dann der Rechenweg.

A1
Compiler oder Interpreter — Zeiteinheiten im Modell
AFB II

Ein Programm hat 5 Anweisungen: 3 stehen außerhalb einer Schleife und laufen je einmal, 2 stehen in einer Schleife mit 4 Durchläufen. Im Modell dauert das Übersetzen einer Anweisung 2 Zeiteinheiten (ZE), das Ausführen 1 ZE. Der Compiler übersetzt jede Anweisung genau einmal vor dem ersten Start. Der Interpreter übersetzt jede Anweisung bei jeder Ausführung neu.

a) Wie viele ZE braucht der Interpreter für einen Programmlauf? b) Das kompilierte Programm wird fünfmal gestartet, ohne neu zu übersetzen. Wie viele ZE braucht der Compiler-Weg insgesamt (Übersetzen plus fünf Läufe)?

ZE
ZE
Ansatz: Zähle zuerst, wie viele Anweisungen bei einem Lauf ausgeführt werden. Beim Interpreter kostet jede Ausführung Übersetzen + Ausführen. Beim Compiler fällt das Übersetzen nur einmal pro Anweisung an, das Ausführen bei jedem Lauf.
Rechenweg: Ausführungen pro Lauf: 3 + 2 · 4 = 11. Interpreter: 11 · (2 + 1) ZE. Compiler: 5 Anweisungen · 2 ZE zum Übersetzen, dann 5 Läufe · 11 ZE.
Vollständige Lösung

a) Bei einem Lauf werden 3 + 2 · 4 = 11 Anweisungen ausgeführt. Der Interpreter übersetzt jede davon neu: 11 · (2 + 1) = 33 ZE.

b) Der Compiler übersetzt die 5 Anweisungen einmal: 5 · 2 = 10 ZE. Jeder Lauf kostet nur noch das Ausführen: 11 ZE. Bei fünf Starts: 10 + 5 · 11 = 65 ZE. Der Interpreter bräuchte für fünf Läufe 5 · 33 = 165 ZE.

Hinweis: Das Modell zeigt die Grundidee. Echte Interpreter und JIT-Compiler merken sich schon übersetzte Teile und sind deshalb schneller, als das Modell vermuten lässt.

A2
Gleicher Code, zwei Sprachen — Typumwandlung verfolgen
AFB II

Derselbe Algorithmus steht einmal in JavaScript und einmal in PHP:

JavaScript
let a = "4";
let b = 2;
let c = a * b + a;
console.log(c - 4);
PHP
<?php
$a = "4";
$b = 2;
$c = $a * $b + $a;
echo $c - 4;
?>

a) Welche Zahl gibt JavaScript aus? b) Welche Zahl gibt PHP aus?

Ansatz: Rechne Zeile für Zeile und schreibe nach jedem Schritt auf, ob der Wert eine Zahl oder ein Text ist. JavaScript: * und - machen Zahlen, + mit einem Text verkettet. PHP: + rechnet immer.
Rechenweg: JavaScript: a * b = 8 (Zahl), 8 + "4" = "84" (Text), "84" - 4 = ? — PHP: $a * $b = 8, 8 + "4" = 12, 12 - 4 = ?
Vollständige Lösung

a) JavaScript: a * b: Das * wandelt "4" in 4 um, also 8 (Zahl). 8 + a: Weil a ein Text ist, verkettet + → c ist der Text "84". c - 4: Das - wandelt "84" in die Zahl 84 um → Ausgabe 80.

b) PHP: $a * $b = 8. 8 + "4": In PHP rechnet + immer, also 12. 12 - 4 → Ausgabe 8.

Hinweis: Beide Sprachen sind dynamisch typisiert, wandeln aber verschieden um. In Python ergäbe "4" * 2 sogar "44" (Text wiederholt), und spätestens c - 4 bräche mit einem TypeError ab.

A3
Die Playlist der Schulband
AFB II

Die Schulband speichert ihre Songs in der Tabelle songs (Dauer in Sekunden):

Tabelle songs
titelgenredauer
MorgenrotPop215
LaternenPop184
NachtbusRock243
PapierfliegerPop176
FunkstilleHip-Hop198
SommerregenPop199
EchoRock167
KompassPop231
SQL
SELECT titel, dauer FROM songs
WHERE genre = 'Pop' AND dauer < 200
ORDER BY dauer DESC;

a) Wie viele Zeilen hat die Ergebnistabelle? b) Welche Dauer steht in der ersten Zeile der Ergebnistabelle?

Zeilen
s
Ansatz: Arbeite die Abfrage in der Reihenfolge ab, in der eine Datenbank sie auswertet: erst FROM und WHERE (welche Zeilen bleiben?), dann ORDER BY (wie werden sie sortiert?), zuletzt SELECT (welche Spalten werden gezeigt?).
Rechenweg: Pop-Songs: Morgenrot 215, Laternen 184, Papierflieger 176, Sommerregen 199, Kompass 231. Davon unter 200 s: Laternen, Papierflieger, Sommerregen. Nun absteigend nach Dauer sortieren — DESC heißt: größter Wert zuerst.
Vollständige Lösung

a) genre = 'Pop' trifft auf 5 Songs zu. dauer < 200 schließt Morgenrot (215) und Kompass (231) aus. Es bleiben Laternen (184), Papierflieger (176) und Sommerregen (199): 3 Zeilen.

b) ORDER BY dauer DESC sortiert absteigend: Sommerregen 199, Laternen 184, Papierflieger 176. In der ersten Zeile steht 199.

Hinweis: Funkstille (198 s) ist kürzer als 200 s, aber kein Pop — bei AND müssen beide Bedingungen gelten.

A4
Schach-AG — Turnierauswertung mit SQL
AFB II

Die Schach-AG speichert die Ergebnisse ihres Schulturniers in der Tabelle turnier:

Tabelle turnier
nameklassesiegeremisniederlagen
Aylin9a410
Ben9b221
Carla9b302
Deniz9a131
Emil9b401
Finja9c023
SQL — Abfrage a
SELECT AVG(siege) FROM turnier
WHERE klasse = '9b';
SQL — Abfrage b
SELECT COUNT(*) FROM turnier
WHERE remis >= 2 AND klasse <> '9a';

a) Welchen Wert liefert Abfrage a? b) Welchen Wert liefert Abfrage b?

Siege
Ansatz: Filtere zuerst mit WHERE, dann wende die Funktion an. AVG bildet den Mittelwert einer Spalte, COUNT(*) zählt Zeilen. Das Zeichen <> bedeutet „ungleich“.
Rechenweg: a) Klasse 9b: Ben 2, Carla 3, Emil 4 Siege → (2 + 3 + 4) : 3. b) Mindestens 2 Remis: Ben, Deniz, Finja. Davon nicht aus der 9a: Ben (9b), Finja (9c).
Vollständige Lösung

a) WHERE klasse = '9b' lässt Ben, Carla und Emil übrig. AVG(siege) = (2 + 3 + 4) : 3 = 3.

b) remis >= 2 gilt für Ben (2), Deniz (3) und Finja (2). klasse <> '9a' schließt Deniz aus. Übrig: Ben und Finja → COUNT(*) = 2.

Hinweis: Die Ergebnistabelle einer Abfrage mit AVG oder COUNT ist wieder eine Tabelle — mit nur einer Zeile und einer Spalte.

A5
PHP — was der Browser wirklich bekommt
AFB II

Die Webseite eines Sportvereins zeigt die Trainingszeiten. Auf dem Server liegt dieses PHP-Skript:

PHP
<?php
echo "<h2>Training heute</h2>";
for ($gruppe = 1; $gruppe <= 7; $gruppe += 2) {
    $uhr = 14 + $gruppe;
    echo "<p>Gruppe $gruppe: $uhr Uhr</p>";
}
?>

a) Wie viele <p>-Elemente enthält das HTML, das beim Browser ankommt? b) Welche Uhrzeit (nur die Zahl) steht im letzten <p>-Element?

<p>-Elemente
Uhr
Ansatz: Der Server führt das Skript aus, bevor er antwortet. Jeder Schleifendurchlauf schreibt mit echo genau ein <p>-Element. Notiere die Werte von $gruppe: Start 1, Schrittweite 2, solange $gruppe <= 7.
Rechenweg: $gruppe nimmt die Werte 1, 3, 5, 7 an (9 ist zu groß). Zu jedem Wert: $uhr = 14 + $gruppe.
Vollständige Lösung

a) Die Schleife läuft für $gruppe = 1, 3, 5, 7 — das sind 4 Durchläufe und damit 4 <p>-Elemente. Die Überschrift ist ein <h2>, kein <p>.

b) Letzter Durchlauf: $gruppe = 7, $uhr = 14 + 7 = 21. Im Browser steht „Gruppe 7: 21 Uhr“.

Hinweis: Der Browser erhält nur das fertige HTML. Schaut man sich dort den Seitenquelltext an, findet man keine einzige Zeile PHP — und kein $gruppe.

A6
Rust — wem gehört der String?
AFB II

Dieses Rust-Programm wird fehlerfrei kompiliert:

Rust
fn laenge(s: &String) -> usize {
    s.len()
}

fn main() {
    let a = String::from("Schach");
    let n = laenge(&a);
    let b = a;
    let x = 5;
    let y = x;
    println!("{} {} {}", n, x + y, b);
}

a) Welche Zahl gibt das Programm als Erstes aus (Wert von n)? b) Wie viele der fünf Variablen a, n, b, x, y dürfen in der letzten Zeile noch benutzt werden?

Zeichen
Variablen
Ansatz: Unterscheide drei Fälle: Mit &a wird der String nur geliehen — a bleibt Besitzer. let b = a; verschiebt den String (move) — danach ist a ungültig. Zahlen wie i32 werden einfach kopiert.
Rechenweg: a) laenge(&a) zählt die Zeichen von „Schach“. b) Nach let b = a; ist nur noch b Besitzer. let y = x; kopiert die 5 — x und y sind beide gültig.
Vollständige Lösung

a) Die Funktion laenge leiht sich den String über &a und gibt seine Länge zurück: „Schach“ hat 6 Zeichen. Nach dem Leihen gehört der String weiterhin a.

b) let b = a; verschiebt den Besitz: Ab hier ist a ungültig. n, b, x und y sind gültig — die Zahl 5 wurde bei let y = x; kopiert, nicht verschoben. Also 4 Variablen.

Hinweis: Stünde in der letzten Zeile zusätzlich a, würde der Borrow Checker das Programm schon beim Kompilieren ablehnen („borrow of moved value“).

A7
Go — Schleife mit Bedingung
AFB II

Was gibt dieses Go-Programm aus?

Go
package main

import "fmt"

func main() {
    summe := 0
    for i := 1; i <= 10; i++ {
        if i%3 == 0 {
            summe += i
        }
    }
    fmt.Println(summe, summe/4)
}

a) Welche Zahl wird als Erstes ausgegeben? b) Welche Zahl wird als Zweites ausgegeben?

Ansatz: Die Schleife zählt i von 1 bis 10. i%3 == 0 ist genau für die Vielfachen von 3 wahr. summe ist eine int-Variable — bei / fallen also die Nachkommastellen weg.
Rechenweg: Vielfache von 3 bis 10: 3, 6, 9. summe = 3 + 6 + 9. Danach summe/4 ganzzahlig.
Vollständige Lösung

a) Nur für i = 3, 6 und 9 ist der Rest bei Division durch 3 gleich 0. summe = 3 + 6 + 9 = 18.

b) summe/4 = 18 / 4 = 4,5 — da beide Werte int sind, schneidet Go ab: 4. Ausgabe: 18 4.

Hinweis: Hätte man zusätzlich rest := summe % 4 geschrieben, ohne rest zu benutzen, würde der Go-Compiler das Programm gar nicht erst übersetzen.

A8
Unity — Rakete mit Time.deltaTime
AFB II

In einem Unity-Spiel steuert dieses C#-Skript eine Rakete. Das Spiel läuft gleichmäßig mit 50 Bildern pro Sekunde (fps). Du hältst die Pfeiltaste nach oben genau 4 Sekunden lang gedrückt.

C#
public class Rakete : MonoBehaviour
{
    float tempo = 3f;   // Einheiten pro Sekunde

    void Update()
    {
        if (Input.GetKey(KeyCode.UpArrow))
        {
            transform.Translate(0, tempo * Time.deltaTime, 0);
        }
    }
}

a) Wie oft wird Update() in diesen 4 Sekunden aufgerufen? b) Um wie viele Einheiten bewegt sich die Rakete nach oben?

Einheiten
Ansatz: Update() läuft einmal pro Bild (Frame). Time.deltaTime ist die Zeit seit dem letzten Frame in Sekunden, bei 50 fps also 1/50 s = 0,02 s.
Rechenweg: a) 50 Frames pro Sekunde · 4 s. b) Pro Frame: 3 · 0,02 = 0,06 Einheiten. Das mal Anzahl der Frames — oder direkt: Tempo · Zeit.
Vollständige Lösung

a) Bei 50 fps wird Update() 50-mal pro Sekunde aufgerufen: 50 · 4 = 200 Aufrufe.

b) Pro Aufruf bewegt sich die Rakete um 3 · 0,02 = 0,06 Einheiten, insgesamt 200 · 0,06 = 12 Einheiten. Kürzer: 3 Einheiten pro Sekunde · 4 s = 12 Einheiten.

Hinweis: Genau dafür gibt es Time.deltaTime: Bei 100 fps gäbe es 400 Aufrufe mit je 0,03 Einheiten — der Weg bleibt 12 Einheiten.

A9
Laufzeitfaktor — lohnt sich das Umschreiben?
AFB II

Ein Programm bewertet Schachstellungen. In C braucht es für eine Stellungsliste 0,8 s. Im Modell gilt für die Laufzeit (als Vielfaches der Laufzeit von C): C 1 · Rust 1 · Go, Java, C# 1,5 · JavaScript 2 · PHP 8 · Python 25.

a) Wie lange braucht die Python-Fassung? b) Das Team schreibt die Python-Fassung in Go um. Um wie viele Sekunden ist die Go-Fassung schneller als die Python-Fassung? Schreibe Kommazahlen mit Komma.

s
s
Ansatz: Der Laufzeitfaktor sagt, wie viel länger eine Sprache als C braucht: t(Sprache) = Faktor · t(C). Rechne beide Laufzeiten aus und bilde die Differenz.
Rechenweg: Python: 25 · 0,8 s. Go: 1,5 · 0,8 s = 1,2 s. Ersparnis: Python-Zeit − 1,2 s.
Vollständige Lösung

a) t(Python) = 25 · 0,8 s = 20 s.

b) t(Go) = 1,5 · 0,8 s = 1,2 s. Ersparnis: 20 s − 1,2 s = 18,8 s.

Hinweis: Ob sich das Umschreiben lohnt, hängt nicht nur an der Laufzeit: Läuft das Programm einmal am Tag, sind 20 s egal. Wird es tausendmal am Tag gestartet, sparen 18,8 s pro Lauf über fünf Stunden.

A10
Von Python nach Java — gleiche Idee, anderes Ergebnis
AFB II

Lena übersetzt ein Python-Programm Zeile für Zeile nach Java:

Python
summe = 0
for i in range(1, 6):
    summe = summe + i
print(summe / 2)
Java
int summe = 0;
for (int i = 1; i < 6; i++) {
    summe = summe + i;
}
System.out.println(summe / 2);

a) Welche Zahl gibt das Python-Programm aus? b) Welche Zahl gibt das Java-Programm aus? Schreibe Kommazahlen mit Komma.

Ansatz: Prüfe zuerst, ob beide Schleifen dieselben Werte durchlaufen: range(1, 6) endet vor der 6. Dann kommt es auf das Teilen an: In Python liefert / immer eine Kommazahl, in Java ist int / int ganzzahlig.
Rechenweg: Beide Schleifen addieren 1 + 2 + 3 + 4 + 5 = 15. Python: 15 / 2. Java: 15 / 2 mit zwei int-Werten.
Vollständige Lösung

Beide Schleifen laufen für i = 1, 2, 3, 4, 5, also ist summe in beiden Fällen 15. Die Schleife wurde korrekt übertragen.

a) Python: 15 / 2 = 7,5 (Ausgabe 7.5).

b) Java: summe ist int, 2 auch — Ganzzahldivision: 7.

Hinweis: Das Konzept (Schleife, Summe) lässt sich eins zu eins übertragen, die Feinheiten der neuen Sprache nicht. Richtig wäre in Java summe / 2.0.