MINT lernen

Textaufgaben: Datentypen und printf

Miras Wetterstation meldet einen verdächtig glatten Mittelwert, und die Mensa-Kasse der Schülerfirma soll auf den Cent genau abrechnen.

Dein Fortschritt:
0 / 0 Aufgaben
1

Die Tagesanzeige der Wetterstation

AFB I–II

Die Wetter-AG betreibt auf dem Schuldach eine kleine Wetterstation. Mira schreibt ein C-Programm, das auf dem Display im Foyer eine Tageszusammenfassung zeigt. Heute wurden vier Temperaturen gemessen: 19 °C, 22 °C, 24 °C und 18 °C. Zum Testen trägt Mira die Werte fest im Programm ein.

C · wetter.c
#include <stdio.h>

int main(void) {
    int summe = 83;          // vier Messwerte in °C: 19 + 22 + 24 + 18
    int anzahl = 4;
    double mittel = summe / anzahl;
    char einheit = 'C';
    int regen = 35;          // Regenwahrscheinlichkeit in Prozent

    printf("Messungen:%5d\n", anzahl);
    printf("Mittel:%8.2f %c\n", mittel, einheit);
    printf("Regen:\t%d%%\n", regen);
    return 0;
}

Beim ersten Test wundert sich Mira: Der Mittelwert sollte doch 20,75 °C sein.

  1. Ermitteln Sie die genaue Ausgabe des Programms. Kennzeichnen Sie jedes Leerzeichen mit dem Zeichen ␣ und den Tabulator mit →.
  2. Begründen Sie, warum beim Mittelwert nicht 20.75 erscheint, obwohl mittel als double deklariert ist.
  3. Nennen Sie zwei verschiedene Änderungen der Zeile double mittel = summe / anzahl;, nach denen 20.75 ausgegeben wird.

Hinweise

Hinweis zu Aufgabe a)
Gehen Sie die drei printf-Aufrufe einzeln durch. %5d reserviert 5 Zeichen, %8.2f reserviert 8 Zeichen inklusive Punkt und Nachkommastellen; der Wert steht rechtsbündig. Was macht %%?
Hinweis zu Aufgabe b)
Welchen Typ haben summe und anzahl? In welcher Reihenfolge passieren Rechnen und Speichern in mittel?
Hinweis zu Aufgabe c)
Es genügt, wenn einer der beiden Operanden ein Kommazahl-Typ ist. Vorsicht mit Klammern: Wann wird umgewandelt?

Erwartungshorizont

Erwartungshorizont zu Aufgabe a)
Ausgabe (␣ = Leerzeichen, → = Tabulator)
Messungen:␣␣␣␣4
Mittel:␣␣␣20.00␣C
Regen:→35%
  • %5d: Die 4 ist eine Stelle breit, also 4 Leerzeichen davor.
  • %8.2f: 20.00 ist 5 Zeichen breit, also 3 Leerzeichen davor; danach folgen das Leerzeichen aus dem Formatstring und das Zeichen C (%c).
  • \t springt zur nächsten Tabulatorposition (im Terminal meist Spalte 9), %% gibt ein einzelnes Prozentzeichen aus.
Erwartungshorizont zu Aufgabe b)

summe und anzahl sind beide int. Deshalb rechnet C 83 / 4 als Ganzzahldivision: Das Ergebnis ist 20, der Rest 3 (83 % 4) fällt weg. Erst danach wird die fertige 20 in die double-Variable gespeichert und zu 20.0 umgewandelt. Der Typ der Zielvariable ändert an der Rechnung nichts mehr.

Erwartungshorizont zu Aufgabe c)
  • double mittel = (double) summe / anzahl; — Typumwandlung (cast) vor der Division
  • double mittel = summe / 4.0; — Kommazahl-Literal als Teiler
  • alternativ: summe gleich als double summe = 83; deklarieren

Nicht richtig ist (double) (summe / anzahl): Hier wird erst ganzzahlig geteilt und dann 20 umgewandelt — Ausgabe weiterhin 20.00. Mit gcc geprüft: Die beiden ersten Varianten liefern 20.75.

2

Der Bon der Mensa-Kasse

AFB II–III

Die Schülerfirma „Mampf & Co.“ programmiert eine einfache Kasse für die Mensa. Jonas und Aylin haben festgelegt: Alle Preise werden in Cent als int gespeichert, erst bei der Ausgabe wird in Euro umgerechnet. Schülerinnen und Schüler erhalten 10 % Rabatt auf den Gesamtbetrag; dabei wird auf ganze Cent abgeschnitten.

Die Preise: Nudelauflauf 3,95 €, Apfelschorle 1,50 €, Obstsalat 1,90 €. Für den ersten Test soll das Programm den Bon für eine Bestellung ausgeben, die genau so aussieht:

Vorlage · Kassenbon
MENSA-KASSE     Bon 0417
1 x Nudelauflauf     3.95 EUR
2 x Apfelschorle     3.00 EUR
1 x Obstsalat        1.90 EUR
Summe                8.85 EUR
Rabatt 10%          -0.88 EUR
Zu zahlen            7.97 EUR

Für den Rabatt haben die beiden zwei Zeilen im Gespräch: Jonas schreibt int rabatt = summe * 10 / 100;, Aylin int rabatt = summe / 100 * 10;.

