Schlagwort: Theorie

(Pseudo-)Zufallszahlen in C# 👍 👎

Sehr häufig benötigt man in div. Anwendungen zufällige Zahlen (oder zumindest solche, die sich hinreichend ähnlich verhalten). Hierfür steht uns in C# die grundlegende Klasse Random zur Verfügung:
Random-Klasse verwenden
0102030405060708091011121314
Random random = new Random();
int randomInt = random.Next(); // Intervall: [0,Int32.MaxValue)int randomIntMax = random.Next(8); // Intervall: [0,8) bzw. [0,7]int randomIntMinMax = random.Next(5, 19); // Intervall: [5,19) bzw. [5,18]
/** * Befüllt "randomData" mit * zufälligen Byte-Werten.**/
byte[] randomData = new byte[3];random.NextBytes(randomData);
double randomDouble = random.NextDouble(); // Intervall: [0,1)
Manche Entwickler sind ggf. erst einmal etwas auf Grund der oberen Grenze verwirrt, welche bei Verwendung der entsprechenden Methoden exklusiv ist. Das bedeutet, dass ihr das eigentlich gewünschte Maximum inkrementiert angeben müsst, sofern dieses ebenfalls enthalten sein soll.

Die Verwendung gestaltet sich dennoch offensichtlich sehr einfach. Zu berücksichtigen gilt jedoch, dass als Seed standardmäßig ein zeitabhängiger Wert verwendet wird – um dieses Verhalten selbst zu steuern, existiert eine weitere Variante des Konstruktors. Gleiche Startwerte ergeben wie üblich gleiche Sequenzen an Zufallszahlen.

