Sehr geehrter Herr Schnoor,
Sie haben Ihr persönliches "Spezialprogramm" zur Prüfung des Strings <ziffern>
auf Mehrfachzeichen bisher nicht vorgelegt. Andererseits hat bislang keiner der
Mitforisten an meinem Nachweis genau dieses Defekts von <ziffern> Kritik geübt.
Wie es scheint, sind Sie als einziger davon überzeugt, dass Ihr <ziffern>String
ein taugliches Gebilde zur fehlerfreien Kodierung und Dekodierung von Zahlen
zur Basis 4096 ist.
Anyway.
Machen wir ein neues Faß auf. Untersuchen wir die Frage: Was ist problematisch,
wenn ein solcher Ziffernstring ein Zeichen mehrfach enthält?
(1) Als Beispiel betrachte ich Hexzahlen mit dem Standard-Ziffernstring ziffern
= '0123456789ABCDEF'.
Als Studienobjekt wähle ich – angregt durch wikipedia – die Dezimalzahl z1 =
45054 (eine Palindromzahl), umgewandelt in HexForm ergibt sich z2 =
hex(z1)[2:].upper() = 'AFFE'.
Konvertiert man z2 zurück in eine Dezimalzahl, erhält man mit z3 = int(z2, 16)
= 45054 die Ausgangszahl z1.
Wenn <ziffern> OK ist, hat man eine "Reise" von z1 zu z2, von z2 zu z3
absolviert. Und prüft abschließend, ob z1 und z3 gleich sind, ob man also ein
Rundreise absolviert hat. Das Umgekehrte gilt auch: Wenn die Reise eine
Rundreise war, ist <ziffern> OK.
Man kann dies kompakt so formulieren:
int(hex(z1)[2:].upper(), 16) == z1,
mit dem Output True.
(2) Jetzt sei <ziffern> defekt, enthalte aber weiterhin 16 Zeichen, jedoch
eines doppelt, etwa statt D ein F, also
ziffern2 = '0123456789ABCFEF', kurz Hexgestört.
Jetzt benötigt man zum Kodieren und Dekodieren zwei selbstgestrickte Funktionen.
Man kann sich freilich jetzt schon klar machen: Die Kodierung von Dezimal z1
via Hexgestört zu z2 geht ohne Probleme. Denn zum Kodieren einer Dezimalzahl
nach einer anderen Basis wird der Euklidische Divisionsalgorithmus verwendet.
Der berechnet aus z1 iteriert die Reste bei Division von z1 durch 16 (rest = z1
% 16), wobei z1 schrittweise ebenfalls verkleinert wird durch Ganzzahldivision
z1 = z1 // 16.
Daraus folgt für den Kodierschritt: Auch mit einem defekten Ziffernstring geht
das problemlos.
Mit der folgenden Funktion
def dezToBase(basis, zahl, ziffern=None):
#
https://stackoverflow.com/questions/2267362/how-to-convert-an-integer-to-a-string-in-any-base
# etwas erweitert.
if zahl == 0:
if ziffern: return '0'
else: return [0]
# Methode: Euklidischer Divisionsalgorithmus
reste = []
while zahl:
reste.append(zahl % basis)
zahl //= basis
reste = reste[::-1] # Reihenfolge der Reste umkehren
if ziffern:
return ''.join([ ziffern[x] for x in reste ])
else:
return reste
und basis = len(ziffern2)
ergibt sich z2 = zahl2Base(basis, z1, ziffern2) = 'AFFE'.
(3) Beim Dekodierschritt stößt man auf ein mögliches Problem: Hier wird z2 zu
einer (Pseudo-)Dezimalzahl
z3 = A*16**3 + F*16**2 + F*16**1 + E*16**0
umgewandelt. Man sieht, wo das Problem (für den Algorithmus) liegt: Welchen
Wert für F nehme ich aus <ziffern2>? Das linke F (der Ersatzspieler für D) hat
den Index-Wert 13, das rechte (=richtige) F hat weiterhin den Index-Wert 15.
Wegen der Wahl des Buchstabens aus <ziffern2> mittels ziffern2.index(.) fällt
die Wahl des Algorithmus auf das linke F (weil der Indexwert 13 < 15 ist).
Mit der Funktion
def bas2dez(basis, zahl, ziffern):
z10 = 0
for i in range(len(zahl)):
z10 = z10*basis + ziffern.index(zahl[i])
return z10
ergibt sich z3 = 44510 != z1, also eine Fehl-Dekodierung
(4) Wie prüft man das gesamte Zahlensystem (aus <ziffern> und davon
abgeleiteter basis) auf Korrektheit?
Dazu genügt es, jede Zahl im Intervall [0, basis] zu Kodieren und zu
Dekodieren, und die Ergebnisse auf Gleichheit zu prüfen. Etwa so:
for z1 in range(basis):
z2 = dezToBase(basis, z1, ziffern)
z3 = bas2dez(basis, z2, ziffern)
if z1 != z3:
print("%s == %s" % (z1, z3))
Für das defekte <ziffern2> oben ergibt sich damit:
45054 == 44510 # eine richtige Fehl-Dekodierung
(5) Man könnte jetzt noch weitere Defekte durchspielen (E ersetzen durch F, C
ersetzen durch D, ...). Es mag sein, dass in EINZELFÄLLEN z1 gleich z3
resultiert. Schön, aber irrelevant. Es geht einzig um die
Frage: Arbeitet das System in ALLEN Fällen korrekt?
(6) Zusammenfassung:
Ein Zahlensystem zu einer "höheren" Basis mit einem
Nicht-Standard-Ziffernstring funktioniert nur genau dann (in ALLEN Fällen)
korrekt, wenn dieser Ziffernstring kein Zeichen mehrfach enthält.
(7) Prüft man das System ziffern4096 von Ihnen, Herr Schnoor, -- hier
publiziert, von Ihnen bis heute als tauglich und insbesondere frei von
Mehrfachzeichen behauptet -- so ergibt sich (nach Tilgung der untauglichen, da
unsichtbaren whitespace-Zeichen, unter Beibehaltung der 60+ Mehrfachzeichen,
und unter Voranstellung der (bislang fehlenden) Ziffer '0', folgender Output
mit 77 Fehl-Dekodierungen:
Basis : 4059 # bewirkt durch die eben beschriebenen "Reinigungsmaßnahmen"
ziffern : "0123456789 ... ꇰꇱꇲꇳꇴꇵꇶꇷꇸꇹ"
[ 1] 877 == 844 [ 2] 878 == 876 [ 3] 879 == 845 [ 4] 880
== 876
[ 5] 881 == 846 [ 6] 882 == 876 [ 7] 883 == 851 [ 8] 884
== 876
[ 9] 885 == 856 [10] 886 == 876 [11] 888 == 876 [12] 890
== 876
[13] 892 == 876 [14] 964 == 943 [15] 966 == 944 [16] 967
== 965
[17] 968 == 956 [18] 969 == 965 [19] 1047 == 1025 [20] 1049
== 1026
[21] 1050 == 1048 [22] 1506 == 1505 [23] 1516 == 1515 [24] 1517
== 1507
[25] 1522 == 1521 [26] 1523 == 1507 [27] 1528 == 1527 [28] 1529
== 1507
[29] 1534 == 1533 [30] 1535 == 1507 [31] 1548 == 1503 [32] 3885
== 857
[33] 3886 == 858 [34] 3887 == 859 [35] 3888 == 860 [36] 3889
== 861
[37] 3890 == 862 [38] 3891 == 863 [39] 3892 == 864 [40] 3893
== 865
[41] 3894 == 866 [42] 3895 == 867 [43] 3947 == 3077 [44] 3948
== 3078
[45] 3949 == 3079 [46] 3950 == 3080 [47] 3951 == 3081 [48] 3952
== 3082
[49] 3953 == 3083 [50] 3954 == 3084 [51] 3955 == 3085 [52] 3956
== 3086
[53] 3957 == 3090 [54] 3959 == 3461 [55] 3960 == 3462 [56] 3961
== 3463
[57] 3962 == 3464 [58] 3963 == 3465 [59] 3964 == 3466 [60] 3965
== 3467
[61] 3966 == 3468 [62] 3967 == 3469 [63] 3968 == 3470 [64] 3969
== 3471
[65] 3970 == 3472 [66] 3971 == 3473 [67] 3972 == 3474 [68] 3973
== 3475
[69] 3974 == 3476 [70] 3975 == 3477 [71] 3976 == 3478 [72] 3977
== 3479
[73] 3978 == 3480 [74] 3979 == 3445 [75] 3980 == 3446 [76] 3981
== 3447
[77] 3982 == 3448
Erst nach Tilgung der Mehrfachzeichen durch
ziffern = ''.join(sorted(list(set(ziffern))))
gibt es keine Fehler mehr.
Dafür hat man aber auch die Basis 4096 "verloren" und gegen die Basis 3982
getauscht. Will man die Wunschbasis 4096 wiederhaben, muß man halt – wie schon
früher gesagt – nachbessern.
W. Büchel
_______________________________________________
python-de Mailingliste -- [email protected]
Zur Abmeldung von dieser Mailingliste senden Sie eine Nachricht an
[email protected]
https://mail.python.org/mailman3/lists/python-de.python.org/
Mitgliedsadresse: [email protected]