Ein Lehrer rät: „Nehmt doch einfach double und rechnet gleich in Euro, das ist viel natürlicher.“ Aylin testet dazu printf("%.17f\n", 0.1 + 0.2); und erhält 0.30000000000000004.

  1. Implementieren Sie ein vollständiges C-Programm, das mit den Cent-Beträgen rechnet und den Bon genau wie in der Vorlage ausgibt (gleiche Spalten, gleiche Leerzeichen).
  2. Untersuchen Sie die beiden Rabatt-Zeilen von Jonas und Aylin für die Summe dieser Bestellung und für den allgemeinen Fall.
  3. Bewerten Sie die Entscheidung der Schülerfirma, Geldbeträge in Cent als int statt in Euro als double zu speichern.

Hinweise

Hinweis zu Aufgabe a)
Legen Sie für jeden Preis eine int-Variable in Cent an. Für die Euro-Ausgabe teilen Sie durch 100.0 (warum nicht durch 100?). Zählen Sie in der Vorlage, wie breit die Zahlenspalte ist, und wählen Sie die Feldbreite in %…f passend. Das Prozentzeichen im Formatstring braucht eine Sonderbehandlung.
Hinweis zu Aufgabe b)
Rechnen Sie beide Zeilen mit der Summe von Hand aus — Schritt für Schritt von links nach rechts und jeweils mit Ganzzahldivision. Für den allgemeinen Fall: Wann geht bei Aylins Reihenfolge etwas verloren?
Hinweis zu Aufgabe c)
Mögliche Kriterien: Genauigkeit (was zeigt Aylins Test?), Summieren vieler Beträge, Rundung beim Rabatt, Aufwand bei der Ausgabe, Lesbarkeit des Codes.

Erwartungshorizont

Erwartungshorizont zu Aufgabe a)
C · kasse.c (mit gcc -Wall getestet)
#include <stdio.h>

int main(void) {
    int auflauf = 395;       // Preise in Cent
    int schorle = 150;
    int obstsalat = 190;

    int summe = auflauf + 2 * schorle + obstsalat;
    int rabatt = summe * 10 / 100;          // 10 % in ganzen Cent
    int zahlen = summe - rabatt;

    printf("MENSA-KASSE     Bon 0417\n");
    printf("1 x Nudelauflauf %8.2f EUR\n", auflauf / 100.0);
    printf("2 x Apfelschorle %8.2f EUR\n", 2 * schorle / 100.0);
    printf("1 x Obstsalat    %8.2f EUR\n", obstsalat / 100.0);
    printf("Summe            %8.2f EUR\n", summe / 100.0);
    printf("Rabatt 10%%       %8.2f EUR\n", -rabatt / 100.0);
    printf("Zu zahlen        %8.2f EUR\n", zahlen / 100.0);
    return 0;
}

Die Ausgabe stimmt Zeichen für Zeichen mit der Vorlage überein. Wichtig: / 100.0 statt / 100 (sonst Ganzzahldivision, z. B. 395 / 100 = 3), %8.2f für die 8 Zeichen breite Zahlenspalte, %% für das Prozentzeichen. Andere Aufteilungen (z. B. eine Variable je Zeile) sind gleichwertig, wenn gerechnet statt abgeschrieben wird.

Erwartungshorizont zu Aufgabe b)

Summe: 395 + 2 · 150 + 190 = 885 Cent.

  • Jonas: 885 * 10 / 100 = 8850 / 100 = 88 Cent (exakt wären 88,5 Cent; abgeschnitten wie vereinbart).
  • Aylin: 885 / 100 * 10 = 8 * 10 = 80 Cent — schon die erste Division wirft 85 Cent weg.

Allgemein: Bei Jonas geht erst im letzten Schritt höchstens ein Rest unter 1 Cent verloren, bei Aylin werden zuerst alle Cent unter einem vollen Euro abgeschnitten, sodass bis zu 9,9 Cent Rabatt fehlen können. Richtig ist Jonas’ Zeile; Faustregel: bei int erst multiplizieren, dann teilen. (Mit gcc geprüft: 88 bzw. 80.)

Erwartungshorizont zu Aufgabe c)

Für int in Cent spricht: Ganze Zahlen werden exakt gespeichert, Summen aus vielen Buchungen stimmen immer auf den Cent. Aylins Test zeigt, dass double schon 0,10 € und 0,20 € nicht exakt darstellen kann; bei vielen Additionen können sich solche Fehler bemerkbar machen, und Vergleiche wie „ist die Kasse ausgeglichen?“ werden unzuverlässig. Die Rundungsregel beim Rabatt lässt sich mit Ganzzahlen genau festlegen.

Dagegen spricht: Bei jeder Ausgabe muss umgerechnet werden (/ 100.0), und man muss die Ganzzahldivision im Blick behalten (siehe b). Beträge in Cent sind im Quelltext etwas schlechter lesbar.

Urteil: Für eine Kasse ist die Entscheidung gut begründet, weil Geldbeträge exakt stimmen müssen; der Mehraufwand ist gering. Vollständig ist die Bewertung mit mindestens zwei Kriterien, dem Bezug auf Aylins Testausgabe und einem klaren Urteil.