Rundungsfehler in ANNO 1602 ?

Wer die Dateien FIGUREN.COD und HAEUSER.COD wie oben beschrieben decodiert hat und sich als Text-Files anschaut, hat Zugriff auf so gut wie alle wichtigen Parameter in ANNO 1602.

Figuren.COD
Figuren.txt
Haeuser.COD
Haeuser.txt

Viele Parameter wie z.B. die Bau- und Unterhaltskosten für Gebäude oder die maximale Bewohnerzahl für Wohnhäuser sind leicht zu finden und stimmen mit der Erfahrung überein. Es gibt aber auch Parameter in den COD-Files, die der Spieler nicht direkt beobachten kann. Um diese Parameter zu verifizieren, muß er sich zuerst ein kleines Experiment ausdenken und aus beobachtbaren Größen die versteckten Parameter berechnen. Stimmen die berechneten Werte und die COD-Parameter weitgehend überein, so kann man davon ausgehen, daß sie wirklich zusammengehören.

In einigen Fällen hat sich gezeigt, daß die COD-Parameter zwar bestimmte Größen in ANNO 1602 repräsentieren, der Spieler aber andere Werte beobachtet, da Programm und Spieler auf unterschiedliche Weise rechnen. Der Spieler wird immer mit REAL-Zahlen (relle Zahlen mit nahezu beliebig vielen Nachkommastellen) arbeiten, während ANNO 1602 meistens INTEGER-Zahlen (ganze Zahlen) benutzt. Steuern und Unterhalt werden in ganzen Talern bezahlt, Nahrung in ganzen Einheiten produziert und von der Bevölkerung konsumiert oder gehandelt. Da in die internen Rechnungen immer wieder REAL-Zahlen eingehen, muß ANNO 1602 die Ergebnisse an vielen Stellen runden. Meist sieht das so aus, daß die Nachkommastellen einer REAL-Zahl einfach abgeschnitten werden, wodurch ein INTEGER als Ergebnis übrig bleibt. Der in Kauf genommene Rundungsfehler liegt zwischen 0 und 1. Ist die ursprüngliche Zahl viel größer als 1, so ist der Fehler klein und kann in der Regel vernachlässigt werden. Ist die Zahl jedoch in der gleichen Größenordnung wie 1, so ist der Fehler groß und führt möglicherweise zu falschen Ergebnissen. Wird ein Wert während des Spiels sehr oft [N mal] berechnet, so kann sich der Rundungsfehler [R] mit der Zeit zu einer merkbaren Größe [N * R] aufsummieren. Das gleiche kann passieren, wenn eine gerundete Zahl anschließend mit einer grßen Zahl [A] multipliziert wird. [Der resultierende Fehler ist dann A * R.]

Ein schönes Beispiel ist die Berechnung der

Einnahmen und Ausgaben in ANNO 1602:

Der Spieler kann in ANNO 1602 ohne Probleme am rechten Bildschirmrand seine momentane Bilanz ablesen. Tätigt er keine Ein- oder Verkäufe, so handelt es sich dabei nur um Steuereinnahmen und Unterhaltskosten, die in bestimmten Zeiträumen auf sein Konto fließen bzw. davon abgezogen werden. Wer genauer hinschaut, wird feststellen, daß ein solcher Bilanzzeitraum bei normaler Spielgeschwindigkeit genau 1 Minute (= 60 Sekunden) dauert. Innerhalb dieser Minute ändert sich das Vermögen des Spielers bei konstanter Bilanz um genau den abgelesenen Betrag (Wenn man von dem im folgenden beschriebenen Rundungsfehler absieht!). Da 1 Minute für ein dynamisches Spiel zu grob ist, wurde der Bilanzzeitraum von den Programmierern weiter in 6 Abschnitte a 10 Sekunden unterteilt. Alle 10 Sekunden wird die Bilanz neu berechnet und ein Sechstel (abgerundet!) an den Spieler überwiesen. Angenommen, die Bilanz beträgt konstant  + 65 $, dann bekommt der Spieler alle 10 Sekunden

INTEGER ( 65/6 ) = INTEGER ( 10.83333... ) = 10 $

gutgeschrieben. In einer Minute macht das aber nur

6 * 10 $ = 60 $

statt der eigentlichen 65 $. Der anfänglich kleine Rundungsfehler von knapp 1 $ pro Rechnung summiert sich hier innerhalb einer Minute zu 5$ auf. Das macht pro Stunde 60 * 5 $ = 300 $ oder pro Tag sogar 24 * 60 * 5 $ = 7200 $. Trotzdem ist der relative Fehler klein :

