Kiste
EN

Taschenrechner

Grundrechenarten, Prozent, Vorzeichen, ein Verlauf der letzten Rechnungen und volle Tastatur-Bedienung. Und er rechnet exakt: 0,1 + 0,2 ergibt hier wirklich 0,3.

Taschenrechner mit Anzeige, Tastenfeld und Verlauf

Kostenlos selber bauen

Der Taschenrechner ist quelloffen — und er besteht aus einer einzigen Datei. Lade den Quelltext, öffne ihn in der Kiste-IDE (oder bau ihn auf der Kommandozeile mit kiste build taschenrechner.ki) — es ist derselbe Code, aus dem das Programm oben entsteht.

Du willst ihn Schritt für Schritt selbst bauen? Das Tutorial dazu führt dich in fünf Etappen durch — schon nach der zweiten rechnet dein Programm.

So gebaut

Ein Taschenrechner klingt nach einer Fingerübung, ist aber ein gutes Lehrstück: ein wenig Zustand, ein Raster voller Knöpfe, eine selbstgezeichnete Anzeige — und eine Entscheidung über Zahlen, die viele Sprachen falsch treffen.

1 · Warum 0,1 + 0,2 hier wirklich 0,3 ergibt

In den meisten Programmiersprachen ergibt 0.1 + 0.2 nicht 0,3, sondern 0,30000000000000004. Das liegt an Gleitkommazahlen, die im Binärsystem rechnen und Zehntel gar nicht exakt darstellen können. Kiste hat dafür einen eigenen Zahlentyp: dezimal rechnet exakt in Dezimalstellen — genau richtig für Geld und für Rechner.

// Gerechnet wird mit "dezimal" — exakt, nicht mit Gleitkomma.
nimm gespeichert = 0.0            // eine Dezimalzahl

funktion anwenden() {
    nimm jetzt = als_dezimal(anzeige)
    wenn operator == "+" {
        gespeichert = gespeichert + jetzt
    }
}

2 · Teilen durch null, ohne Absturz

Kiste wirft bei einer Teilung durch null einen Fehler — richtig so, denn stillschweigend „unendlich" zurückzugeben verschleiert nur Programmierfehler. Ein Taschenrechner darf deswegen aber nicht abstürzen. Also fragen wir vorher.

// Teilen durch null wird abgefangen, bevor es passiert —
// das Programm zeigt "Nicht definiert" statt abzustuerzen.
wenn operator == "÷" {
    wenn jetzt == 0 {
        fehler = wahr
    } sonst {
        gespeichert = gespeichert / jetzt
    }
}

3 · Eine Taste ist drei Zeilen

Jede Taste ist ein echter Knopf mit eigener Farbe. Weil sich das zwanzigmal wiederholt, wandert es in eine kleine Funktion, die den fertigen Knopf zurückgibt.

// Eine Taste bauen: Knopf anlegen, einfaerben, fertig.
funktion taste(beschriftung, farbe) {
    nimm k = gui.knopf_neu(beschriftung)
    gui.setze_knopf_farbe(k, farbe)
    gib k
}

nimm k7 = taste("7", ZIFFER)
gui.bei_klick(k7, funktion(k) { tippe("7") })

4 · Das Raster ordnet von selbst

Kein Ausrechnen von Positionen: gui.raster bekommt die Spaltenzahl und die Tasten in Lesereihenfolge — den Rest macht es allein, auch beim Vergrößern des Fensters.

// Zwanzig Tasten, vier Spalten — das Raster ordnet sie selbst.
nimm gitter = gui.raster(4, [
    k_c,     k_vz, k_proz,  k_div,
    k7,      k8,   k9,      k_mal,
    k4,      k5,   k6,      k_minus,
    k1,      k2,   k3,      k_plus,
    k_rueck, k0,   k_komma, k_gleich
])

5 · Die Anzeige ist gezeichnet, nicht gesetzt

Für die große Zahl mit der kleinen Nebenzeile darüber reicht kein normales Textfeld. Also ist die Anzeige eine Zeichenfläche, auf die das Programm selbst malt — Hintergrund, Nebenzeile, Ergebnis. Rechtsbündig wird sie, indem die Textbreite vom rechten Rand abgezogen wird.

// Die Anzeige ist eine kleine Zeichenflaeche. Rechtsbuendig heisst:
// die geschaetzte Textbreite vom rechten Rand abziehen.
funktion zeichne_anzeige() {
    gui.leeren(feld)
    gui.rechteck(feld, 0, 0, A_BREITE, A_HOEHE, FELD)

    nimm gross = hübsch(anzeige)
    nimm breite = länge(gross) * 19
    gui.text_an(feld, A_BREITE - 16 - breite, 44, gross, HELL, 34)
}

6 · Tausender trennen

„8680" liest sich schlecht, „8 680" gut. Die Regel ist einfach: nach jeder dritten Stelle von rechts ein Leerzeichen — also Zeichen für Zeichen durchgehen und zählen, wie viele noch folgen.

// "1240" → "1 240": nach jeder dritten Stelle von rechts
// kommt ein schmales Leerzeichen.
funktion gruppiert(t) {
    nimm aus = ""
    nimm n = länge(t)
    nimm i = 0
    solange i < n {
        aus = aus + text.zeichen_bei(t, i)
        nimm rest = n - i - 1
        wenn rest > 0 und rest % 3 == 0 {
            aus = aus + " "
        }
        i = i + 1
    }
    gib aus
}

7 · Maus und Tastatur, derselbe Code

Die Tastatur ruft genau dieselben Funktionen auf wie die Knöpfe. Deshalb gibt es die Bedienlogik nur einmal — tippe, gleich, alles_löschen — und beide Wege können gar nicht auseinanderlaufen.

// Maus UND Tastatur: derselbe Code, egal ob geklickt oder getippt.
gui.bei_taste(fenster, funktion(f) {
    nimm t = gui.letzte_taste(f)
    wenn text.enthält("0123456789", t) {
        tippe(t)
    }
    wenn t == "=" oder t == "eingabe" {
        gleich()
    }
    wenn t == "escape" {
        alles_löschen()
    }
})

Das ist der ganze Rechner: eine Datei, keine Zusatzdateien, kein Framework. Bau ihn nach, häng eine Wurzeltaste dran oder lass ihn sich den letzten Wert merken — der Quelltext liegt oben zum Mitnehmen.