126 lines
5.3 KiB
Python
126 lines
5.3 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
|
|||
|
|
# erzeuge_laufzeit_aufbau.py
|
|||
|
|
"""
|
|||
|
|
Erzeugt das Laufzeit-Diagramm zum Oekosystem-Kapitel:
|
|||
|
|
|
|||
|
|
bilder_04/kap_oekosystem_laufzeit.svg
|
|||
|
|
|
|||
|
|
Gestapelte Balken: Wie viel Zeit geht in den AUFBAU des Modells (Python) und
|
|||
|
|
wie viel ins LOESEN (C++)? Verglichen werden Variante A (ein Add() je
|
|||
|
|
Nebenbedingung) und Variante C (vektorisiert ueber NumPy) bei drei
|
|||
|
|
Problemgroessen.
|
|||
|
|
|
|||
|
|
WARUM HIER NICHT GEMESSEN WIRD: Die Zeiten stehen bereits als abgedruckte
|
|||
|
|
Ausgabe im Kapitel. Ein Neumessen auf einer anderen Maschine ergaebe andere
|
|||
|
|
Werte - das Bild widerspraeche dann der Tabelle unmittelbar daneben. Die
|
|||
|
|
Konstanten unten sind aus genau dieser Ausgabe uebernommen; pruefe_anteile()
|
|||
|
|
rechnet die Prozentspalte grob nach und schlaegt an, wenn eine Abweichung
|
|||
|
|
groesser ist als die Rundung der abgedruckten Zeiten erklaeren kann. So ist das
|
|||
|
|
Uebertragen abgesichert, ohne die Messung zu wiederholen.
|
|||
|
|
|
|||
|
|
Aufruf (aus dem Repository-Wurzelverzeichnis):
|
|||
|
|
python3 bilder_04/erzeuge_laufzeit_aufbau.py
|
|||
|
|
|
|||
|
|
Benoetigt: numpy, matplotlib
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
import os
|
|||
|
|
import sys
|
|||
|
|
|
|||
|
|
import numpy as np
|
|||
|
|
|
|||
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|||
|
|
from stil_04 import FARBEN, neue_figur, speichere # noqa: E402
|
|||
|
|
|
|||
|
|
# (Groesse, Variablen, Aufbau A, Loesen A, Anteil A, Aufbau C, Loesen C,
|
|||
|
|
# Anteil C) - wortgleich aus der abgedruckten Ausgabe des Kapitels.
|
|||
|
|
MESSUNG = [
|
|||
|
|
("40 × 40", 1_600, 0.031, 0.005, 87, 0.001, 0.007, 14),
|
|||
|
|
("120 × 120", 14_400, 0.287, 0.070, 80, 0.001, 0.047, 3),
|
|||
|
|
("250 × 250", 62_500, 1.284, 0.569, 69, 0.003, 0.205, 1),
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
|
|||
|
|
# Wie weit die aus den gerundeten Zeiten nachgerechnete Prozentzahl von der
|
|||
|
|
# abgedruckten abweichen darf. Die Zeiten stehen mit drei Nachkommastellen im
|
|||
|
|
# Buch, die Prozentspalte wurde aber aus den UNGERUNDETEN Werten berechnet:
|
|||
|
|
# 0,001s / 0,008s ergibt nachgerechnet 12 %, abgedruckt sind 14 %. Das ist
|
|||
|
|
# kein Fehler, sondern die Folge der Rundung - bei einer Aufbauzeit von einer
|
|||
|
|
# Millisekunde schlaegt schon die vierte Stelle durch. Die Schranke faengt
|
|||
|
|
# trotzdem einen echten Uebertragungsfehler ab.
|
|||
|
|
TOLERANZ_PROZENTPUNKTE = 4
|
|||
|
|
|
|||
|
|
|
|||
|
|
def pruefe_anteile() -> None:
|
|||
|
|
"""Plausibilitaetspruefung der uebertragenen Prozentspalte."""
|
|||
|
|
for name, _var, auf_a, los_a, pro_a, auf_c, los_c, pro_c in MESSUNG:
|
|||
|
|
for auf, los, pro, variante in ((auf_a, los_a, pro_a, "A"),
|
|||
|
|
(auf_c, los_c, pro_c, "C")):
|
|||
|
|
gerechnet = round(auf / (auf + los) * 100)
|
|||
|
|
if abs(gerechnet - pro) > TOLERANZ_PROZENTPUNKTE:
|
|||
|
|
raise SystemExit(
|
|||
|
|
f"Laufzeit-Diagramm: {name}, Variante {variante}: Aus "
|
|||
|
|
f"{auf}s Aufbau und {los}s Loesen folgen {gerechnet} % "
|
|||
|
|
f"Aufbauanteil, die Tabelle nennt {pro} %. Das ist mehr "
|
|||
|
|
f"als Rundung erklaert - Uebertragungsfehler?")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def zeichne() -> None:
|
|||
|
|
figur, achse = neue_figur(breite=8.0, hoehe=4.4)
|
|||
|
|
|
|||
|
|
# Zwei Balken je Groesse: oben Variante A, darunter Variante C.
|
|||
|
|
beschriftung, hoehen = [], []
|
|||
|
|
aufbau, loesen = [], []
|
|||
|
|
# Gezeichnet wird die ABGEDRUCKTE Prozentzahl - so zeigt das Bild genau
|
|||
|
|
# das, was in der Tabelle daneben steht.
|
|||
|
|
for name, variablen, _aa, _la, pro_a, _ac, _lc, pro_c in MESSUNG:
|
|||
|
|
for variante, anteil in (("A Schleife", pro_a),
|
|||
|
|
("C vektorisiert", pro_c)):
|
|||
|
|
beschriftung.append(f"{name} {variante}")
|
|||
|
|
aufbau.append(float(anteil))
|
|||
|
|
loesen.append(100.0 - anteil)
|
|||
|
|
hoehen.append(variablen)
|
|||
|
|
|
|||
|
|
y = np.arange(len(beschriftung))[::-1].astype(float)
|
|||
|
|
# Luecke zwischen den Groessengruppen
|
|||
|
|
y = y + np.repeat(np.arange(len(MESSUNG))[::-1], 2) * 0.6
|
|||
|
|
|
|||
|
|
achse.barh(y, aufbau, height=0.62, color=FARBEN["fehler"],
|
|||
|
|
label="Aufbau in Python", zorder=3)
|
|||
|
|
achse.barh(y, loesen, height=0.62, left=aufbau, color=FARBEN["haupt"],
|
|||
|
|
label="Lösen in C++", zorder=3)
|
|||
|
|
|
|||
|
|
for stelle, (anteil, name) in enumerate(zip(aufbau, beschriftung)):
|
|||
|
|
# Bei 1 % und 3 % ist der Balken schmaler als die Beschriftung - dann
|
|||
|
|
# steht sie rechts daneben, in der Farbe des Balkens.
|
|||
|
|
if anteil >= 10:
|
|||
|
|
achse.text(anteil / 2, y[stelle], f"{round(anteil)} %",
|
|||
|
|
ha="center", va="center", fontsize=8.5, color="white",
|
|||
|
|
fontweight="bold", zorder=4)
|
|||
|
|
else:
|
|||
|
|
achse.text(anteil + 1.5, y[stelle], f"{round(anteil)} %",
|
|||
|
|
ha="left", va="center", fontsize=8.5,
|
|||
|
|
color=FARBEN["fehler"], fontweight="bold", zorder=4)
|
|||
|
|
achse.text(101, y[stelle], name, va="center", fontsize=8.5,
|
|||
|
|
color=FARBEN["text"])
|
|||
|
|
|
|||
|
|
achse.set_yticks([])
|
|||
|
|
achse.set_xlim(0, 100)
|
|||
|
|
achse.set_xlabel("Anteil an der Gesamtzeit in Prozent")
|
|||
|
|
achse.set_title("Wo die Zeit wirklich hingeht — dieselbe Aufgabe, zwei "
|
|||
|
|
"Arten sie aufzuschreiben", fontsize=10.5,
|
|||
|
|
color=FARBEN["text"])
|
|||
|
|
achse.grid(axis="y", visible=False)
|
|||
|
|
achse.legend(fontsize=9, loc="lower center", bbox_to_anchor=(0.5, -0.28),
|
|||
|
|
ncol=2, frameon=False)
|
|||
|
|
|
|||
|
|
speichere(figur, "kap_oekosystem_laufzeit")
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
pruefe_anteile()
|
|||
|
|
print("Prozentspalte stimmt mit den abgedruckten Zeiten überein.")
|
|||
|
|
zeichne()
|