5 / 65 = ca. 7.69 %

Der berechnete Fehler von 5 $ pro Minute ist übrigens der größtmögliche Fehler, der hier auftreten kann. Da man bei ANNO 1602 innerhalb kurzer Zeit schnell Einnahmen in Tausender-Höhe erreicht, wird der Fehler schon bald verschwindend gering (0.5 % bei 1000 $) und fällt nicht weiter auf. Trotzdem könnte man den Fehler leicht reduzieren, indem man den Kontostand des Spielers intern mit REAL-Zahlen führt und nur bei der Ausgabe gerundet darstellt. In diesem Fall würde zwar mehr Speicher und Rechenzeit verbraucht, der Gesamt-Fehler bliebe aber immer kleiner als 1 $ bei beliebig langer Spielzeit.

Auf die Berechnung der Steuern komme ich weiter unten nocheinmal zurück ... Ein anderes Beispiel für sich aufsummierende Rundungsfehler ist

Die Versorgung der Bevölkerung mit Nahrung und Luxusgütern:

Genauso, wie alle 10 Sekunden die Bilanz neu berechnet und ein Sechstel von ihr verrechnet wird, wird auch die Versorgung der Bevölkerung in ANNO 1602 gehandhabt. Gleich am Anfang von HAEUSER.COD befindet sich z.B. der Eintrag:

;================================================;
;         GRUNDSÄTZLICHE GAMEEINSTELLUNGEN
;================================================;

  Nahrung:    1.3            ; Verbrauch je 100 Einwohner !!

Da 1 Minute in ANNO 1602 der Standard-Zeitraum für alle Angaben ist, bedeutet diese Zeile offensichtlich, daß 100 Einwohner (egal welcher Bevölkerungsklasse !!) pro Minute 1.3 t Nahrung verbrauchen. 1.3 t Nahrung gibt es aber bei ANNO 1602 nicht. Nahrung gibt es nur in ganzen Portionen, d.h. 1 t oder 2 t usw ...

[Diese Geschichte erinnert mich immer mehr an die Anfänge der Quantenmechanik vor 100 Jahren, als die Physiker entdecken mußten, daß z.B. Licht nur in kleinen Paketen (Quanten) der Energie E = h*f  (f steht hier für Frequenz) mit Materie wechselwirkt ...]

Irgendwie muß das Programm bei der Nahrungsverteilung also wieder Runden. In einem kleinen Experiment wurde deshalb eine Stadt mit 1000 Einwohnern beobachtet. 1000 Einwohner sollten pro Minute 13 t Nahrung verbrauchen. Da aber alle 10 Sekunden ein Sechstel der Menge, das sind 

INTEGER (13 / 6) = INTEGER ( 2.1666... ) = 2 t Nahrung,

verteilt wird, werden effektiv nur etwa 6 * 2 t = 12 t Nahrung verbraucht. Bei einer Langzeitmessung über ca. 80 Minuten (= ca. 10 Minuten bei Shift-F8 !) stellte sich sogar heraus, daß (... aus noch ungeklärten Gründen ...) im Durchschnitt nur 1.17 t Nahrung verbraucht wurden. Ich habe daher in einem zweiten Experiment eine Stadt mit 6000 Einwohnern beobachtet, die innerhalb einer Minute ihre Nahrung in einem Rythmus von

12 - 12 - 11 - 12 - 12 - 11

abholten. Aufgrund der schönen Zahlen (Verbrauch von 6 * 13 t pro Minute) hätte man eigentlich keinen Rundungsfehler und eine konstante Rate von 13 t alle 10 Sekunden erwartet. So jedoch werden pro Minute nur 70 t umgesetzt, was wie vorher einem Durchschnitt von

70 / 60 = 1.16666... t Nahrung pro 100 Einwohner

entspricht.
[Dieser Wert stimmt übrigens sehr gut mit dem früher von mir beobachteten Wert von 0.95 t pro 80 Einwohner überein. 0.95 t * 1.25 = 1.1875 t !]

Obwohl also der COD-Parameter einen Verbrauch von 1.3 t Nahrung pro 100 Einwohner nahelegt, werden aus ungeklärten Gründen nur 1,17 t (pro 100 Einwohner) konsumiert. Die Abweichung ist in diesem Fall eindeutig zu Gunsten des Spielers, weshalb sich sicherlich niemand beklagen wird. Man sieht aber an diesem Beispiel sehr gut, daß bestimmte COD-Parameter nicht das sind, was sie auf den ersten Blick scheinen ...