Für sensiblere Anwendungen, beispielsweise zur Schlüsselgenerierung, steht der kryptografische Zufallszahlengenerator RNGCryptoServiceProvider als konkrete Implementierung der abstrakten Basisklasse RandomNumberGenerator zur Verfügung. Die Verwendung gestaltet sich ähnlich einfach:
RNGCryptoServiceProvider-Klasse verwenden
01020304050607080910111213
using(RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider()) {      // 3 Zufallszahlen erzeugen    byte[] randomData = new byte[3];    rng.GetBytes(randomData);
// Zufalls-Bytes durchlaufen foreach(byte randomNumber in randomData) { /** * "randomNumber" enthält nun jeweils * eine der erzeugten Zufallszahlen. **/ }}
Weitere sinnvolle Hinweise finden sich in den jeweiligen Klassenbeschreibungen des MSDN.

Farbcodes 👍 👎

Ab dem 1. August haben wir in der Firma einen neuen Auszubildenden zum Fachinformatiker für Anwendungsentwicklung. Dieser hat vor Kurzem noch ein zweiwöchiges Praktikum bei uns absolviert und dabei auch einiges von mir erfahren (ich hoffe, er hat sich erholt Smiley: winking). Auf dem Plan stand auch das Thema Farbcodes, wie sie insbesondere im Webdesign auftreten und nun möchte ich hier ebenfalls ein paar Worte dazu verlieren.

Zuerst einmal muss klar sein, was eigentlich die theoretische Grundlage dieser Notation ist, um sinnvolle Aussagen treffen zu können. Wir besprechen hier den RGB-Farbraum, welcher ein (additiver) Farbraum aus den drei Grundfarben Rot, Grün und Blau darstellt – wir besitzen demnach also drei Farbkanäle. Mit ein wenig Fantasie lässt sich bereits jetzt erahnen, wie entsprechende Farbcodes aus CSS zu verstehen sind:
#R1R0G1G0B1B0
Für jeden Farbkanal stehen uns in dieser Notation zwei hexadezimale Ziffern zur Verfügung, d. h. der Wertebereich pro Farbkanal erstreckt sich von 0 – ff16 (bzw. 0 – 25510) ≙ 162 (= 256) mögliche Werte.

Durch entsprechend niedrige bzw. hohe Werte pro Farbkanal ergibt sich proportional dazu die Intensität der jeweiligen Grundfarbe, d. h. um eben diese in voller Ausprägung darzustellen müssen wir lediglich den entsprechenden Farbkanal mit dem höchsten Wert belegen:
Grundfarben als Farbcode
010203
#ff0000 = ff (Rot) + 00 (Grün) + 00 (Blau) = Rot#00ff00 = 00 (Rot) + ff (Grün) + 00 (Blau) = Grün#0000ff = 00 (Rot) + 00 (Grün) + ff (Blau) = Blau
Wenn man sich den Farbraum wörtlich vorstellt, d. h. als Koordinatensystem mit den entsprechenden Farbkanälen als Achsen, können wir jeder Koordinate einen Farbeindruck entnehmen. Die tatsächlichen Farbmodelle sind noch etwas komplexer, für diese kleine Einführung ist diese Vorstellung jedoch durchaus legitim.

Sofern wir alle drei Farbkanäle mit einem identischen Wert belegen, erhalten wir einen grauen Eindruck zwischen niedrigster (Schwarz) und höchster (Weiß) Intensität:
Grauwerte
010203040506070809
#000000 = 00 (R) + 00 (G) + 00 (B) = Schwarz#333333 = 33 (R) + 33 (G) + 33 (B) = dunkles Grau#777777 = 77 (R) + 77 (G) + 77 (B) = mittleres Grau#cccccc = cc (R) + cc (G) + cc (B) = helles Grau#ffffff = ff (R) + ff (G) + ff (B) = Weiß
Sofern – wie im o. g. Beispiel, was dafür nicht unbedingt notwendig gewesen wäre – jeder Farbkanal aus zwei identischen Ziffern besteht, erlauben uns CSS und viele Grafikprogramme eine Kurzschreibweise, so dass aus #RRGGBB die Verkürzung #RGB werden kann. So kann beispielsweise aus #112233 schlicht #123 werden.

Weitere prägnante Farben zur Orientierung:
Weitere Farbcodes
010203
#00ffff (= #0ff) = 00 (R) + ff (G) + ff (B) = Cyan#ff00ff (= #f0f) = ff (R) + 00 (G) + ff (B) = Magenta#ffff00 (= #ff0) = ff (R) + ff (G) + 00 (B) = Gelb
Zugegebenermaßen war das nun wirklich nur eine sehr minimale Einführung mit einigen Vereinfachungen. Ich hoffe dennoch, dass manchem reinen "Farbcode-Kopierer" das System dadurch etwas klarer geworden ist.

Möglicherweise – das kann ich allerdings noch nicht versprechen – kann ich meinen ehem. Ausbilder einmal zu einem Gastbeitrag zum Thema Farbe und Licht bewegen, der als Elektrotechniker auf diesem Gebiet ein Experte ist und das auch sehr gut verständlich machen kann. Ein anderer Gastbeitrag ist auf jeden Fall bereits geplant. Smiley: smiling

Zahl ohne Konvertierung umdrehen 👍 👎

Passend zu einem etwas älteren Beitrag zur Ermittlung der Anzahl der Ziffern einer Zahl soll es noch einmal darum gehen, ein Problem mathematisch zu lösen, statt den Umweg über Zeichenketten zu gehen. Konkret möchten wir eine Zahl schlicht "umdrehen". Im Prinzip soweit natürlich kein Problem:
Zahl umdrehen (mit Konvertierung)
010203
int number = 12345;
int numberReverse = Int32.Parse(String.Concat(number.ToString().Reverse())); // 54321
Wir konvertieren die Zahl hierbei zuerst zu einer Zeichenkette, drehen die Zeichen anschließend um und fügen sie zusammen, um sie letztlich wieder zu einer Zahl zu konvertieren.

Das funktioniert – zumindest bei nicht-negativen Zahlen – soweit auch einwandfrei und kann je nach Kontext auch die schnellste Variante sein, jedoch lässt sich das Problem auch rein rechnerisch lösen:
Zahl umdrehen (ohne Konvertierung)
010203040506070809
int number = 12345;
int numberReverse = 0;while(number != 0) { numberReverse *= 10; numberReverse += (number % 10);
number /= 10;} // "numberReverse" enthält nun (ebenfalls) 54321
Wir nutzen dabei aus, dass uns der Modulo-Operator (%) jeweils den Rest einer ganzzahligen Division liefert, welchen wir als neue Ziffer der Lösung verwenden und anschließend die gegebene Zahl um eben diesen Anteil verringern. Als netter "Nebeneffekt" funktioniert diese Vorgehensweise auch bei negativen Zahlen problemlos.

Anzahl der Ziffern einer Zahl ermitteln 👍 👎

Oftmals sehe ich zur Ermittlung der Anzahl der Ziffern einer Zahl, dass diese explizit in eine Zeichenkette konvertiert und anschließend mit Zeichenketten-Operationen bearbeitet wird. Unter sehr dynamischen Sprachen wie beispielsweise PHP wird einem dies besonders einfach gemacht.

Das funktioniert zwar zweifelsohne und kann je nach Kontext auch der schnellste Weg sein, mathematisch elegant ist das aber nicht und darum möchte ich zumindest der Vollständigkeit wegen gerne aufzeigen, wie sich dieses Problem rein rechnerisch lösen lässt.

Dazu erinnern wir uns zuerst einmal an den Begriff der Größenordnung, welche eine Zahl zu gegebener Basis (im Alltag also meistens die 10, bei Informatikern evtl. auch noch 2, 8 oder 16 Smiley: winking) um eben diesen Faktor erhöht. Anschaulicher lässt sich dies als Potenz vorstellen, bei der der Exponent inkrementiert wird. Da dabei praktisch im jeweiligen Stellenwertsystem auch die Anzahl der Ziffern der jeweiligen Zahl steigt, fällt dem geneigten Leser möglicherweise bereits ein Zusammenhang auf. Zuerst einmal wollen wir die bisherigen Kenntnisse jedoch der Übersicht wegen formal notieren:
Größenordnungen
0102030405060708091011
   1 = 100    // eine Stelle   5 = 100,69  // eine Stelle  10 = 101    // zwei Stellen  15 = 101,17  // zwei Stellen 100 = 102    // drei Stellen 999 = 102,99  // drei Stellen1000 = 103    // vier Stellen1234 = 103,09  // vier Stellen
Es besteht offensichtlich ein Zusammenhang zum Exponenten der Basis des Zahlensystems, wie groß diese Zahl ist – was ja auch völlig klar so sein muss und letztlich keine besondere Erkenntnis ist. Genau diese Rückbesinnung auf Bekanntes bringt uns jedoch zur Lösung des Problems: Wir müssen zu unserer gegebenen Zahl den Exponenten zur Basis des gegebenen Zahlensystems suchen, wodurch unsere Zahl erzeugt wird.

Mit gewissem Entsetzen denken nun vielleicht die ersten Leser spontan an Wurzeln (und nebenbei an ihre letzte Wurzelbehandlung Smiley: grinning), aber es ist "noch schlimmer": Da uns Wurzeln die Basis liefern, wir jedoch den Exponenten benötigen und das Kommutativgesetz bei Potenzen im Allgemeinen nicht gilt (d. h. ab ≠ ba), benötigen wir die zweite Umkehroperation – den Logarithmus.

Dieser löst uns die Gleichung 10x = Zahl nach x auf und damit haben wir bereits beinahe die Lösung unserer eigentlichen Fragestellung. Da der Exponent auch Dezimalstellen enthalten kann, die Anzahl der Ziffern jedoch in jedem Fall eine natürliche Zahl sein muss, runden wir das Ergebnis erst einmal pauschal ab. Da die Zählung des Exponenten nun auch noch bei 0 beginnt (was uns als Softwareentwickler aber nur mäßig schockieren dürfte Smiley: cool), korrigieren wir diesen Versatz durch Addition von 1 und erhalten folgende Lösung:

Anzahl der Ziffern einer Zahl (im Dezimalsystem) = ⌊log10 Zahl⌋ + 1

Natürlich lässt sich dies auch in Programmen sehr einfach verwenden, daher wollen wir eine Erweiterungsmethode für ganze Zahlen in C# schreiben, die uns die Anzahl der Ziffern liefert:
Anzahl der Ziffern einer Zahl (Implementierung in C#)
010203040506070809
public static int GetDigitCount(this int number) {    if(number != 0) {        double baseExp = Math.Log10(Math.Abs(number));
return Convert.ToInt32(Math.Floor(baseExp) + 1); } else { return 1; }}
Wir berücksichtigen dabei die 0 separat und beugen außerdem Problemen mit negativen Zahlen durch Verwendung der Betragsfunktion vor. Die Anwendung gestaltet sich nun denkbar einfach:
Anzahl der Ziffern einer Zahl (Verwendung der C#-Implementierung)
01020304
int digitCount = (1).GetDigitCount();     // 1int digitCount = (12).GetDigitCount();    // 2int digitCount = (123).GetDigitCount();   // 3int digitCount = (1234).GetDigitCount();  // 4
Natürlich wäre auch die Implementierung in Form einer Schleife, welche die Zahl fortlaufend durch die Basis (10) teilt, denkbar, um die Anzahl der Ziffern zu ermitteln. Aber das sei dem geneigten Leser zur Übung überlassen. Smiley: tongue_out

Notation formaler Ausdrücke 👍 👎

a + b ist ein Term, wobei a und b als Summanden bezeichnet werden. Das sollte soweit jedem Leser dieses Blogs klar sein – mit Grundschulmathematik soll es nun aber gar nicht weitergehen, wir benötigen nur eine gemeinsame Grundlage für den weiteren Teil des Artikels. Smiley: grinning

Einen Bestandteil haben wir bisher jedoch gar nicht näher betrachtet: Das beinahe selbstverständliche Symbol der Addition, das +. Dabei ist das gar nicht so uninteressant. Was genau ist das eigentlich? Nun, auf jeden Fall wird es als Operator bezeichnet. Diese Schreibweise ist uns so vertraut, dass sich die meisten bisher wahrscheinlich gar keine Gedanken zu den Hintergründen einer solchen Schreibweise gemacht haben – und wir auch andere ganz selbstverständlich verwenden.

Tatsächlich handelt es sich nämlich um den in sogenannter Infixnotation geschriebenen Aufruf der Funktion +(a,b); der Name der Funktion lautet also + und Funktionen dieser Darstellung werden üblicherweise in Präfixnotation geschrieben. Dies ist einem aus der Mathematik bei Funktionen wie sin und cos geläufig und selbstverständlich auch als Entwickler der meisten Programmiersprachen und sogar bei Konsoleneingaben.

Präfixnotation findet in der Mathematik meist bei unären Operationen Anwendung, wohingegen bei binären Operationen für gewöhnlich die Infixnotation zum Einsatz kommt. Mehrstellige Operationen werden (auch) in einfacher Funktionsschreibweise notiert.

Bei in Infixnotation geschriebenen Ausdrücken ist unbedingt die Operatorpräzedenz (und ggf. Operatorassoziativität) zu berücksichtigen. Dazu gehört auch der den meisten Lesern sicherlich bekannte Spruch "Punkt vor Strich": Manche Operationen müssen vor anderen ausgewertet werden, um das Ergebnis eindeutig zu halten; im Allgemeinen gilt beispielsweise:

(a + b) * c  ≠  a + (b * c)

Wie dadurch bereits ersichtlich und hoffentlich bekannt, lässt sich eine bestimmte Rangfolge mit Klammerung auch erzwingen. Üblicherweise gilt ohne nähere Spezifikation folgende Rangfolge bei einfachen Rechnungen:
  1. Klammerung
  2. Potenzierung
  3. Multiplikation, Division ("Punktrechnung")
  4. Addition, Subtraktion ("Strichrechnung")
Auch Programmiersprachen (z. B. C#, PHP) besitzen eine solche Rangfolge und unterscheiden sich teilweise.

Um aber noch einmal auf unsere Feststellung der unterschiedlichen Schreibweisen einzugehen: Tatsächlich ist dieses Problem nämlich der Infixnotation geschuldet; Präfixnotation (im Übrigen auch die umgekehrte Variante, die Postfixnotation) kann nämlich klammerfrei erfolgen und ist ganz einfach – wenn auch für die meisten sicherlich eher etwas ungewohnt – auf unser Beispiel der Addition übertragbar:
Addition mit Symbol und Präfixnotation
01
+ a b
Auch "komplexere" (na ja …) Anwendungen stellen kein Problem dar:
Vergleich von Infix- und Präfixnotation
0102030405
  // Infixnotation(a + b) * (c – d)
// Präfixnotation* + a b – c d
Wie man sieht, können hier die Klammern entfallen und man erhält dennoch das erwartete Ergebnis. Diese Darstellungsform vereinfacht im Übrigen das automatisierte Verarbeiten erheblich.

123

Projektverweise

Kategorien / Archiv  |  Übersicht RSS-Feed

Schlagworte

Suche