Ein Fall, in dem eindeutig auf Kosten des Spielers gerundet wird, kommt jetzt:

Die Berechnung der Steuern

In der Datei HAEUSER.COD befinden sich neben den Verbrauchswerten auch die Steuersätze der verschiedenen Bevölkerungsklassen. Diese weichen (... wie zu erwarten ... ansonsten würde ich sie ja nicht erwähnen ...) von den beobachteten Werten ab. Die folgende Tabelle faßt alle Werte für jeweils 1.000 Einwohner zusammen. Unter COD steht der aufgrund der gefundenen Parameter erwartete Wert, z.B. für Pioniere mit einem Steuersatz von 1,4 $ pro Einwohner (bei 32% Steuern) 1.000 * 1,4 $ = 1.400 $ ... NR ist eine kleine Nebenrechnung, die ganz nützlich ist, um die Werte leichter zu verstehen ...

Klasse
Steuersatz
COD
beobachtet
NR
Pioniere
1,4
1.400 $
1.312 $
1.312,5 = 7 * 187,5
Siedler
1,6
1.600 $
1.500 $
1.500 = 8 * 187,5
Bürger
2,1
2.100 $
2.062 $
2.062,5 = 11 * 187,5
Kaufleute
2,4
2.400 $
2.250 $
2.250 = 12 * 187,5
Aristokraten
2,6
2.600 $
2.437 $
2.437,5 = 13 * 187,5

Man erhält diese Werte, wenn man den Steuersatz [S] z.B. in folgende Formel einsetzt :

F (S) = INTEGER { 187,5 * INTEGER { (S * 16) / 3 } }

Weshalb ANNO 1602 diese oder eine äquivalente Formel benutzt, weiß ich auch nicht, aber es ist in jedem Fall die korrekte Formel, um aus dem Steuersatz [S] (in HAEUSER.COD) das Steueraufkommen F(S) von genau 1.000 Einwohnern dieser Steuerklasse im Spiel zu berechnen. Um auf diese Formel zu kommen, mußte ich zahlreiche Werte für S ausprobieren ... (... Manipulation der COD-Files ...).

S F(S) - S F(S) - S F(S)
0 0 - 1,0 937 - 1 937
0,1 0 - 1,1 937 - 2 1.875
0,2 187 - 1,2 1.125 - 3 3.000
0,3 187 - 1,3 1.125 - 4 3.937
0,4 375 - 1,4 1.312 - 5 4.875
    - 1,5 1.500 -    
    - 1,6 1.500 - 10 9.937
    -     - 100 99.937

Beim Betrachten der Werte für natürliche Zahlen auf der rechten Seite bemerkt man sofort, daß die Veränderung der Zahlen etwas mit einer INTEGER-Division durch 3 zu tun haben muß ... Offensichtlich gilt für natürliche Zahlen N das Gesetz :

F (3 * N) = 3 * N * 1.000 $
F (3 * N + 1) = F (3 * N) + F (1)
F (3 * N + 2) = F (3 * N) + F (2)

Die beobachtete Abweichung von den COD-Parametern ist übrigens unabhängig von der Einwohnerzahl, d.h. die Basis für 32 % Steuern ist 1,312 $ pro Pionier.

10 Pioniere zahlen 13 $ statt 14 $,
100 Pioniere zahlen 131 $ statt 140 $,
usw.

Falls es sich hierbei nicht um Absicht, sondern um einen Rundungsfehler handelt, so ist er besonders schwerwiegend, da der Fehler

X = 1,4 $ - 1,312 $ = 0,088 $ pro Pionier
später noch mit der Zahl der Pioniere multipliziert wird.
Gesamt-Fehler = Anzahl Pioniere * 0,088 $.

Ich möchte an dieser Stelle darauf hinweisen, daß es allein Sache der Programmierer ist, wie aus bestimmten Parametern innerhalb ihres Programms bestimmte Werte für das Spiel berechnet werden ... Solange das Spiel in seiner Funktionalität (Spielbarkeit, Spielspaß) nicht eingeschränkt wird, ist alles erlaubt. Daher hat auch der Spieler leider kein Recht auf Ersatz der ihm womöglich entgangenen Steuereinnahmen ...

Auf jeden Fall sollte nun allen klar sein, daß man manche COD-Parameter erst nach einer sorgfältigen (und meist sehr zeitintensiven) Prüfung korrekt interpretieren kann.