Herausforderungen mit Zahlen in der Programmierung: Hidden bugs, Effekte auf die Realität und der richtige Umgang.
Der korrekte Umgang mit Zahlen in der Softwareentwicklung ist so wichtig wie die Reifen bei einem Auto, um es zu fahren.
Obwohl viele Entwickler sagen, Mathematik ist ein täglicher Bestandteil des Tages, so kommt man um die Verarbeitung von Zahlen nicht drum herum.
Doch wie schon früher in der Schule, kann der Umgang mit Zahlen sehr Herausfordernd sein. In dieser Episode sprechen wir über klassische Fehler, die beim Umgang mit Zahlen in Software gemacht werden, über skurriles Verhalten von Programmiersprachen aber auch über die Effekte dessen auf die reale Welt.
Es geht um Datentypen in Programmiersprachen und deren Wertebereiche, Probleme mit großen Zahlen und JSON, Währungsumrechnung und die korrekte Speicherung, Integer-Under- und Overflow, negative Modulo-Berechnungen, rückwärtslaufende Uhrzeiten und wie verschiedene Programmiersprachen sich bei der selben Berechnung anders verhalten.
Bonus: Ob Wolfgang Graf Zahl von der Sesamstraße kennt und warum JavaScript nicht gut in dieser Episode davonkommt.
Unsere aktuellen Werbepartner findest du auf https://engineeringkiosk.dev/partners
Das schnelle Feedback zur Episode:
Links
- Katalog der ACM für Computer-Informatik/Forschungsbereiche: https://en.wikipedia.org/wiki/ACM_Computing_Classification_System
- PHP Spaceship operator: https://www.php.net/manual/en/migration70.new-features.php
- Graf Zahl (Sesamstraße): https://de.wikipedia.org/wiki/Sesamstra%C3%9Fe#Graf_Zahl
- Go Programmiersprache: https://go.dev/
- Numerische Datentypen in Go: https://go.dev/ref/spec#Numeric_types
- JavaScript Number Encoding: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number#number_encoding
- TC39 Comittee zur Erweiterung von JSON um BigInt: https://github.com/tc39/proposal-json-parse-with-source
- LLVM CLang UndefinedBehaviorSanitizer: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
- Modulo mit negativen Zahlen: https://torstencurdt.com/tech/posts/modulo-of-negative-numbers/
- “Salami Taktik” Kleine Geldbeträge stehlen: https://en.wikipedia.org/wiki/Salami_slicing_tactics
- Examples of problems with integers: https://jvns.ca/blog/2023/01/18/examples-of-problems-with-integers/
- Examples of floating point problems: https://jvns.ca/blog/2023/01/13/examples-of-floating-point-problems/
Sprungmarken
Hosts
- Wolfgang Gassler (https://mastodon.social/@woolf)
- Andy Grunwald (https://twitter.com/andygrunwald)
Feedback (gerne auch als Voice Message)
- EngKiosk Community: https://engineeringkiosk.dev/join-discord
- Email: stehtisch@engineeringkiosk.dev
- Mastodon: https://podcasts.social/@engkiosk
- Twitter: https://twitter.com/EngKiosk
- WhatsApp +49 15678 136776
Transkript
Andy Grunwald (00:00:18 - 00:01:14)
Das war Graf Zahl von der Sesamstraße beim Zählen. Dass jemand so viel Spaß mit Zahlen hat, hört man selten. Deswegen versuchen wir, das ganze Thema heute mal von einer anderen Seite aufzurollen. Wir sprechen über Herausforderungen mit Zahlen bei der Softwareentwicklung, aber eher aus der Sicht von skurrilem bzw. unerwartetem Verhalten. Es geht um Probleme mit großen Zahlen und JSON, Integer, Under- und Overflows sowie das Jahr 2038 und das Jahr 2036 Problem. Es geht um rückwärts laufende Uhrzeiten, negative Modulo-Berechnungen und wie verschiedene Programmiersprachen sich bei derselben Berechnung anders verhalten und vieles mehr. Wir hoffen, ihr habt genauso viel Spaß beim Zählen wie Graf Zahl. Und los geht's! Lieber Wolfgang, du hast ja einen Doktortitel und ich habe mich immer gefragt, wie viel Informatik mit Softwareentwicklung zu tun hat bzw. wie viel Softwareentwicklung steckt in Informatik, im Fachbereich Informatik.
Andy Grunwald (00:01:18 - 00:01:26)
Nee, ob das einfach ein essenzieller Teil davon ist oder ob Informatik eigentlich gar nichts mit Softwareentwicklung zu tun hat oder oder oder.
Wolfi Gassler (00:01:26 - 00:01:47)
Ja, Softwareentwicklung ist ein Teil der Informatik, ist ja ganz klar. Es gibt ja irgendwie so einen Katalog von der ACM, glaube ich, von der American Computer Machinery, glaube ich, heißt die Abkürzung und die definiert da Computerbereiche, Informatikbereiche, Forschungsbereiche. Da ist Softwareentwicklung sicher einer davon, ja.
Andy Grunwald (00:01:47 - 00:02:00)
Zweite Frage. Wie viel hat Mathematik mit Softwareentwicklung zu tun? Wie viel Mathe muss man verstehen, um Software entwickeln zu können? Oder ist Mathematik ein essentieller und sehr wichtiger Bestandteil der Softwareentwicklung?
Wolfi Gassler (00:02:00 - 00:02:33)
Also einerseits gibt es immer extrem viele Studierende, die sich über die Mathe-Vorlesungen aufregen und vielleicht dann sogar raustroppen, weil das Informatikstudium so mathematisch ist. Auf der anderen Seite habe ich schon Programmiererinnen kennengelernt, die wenig Mathe-Ahnung hatten und vor allem, wenn es dann irgendwie tiefer nach unten geht und du keine Standard-if-Classes baust, die die Copilot machen kann, dann sieht man teilweise schon, dass Mathematik-Grundwissen oder tieferes Wissen schon ganz praktisch sein kann. Weil zum Beispiel, kennst du den Pipe Operator in der Programmiersprache?
Andy Grunwald (00:02:33 - 00:02:41)
Ich kenne den Spaceship Operator. Ich glaube, der wurde bei PHP und bei Ruby irgendwie eingeführt. Pipe Operator, ist das dasselbe wie auf der Bash-Kommandozeile, oder?
Wolfi Gassler (00:02:41 - 00:02:47)
Ja, ja, der ganz normale Pipe. Wenn du ein Oder machst, in deiner Go-Sprache, wie machst du denn da ein Oder? Mit zwei Strichen.
Wolfi Gassler (00:02:53 - 00:03:02)
Sehr gut, Herr Grunwald. Das wissen schon extrem viele Leute nicht mehr, was eine Bit-Operation ist. Oder weißt du, was eine Bit-Operation ist? Oder weißt du nur, dass es eine Bit-Operation ist?
Andy Grunwald (00:03:03 - 00:03:09)
Ich kriege das schon noch hin. Und ich glaube, das Gegenstück dazu ist natürlich auch das einfache Rund, also das einfache Kaufmannsrund. Ja, genau.
Andy Grunwald (00:03:12 - 00:03:15)
Gegenfrage, was man eigentlich nicht tut. Wie sehr hasse ich Bit-Shifting?
Andy Grunwald (00:03:18 - 00:03:37)
Das ist richtig. Selbes Feld. Ich hasse auch Bit-Operationen, ja? Weil mein Kopf da einfach zusammenfällt. Mein Kopf kann das einfach nicht... Ich versteh, was 0 und 1 sind, ja, und ich kann ne einfache Zahl so mit einem Bit und so, das krieg ich auch grad noch im Papier hin. Aber viel weiter darüber ist es echt... Also, mein Kopf kann das nicht verarbeiten. Ich weiß nicht, warum. Vielleicht bin ich auch einfach kein guter Softwareentwickler.
Wolfi Gassler (00:03:38 - 00:04:03)
Es ist ja eigentlich ganz einfach, weil wenn du die zwei Striche hast, ein logisches oder, das macht ja das gleiche wie das bitweise oder, nur das bitweise oder macht das pro Bit. Das heißt, das vergleicht halt dann die erste 1 oder die erste 1 oder die erste Stelle von der zweiten Zahl. Also das ist genau das gleiche. Das ist nur das eine auf Bitlevel und das andere auf logischer Ebene. Die Frage ist ja immer, muss man das Ganze wissen?
Andy Grunwald (00:04:03 - 00:04:13)
Ja, deswegen mache ich mal das mit einer dritten Frage ein bisschen einfacher. Wie viel hat Mathematik mit Zahlen zu tun? Also nicht mit Geldzahlen, sondern so mit Zahlen wie eins, zwei, drei und so.
Wolfi Gassler (00:04:13 - 00:04:20)
Ja, das ist so ähnlich, wie wenn du fragst, was hat Menschsein mit dir zu tun? Zahlen sind Teil der Mathematik.
Andy Grunwald (00:04:20 - 00:04:36)
Ja, doch, man sagt eigentlich schon, das ist die Zahl E, oder? Also ich meine, E ist ein Buchstabe in der Hinsicht. Die Zahl E drückt ja dann Wert aus oder die Zahl Pi. Pi ist ja keine Zahl, obwohl es 3,14 und so weiter ist, aber das Zeichen Pi ist ja keine Zahl und das Zeichen E ist ja auch keine Zahl.
Andy Grunwald (00:04:39 - 00:04:41)
Nee, aber ich meine, die wird ja durch den Buchstaben repräsentiert.
Wolfi Gassler (00:04:44 - 00:04:49)
Wir sagen übrigens Mathematik, nicht Mathe, Mathematik. Ganz wichtig, die österreichische Betonung.
Andy Grunwald (00:04:49 - 00:04:55)
Und bevor wir ins eigentliche, wirkliche Thema einsteigen, die viel wichtige Frage, Im Moment.
Wolfi Gassler (00:04:55 - 00:05:01)
Sind wir nicht so lange im Thema drin. Jetzt wird es spannend, was wir für ein Thema haben. Okay, unser Einsprecher hat das ja schon verraten.
Wolfi Gassler (00:05:03 - 00:05:07)
Hallo, Datenschutz? Ich kann das ja nicht so in die Welt rausbussernen.
Andy Grunwald (00:05:13 - 00:05:18)
In der Sesamstraße gibt es Graf Zahl. Und Graf Zahl bringt den Kindern im Vorschulalter.
Andy Grunwald (00:05:21 - 00:05:25)
Ich glaube, was du meinst, ist Bernd das Brot? Das ist eine andere Generation.
Andy Grunwald (00:05:28 - 00:05:37)
Und ich weiß gar nicht, ob die Elemente, diese Dinger, die reden können, bei der Sesamstraße Menschen sind. Das ist eine andere Frage. Aber du kennst anscheinend nicht Graf Zahl.
Andy Grunwald (00:05:39 - 00:05:49)
Okay, Graf Zahl bringt den Kindern im Vorschulalter das Zählen von Dingen bei. Und vielleicht war das der Knackpunkt, warum du in der Programmierung immer in Probleme mit Zahlen rennst.
Wolfi Gassler (00:05:54 - 00:06:06)
Ich bin mir nicht sicher, ob es die Sesamstraße so in Österreich gegeben hat, vor dem ganzen Zeitalter des Kabelfernsehens. Ich kann mich zumindest nicht erinnern, dass ich die jemals gesehen habe als Kind oder so. Hat es die überhaupt schon gegeben, wie jung war?
Andy Grunwald (00:06:06 - 00:06:17)
Also sie läuft seit 1969. Ja, das geht sich knapp aus. Die erste deutschsprachige Ausstrahlung war im Januar 1973.
Wolfi Gassler (00:06:17 - 00:06:24)
Das geht sich leider immer noch aus. Aber irgendwie im österreichischen Fernsehen war die meines Wissens nicht vertreten. Wäre interessant.
Andy Grunwald (00:06:24 - 00:07:21)
Okay, für alle Leute, die Grafzahl nicht kennengelernt haben und somit bei Grafzahl nicht das Zählen von Dingen gelernt haben, für die Leute haben wir heute eine besondere Ebene. Und zwar sprechen wir wieder über ein Thema in der Softwareprogrammierung, wo irgendwie wir jeden Tag mit zu tun haben, aber wo ich öfters den Anstand habe, dass wir diesem ganzen Bereich sehr, sehr wenig Aufmerksamkeit schenken. Und zwar ist das einfach das Thema Herausforderungen oder vielleicht kann man auch schon Probleme mit Zahlen sagen, mit Integer, mit Floats, mit Doubles, mit Dezimals und so weiter und so fort. Also Vielleicht auch über diese Art von Problemen, da wo ihr sagt, geil, endlich mal bugfreie Software geschrieben und dann deployed ihr das und nach vier Monaten habt ihr falsche Werte in der Datenbank und ihr versteht, die fehlt nicht mehr. Wir haben heute einfach mal ein paar klassische Real-World-Probleme rausgesucht, wo man ab und zu darüber schmunzeln kann und ab und zu sagt, what the fuck ist, was geht denn hier ab.
Wolfi Gassler (00:07:21 - 00:07:30)
Also was wir eigentlich machen ist, dass der Andi heute diesen Graph Zahl spielt für die Informatik. Sehe ich das richtig, Andi? Du erklärst uns jetzt die mathematische Welt.
Andy Grunwald (00:07:30 - 00:07:48)
Die erste Note in meiner Statistik 1 Klausur war, glaube ich, eine 3,7. Ich habe mich sehr gut vorbereitet gefühlt, bin da reingegangen, bin rausgegangen, war eine mega Leistung und bin gerade mit Statistik 1 mit so einer 3,7 da dabei geschlittert. Für Leute, die es nicht wissen, 4,0 ist auch noch bestanden und alles drüber ist halt, bitte wiederholen Sie die Klausur.
Wolfi Gassler (00:07:48 - 00:07:55)
Ja, aber Statistik hat ja wenig mit Zahlen zu tun. Zumindest mit dem Programmieranteil der Zahlen, würde ich mal sagen.
Andy Grunwald (00:07:55 - 00:08:08)
Und genau deswegen habe ich ja gefragt, was hat Softwareentwicklung mit der realen Informatik zu tun? Ich habe mir nämlich irgendwo gehört, nicht ganz so viel, aber ich versuche es so ein bisschen. Und als kleine Vorwarnung, irgendwie habe ich das Gefühl, bei der heutigen Folge wird JavaScript nicht so gut davon kommen.
Wolfi Gassler (00:08:09 - 00:08:18)
Was war denn dein letzter Fuckup, den du so erlebt hast mit Zahlen, wenn du irgendwie mit Zahlen hantiert hast, jetzt beim Programmieren oder sonst irgendwo in letzter Zeit?
Andy Grunwald (00:08:18 - 00:08:27)
Wo ich sehr oft reinrenne, ist bei Skriptsprachen die Typkonvertierung von String nach Int oder ähnliches, besonders wenn das mit einem Null-Präfix ist.
Wolfi Gassler (00:08:27 - 00:08:31)
Was meinst du mit einem Nullpräfix? Was passiert da genau? Kannst du das kurz erklären?
Andy Grunwald (00:08:31 - 00:08:38)
Naja, je nachdem welche Sprache du hast, kann diese Zahl unter anderem auch als Oktalzahl oder ähnliches...
Andy Grunwald (00:08:40 - 00:09:00)
Eine Oktalzahl ist eine Zahl mit der Basis 8, eine Dezimalzahl ist eine Basis 10, eine Binärzahl ist eine Basis 2 und eine Hexadezimalzahl ist die Basis 16, Wolfgang. Das bedeutet, du hast natürlich auch verschiedene Arten von Zahlen in der Programmierung, die natürlich dann auch anders repräsentiert werden. Zum Beispiel kannst du sagen, okay.
Wolfi Gassler (00:09:00 - 00:09:07)
Und wie repräsentiert man eine Oktalzahl? Ich kenne ja Hexadezimal mit 0x, aber was ist denn dann ein Oktal?
Andy Grunwald (00:09:07 - 00:09:18)
Soviel ich weiß, in vielen Programmiersprachen repräsentiert man eine Zahl mit Oktal, wenn die unter anderem mit einer 0 beginnen kann, aber dann nur die Zahlen 0 bis 7 auch drin hat. Je nach Programmiersprache ist es, glaube ich, ein bisschen anders.
Wolfi Gassler (00:09:18 - 00:09:51)
Das ist ja schon so ein großes Problem, dass man eigentlich ja wenig Ahnung hat, wie die Programmiersprache immer Sachen interpretiert. Und sogar wenn man mit Programmiersprachen lange arbeitet, dann sind ja so klassische Zahlenprobleme die, die man selten antrifft, aber die dann, wenn sie mal auftreten, wirklich ein großes Problem. produzieren, weil man eben keine Ahnung hat, dass da irgendwo was im Hintergrund umkonvertiert wird automatisch oder oktal interpretiert wird. Das heißt, wenn ich dann 0 7 zum Beispiel schreibe oder 0 7 6, dann könnte das oktal interpretiert werden.
Andy Grunwald (00:09:51 - 00:10:36)
Also, wenn man zum Beispiel JavaScript im Strict-Mode laufen lässt, dann kriegt man sogar einen Syntax-Error, weil die sagen, null-prefixed-octal-literals sind deprecated. Also, es geht halt schon in die Richtung, je nachdem, welche Programmiersprache man wählt. Aber das ist so der Klassiker, wenn ich sage, implizite Typkonvertierung, nicht explizite, implizite, das bedeutet, wo die Runtime-Engine, wo der Compiler oder der Interpreter Typen für mich konvertiert, oder wo ich gegebenenfalls Typen nicht ganz unter Kontrolle habe, kann natürlich auch sein. Und dann gegebenenfalls noch eine unglückliche Zahl habe, weil du hast ja keine Oktalzahl, wenn du in der Zahl einen 9 hast, dann ist es ja keine Oktalzahl mehr und somit kann es dann nicht mehr als Oktalzahl interpretiert werden. Also du merkst schon, da müssen dann so ein paar Sachen halt schon zusammenkommen, aber das ist so, wo ich öfter mal reinrenne.
Wolfi Gassler (00:10:36 - 00:10:47)
Ich habe gerade ganz kürzlich in der MySQL-Datenbank eine Division durchgeführt, also in einem SQL-Statement. Was kommt da als Typ raus, Andi? Was glaubst du?
Wolfi Gassler (00:10:48 - 00:10:56)
Ja, es ist gar nicht so leicht zu sagen. Meine Annahme war, es ist float oder so. Habt ihr das Ding in JavaScript einfach nach JSON konvertiert? Was kommt raus?
Wolfi Gassler (00:10:59 - 00:12:17)
Also bei JavaScript und JSON kann man immer, wenn man keine Ahnung hat, am besten String sagen. Das stimmt immer. Auf jeden Fall ist am Ende ein String rausgekommen mit dem Ergebnis und es war wirklich schwierig für mich zu verstehen, warum das passiert, weil es ja eine Division ist, da ist irgendwie ein Float, Double, was auch immer, da sollte sauber konvertiert werden. Javascript habe ich auch die Zahl explodiert, ist dann ein String und die Frage war für mich ja auch, Wo liegt das Problem? Liegt es an der Datenbank? Liegt es in JavaScript? Liegt es an der JSON-Library? Also du hast ganz viele Punkte, wo dieses Problem auftreten kann. Und das Debugging ist dann auch nicht so leicht, weil du musst herausfinden, okay, wo werden da was für Datentypen verwendet? Und am Ende ist es einfach so, dass das Ganze ein sogenannter New Decimal Wert ist. der ganz speziell definiert ist und Javascript kann natürlich mit sowas nicht umgehen und wandelt das dann einfach in String um, damit man auf der sicheren Seite ist und keine Präzisionsfehler oder ähnliche Dinge hat. Also bei diesem einfachen Fall nur Datenbank zu chasen hast du schon drei verschiedene Punkte, wo was schief gehen kann. wo du keine Ahnung hast, was die jeweiligen Libraries machen und die Datenbank, wie der Datenbanktreiber funktioniert. Und es hat mir durchaus einige Zeit gekostet, bis ich da wirklich dahinter gestiegen bin, wo da welcher Datentyp wie verwendet wird und warum.
Andy Grunwald (00:12:17 - 00:12:45)
Also, liebe Hörerinnen und Hörer, ihr merkt schon, das Arbeiten mit Zahlen ist nicht ganz einfach, wenn ein Mensch mit einem Doktortitel in Datenbanken und Wissenssysteme und so weiter und schon in solchen einfachen Fällen von einer Programmiersprache mit JSON-Konvertierung und der Speicherung in einer Datenbank gegen irgendwelche Wände rennt. Genau deswegen sprechen wir mal über ein paar Herausforderungen mit dem Arbeiten von Zahlen heute. Bevor wir aber in die Probleme einsteigen, machen wir mal einen ganz kurzen Einstieg in Datentypen, damit wir mal jeden abholen.
Andy Grunwald (00:12:47 - 00:12:53)
Grafzahl, wenn Grafzahl das folgende in der Sesamstraße als Wissen vermittelt, dann fände ich das schon ziemlich cool, muss ich zugeben.
Andy Grunwald (00:12:56 - 00:13:07)
Also generell kann man erst mal sagen, welche Datentypen es gibt, unterscheidet sich von der Programmiersprache und nicht alle Datentypen werden von allen Programmiersprachen unterstützt.
Wolfi Gassler (00:13:07 - 00:13:15)
Was sind denn Datentypen von Zahlen überhaupt? In JavaScript kann ich da meine Zahl hinschreiben, das funktioniert. Da hat überhaupt nichts mit Datentypen zu tun.
Andy Grunwald (00:13:15 - 00:14:21)
Genau, man hat natürlich verschiedene Arten von Programmiersprachen. Besonders die Scriptsprachen oder auch moderne, kompilierte Programmiersprachen versuchen den Typ zu erraten. Da muss man ihn gar nicht wirklich definieren. Zum Beispiel in Go Variable Doppelpunkt gleich 5 initiiert automatisch einen Integer. Und bei PHP kannst du auch irgendwas definieren und bei JavaScript auch. Du kannst aber auch in diesen Sprachen explizit sagen, okay, das ist ein Integer oder das ist ein 64-Bit-Integer. Das bedeutet, Implizite Typangabe, explizite Typangabe ist schon mal ein Bereich. Welche Datentypen es gibt, wie gesagt, unterscheidet sich pro Programmiersprache. Zum Beispiel in der Sprache Go von Google gibt es mindestens acht Datentypen für einen Integer. Und zwar unterscheiden die sich in der A, in der Bitgröße. Also es gibt einen 8-Bit-Integer, 16, 32, 64. Dann gibt es alle Varianten davon nochmal unsigned und signed. Das bedeutet, kann man da ein Vorzeichen mitspeichern, ja oder nein. Das hat natürlich auch Einfluss auf den Wertebereich und der Wertebereich ist einfach, wie viele Zahlen kann man nämlich in diesem Integer-Datentyp speichern.
Wolfi Gassler (00:14:21 - 00:14:31)
Warum mache ich denn jetzt überhaupt so ein Int8 oder so, wo ich nur ganz wenig Platz habe, jetzt von minus 128 bis 127, minus 1 ist es immer?
Andy Grunwald (00:14:31 - 00:14:58)
Naja, das tolle ist, wenn du jetzt sagst, okay, man nimmt ein Int8, dann hast du automatisch den Wertebereich begrenzt, weil man kann halt nur minus 128 bis 127 speichern, das ist die eine Baustelle. Und ich glaube auch, dass du damit der Hardware bzw. dem Computer die Möglichkeit gibst, den Speicherbereich auch noch weiter zu optimieren, weil du müsstest dann nicht immer einen 64-Bit-Integer speichern, weil du brauchst halt den ganzen Platz nicht. Ob das jetzt wirklich möglich ist, weiß ich jetzt nicht.
Wolfi Gassler (00:14:59 - 00:15:34)
Ich glaube, die meisten Programmiersprachen allokieren wirklich 64-Bit. Vielleicht ist das sogar hardwarebedingt gar nicht anders möglich. Ich glaube, in Java ist es meines Wissens immer so, das war früher schon so, auf 64-Bit-Systemen wurden auch immer 64-Bit allokiert. Aber ob es da mittlerweile schon Optimierungen gibt, da bin ich auch zu wenig in der Softwareentwicklung drin, muss ich zugeben. Aber man könnte es zumindest optimieren und Datenbanken, da spielt es natürlich eine große Rolle, wenn du das dann wirklich irgendwo ablegst. Die Datenbanken optimieren dir das natürlich auf jeden Fall, den Speicherbereich.
Andy Grunwald (00:15:34 - 00:16:06)
Auf jeden Fall gibt es Programmiersprachen wie zum Beispiel Go, da kannst du sagen, okay, ich möchte sogar ein unsigned Integer mit 64 Bit haben. Das bedeutet eine Ganzzahl, die einen Wertebereich hat von 0 bis, und jetzt kommt eine ganz lange Zahl mit 20 Stellen. Das bedeutet, da kann man nicht die Zahl minus 1 drin speichern, weil sie einfach das Vorzeichen nicht mitspeichert, weil sie nicht vorzeichenbehaftet ist. Auf der anderen Seite kann man natürlich auch ein int 64 deklarieren. Da hat man einen Wertebereich von minus eine 19-stellige Zahl bis plus eine 19-stellige Zahl.
Andy Grunwald (00:16:08 - 00:16:14)
Groß. Dann gibt es natürlich die ganze Sache auch noch mit Fließkomma-Zahlen. Float oder Double heißt das in vielen Programmiersprachen.
Andy Grunwald (00:16:17 - 00:16:25)
Das ist glaube ich wirklich der zu speichernde Wertebereich und die Präzision im Fließkomma Bereich, wenn mich das jetzt gerade nicht trickt.
Wolfi Gassler (00:16:26 - 00:17:05)
Also es ist eigentlich ganz einfach zu merken, Double heißt Double, weil einfach doppelt so viele Byte verwendet werden. Das heißt, im klassischen Verständnis sind es einfach 8 statt 4 Byte. Das heißt, du hast eine höhere Präzision und darum heißt das Ding Double. Dass das mittlerweile nicht mehr so ganz hundertprozentig genau definiert ist. MySQL hat ja teilweise auch andere Definitionen. Du hast gerade richtig gesagt, es gibt float 32, float 64. Also das ist ja eigentlich schon wieder das Gleiche. Also es ist nicht mehr so klar definiert, aber das Ursprüngliche, also die klassische C-Definition war einfach Double, 8-byte, float 4-byte. Einfach mehr Genauigkeit.
Andy Grunwald (00:17:05 - 00:18:12)
Und ich hatte gerade gesagt, es unterscheidet sich pro verwendeter Sprache. In JavaScript sieht die ganze Sache anders aus. In JavaScript hat man gar keinen Datentyp Integer, sondern hat man nur den Typ Number. Und Number ist eine Double-Precision-64-Bit-Zahl im Binary-Format. Passwort-Bingo. Also da hat man automatisch eine Fließkomma-Zahl. Also jede Zahl in JavaScript ist eine Fließkomma-Zahl. Und die Eigenheit an JavaScript ist jetzt folgende. Die Größe und Genauigkeit der gespeicherten Zahl ist begrenzt. Das bedeutet, in JavaScript können Ganzzahlen nur im Bereich 2 hoch 53, im negativen und positiven Bereich, ohne Genauigkeitsverlust dargestellt werden. Es gibt eine Konstante, die nennt sich number.maxSafeInteger, da kommt eine Zahl raus, die ist 16 Stellen groß. Wenn ihr euch in diesem Wertebereich bewegt, was ich würde mal fast sagen sehr viele Applikationen tun, dann kann die Zahl von JavaScript mit dem Datentyp Number ohne Genauigkeitsverlust dargestellt werden. Die Zahl Number selbst kann aber eine viel größere Zahl speichern, und zwar eine Zahl bis zum maximalen Value 2 hoch 1024. Wie viele Stellen sind das, Wolfgang?
Andy Grunwald (00:18:13 - 00:18:18)
Aber da ist man dann in einem Bereich, wo es Genauigkeitsverluste geben kann.
Andy Grunwald (00:18:20 - 00:18:34)
Meines Wissens nach durch Rundungsfehler und wie sehr man die Precision nach dem Komma speichern kann. Da sollte man jetzt den Menschen mit dem Doktortitel fragen. Ich habe ja nur Bachelor und auch nur in Wirtschaftsinformatik. Ich bin ja sozusagen dumm.
Wolfi Gassler (00:18:34 - 00:19:31)
Ja, da müsste man natürlich jetzt sehr tief in das Rapid Hole runtergehen. Das ist immer die beste Ausrede, wenn man keine Ahnung hat. Aber grundsätzlich hängt es natürlich zusammen mit der Darstellung bzw. mit dem Speicherformat von Fließkomma-Zahlen, weil es ist ja nicht so, dass die Zahlen genauso gespeichert werden, wie du sie eingibst. Also du sagst, okay, du hast jetzt, wenn du 15,3 hast oder so, dann wird da 15 gespeichert und der 3 am Ende als eigene Zahl, sondern es wird ja umgewandelt in eine interne Repräsentation, die die CPU auch versteht. Und durch diese Umwandlung In so eine Gleitkomma-Repräsentation können die Details am Ende verloren gehen und dadurch kannst du einen Rundungsfehler geben, weil du eben Informationen von dieser Zahl verlierst. Und damit hast du eigentlich immer zu kämpfen, egal ob du Float, Double, was auch immer du verwendest, weil es kann immer diese Edge Cases geben. Was heißt Edge Cases eigentlich auf Deutsch? Corner Cases? Ausnahmefälle? Andy, wie heißt sowas?
Andy Grunwald (00:19:32 - 00:19:35)
Ausnahmefall beziehungsweise Fall, der selten auftritt, würde ich sagen, ja.
Wolfi Gassler (00:19:35 - 00:19:46)
Also der seltene Auftretungsfall ist dann, dass man da Information verliert und dann plötzlich eine andere Zahl rausbekommt. Und das ist ja eigentlich das Gefährliche an diesem ganzen Float-Double-Wert.
Andy Grunwald (00:19:46 - 00:19:49)
Und wie löse ich das Problem jetzt? Wie kriege ich das hin, dass ich damit sicher umgehe mit Leitkommazahlen?
Wolfi Gassler (00:19:49 - 00:20:14)
Ja, es kommt darauf an, was du machen willst. Da kommen wir eh später noch drauf. Aber wenn du Float und Double verwendest, hast du einfach Ungenauigkeiten. Damit musst du einfach leben. Das ist so. Du kannst mehr Genauigkeit draufschieben, indem du mehr Bytes dazuhängst, aber die Ungenauigkeit an sich, die bleibt. Die kannst du nicht verhindern mit diesen Datentypen. Da brauchst du andere Konstrukte dafür. Aber bleiben wir mal bei JavaScript, weil da gibt es sowieso nur den Number-Typ.
Andy Grunwald (00:20:14 - 00:20:58)
Ja, das ist nicht ganz richtig. Bei JavaScript gibt es nämlich auch noch einen anderen Datentyp, der nennt sich BigInt. Und der BigInt-Datentyp ist BigInt, eine große Ganzzahl. Mit dem BigInt kannst du auch in einem Wertebereich über MaxSafeInteger sicher agieren. Diese Zahlen haben in der Regel ein N als Suffix, also hinten dran steht einfach ein N. Und das tolle ist, sie können sogar mit einer normalen Zahl verglichen werden. Zwar nicht strikt, also eine Number ist nicht ein BigInt, wenn man sie strikt vergleicht mit drei gleicher Zeichen, aber wenn man sie loosely miteinander vergleicht, sondern mit zwei, dann klappt das sogar. Also in der Hinsicht ist JavaScript dann schon so ein bisschen einfacher gehalten als zum Beispiel Go, wo Go etliche Datentypen hat, hat JavaScript genau zwei.
Wolfi Gassler (00:20:58 - 00:21:02)
Und kann ich dann mit diesem BigInt endlich meine Twitter-IDs abspeichern?
Andy Grunwald (00:21:02 - 00:21:07)
Ja, könntest du, doch da gibt es so ein anderes Problem und zwar nennt sich das JSON.
Andy Grunwald (00:21:11 - 00:22:21)
Ja, das folgendermaßen. Twitter ist ja eine Plattform, die wird ja sehr viel genutzt. Und zwar hat jeder Tweet eine ID inzwischen. Und ich weiß gerade nicht, wie viele Stellen die Twitter-ID hat. Auf jeden Fall mehr als 16 Stellen. Und jetzt ist es in JavaScript so, hatten wir gerade gesagt, dass der Number-Datentyp einen MaxSafeInteger-Wertebereich hat von 16 Stellen. Alles drüber ist so ein bisschen ungenau und das Problem ist, wenn du dann mit der ID rechnest, dann kriegst du ein anderes Resultat raus, was dann auf eine andere Twitter-ID lenkt, was dann einfach ein anderer Tweet ist. Relativ doof. Das hat die Twitter-API dazu bewegt, ihre Tweet-IDs einmal als Integer rauszugeben, aber auch als String-Datentyp. Das bedeutet, quatschst du mit der Twitter-API, kriegst du die Tweet-ID zweimal in zwei verschiedenen Formaten. Und das haben sie nur gemacht, damit JavaScript die Tweet-IDs lesen kann. Also wenn du mit JavaScript und der Twitter-API arbeiten musst, dann nutze bitte die String-Repräsentation der Tweet-ID. Jetzt könnte man fragen, Moment mal, du hast ja gerade von dem Java-Skript-Datentyp BigInt gesprochen. Warum nutzt denn Twitter nicht BigInt? Ja, sagen wir, es ist kompliziert.
Wolfi Gassler (00:22:21 - 00:22:25)
Funktioniert der überhaupt überall mittlerweile? Kann ich den in jedem Browser verwenden?
Andy Grunwald (00:22:26 - 00:22:31)
Wenn du mit dem Internet Explorer 6 unterwegs bist, glaube ich nicht, aber ich weiß es nicht. Sollen wir mal Can I Use checken?
Andy Grunwald (00:22:33 - 00:22:51)
Sieht auf jeden Fall sehr grün aus, würde ich schon sagen. BigInt kann man relativ gut überall nutzen, in jedem Browser. Aber nur weil wir JavaScript verwenden, heißt das nicht, dass wir im Browser sind, Wolfgang. Denn auch serverseitig gibt es da ein Problem, weil da gibt es dieses tolle Format, das nennt sich JSON, JavaScript Object Notation.
Wolfi Gassler (00:22:51 - 00:22:56)
Was hat denn jetzt JSON mit Server zu tun? Du kannst JSON auch im Client verwenden, lieber Backend-Developer.
Andy Grunwald (00:22:56 - 00:23:38)
Das ist richtig, das ist richtig. Es ist nun mal so, dass die Twitter-API als Response JSON gibt. Und die JSON.Parse-Funktion kann kein BigInt. Zumindest nicht im JavaScript. Das bedeutet, auch wenn du die Integer-Repräsentation der Tweet-ID verarbeiten möchtest, kriegst du es im JavaScript aktuell nicht hin. Das TC39-Komitee, das ist das Komitee, was sich halt um die Sprache, ECMAScript, JavaScript und so weiter kümmert, die arbeiten gerade dran, dass der JSON-Parsing-Standard auch Support für BigInt bekommt. Und das hoffentlich führt dazu, dass wir endlich große Zahlen in API-Responses dann auch als große Zahlen verarbeiten können und nicht als Strings.
Wolfi Gassler (00:23:39 - 00:24:51)
Und da ist ja schon wieder das Problem, wenn du sagst, diese JSON-Parse-Funktion kann das nicht. Das ist ja bei JavaScript auch das Problem, dass man das gar nicht sagen kann, weil es kommt ja darauf an, was für eine JavaScript-Implementierung das ist, was für Engine das Ganze ist, weil es kann ja wieder jede Engine selbst definieren oder programmieren, sollte sie natürlich nicht und die halten sich natürlich schon an die Standards. Aber theoretisch, dadurch du nicht den einen Compiler hast wie bei Go, Wobei bei Go gibt es vielleicht auch mittlerweile mehrere Compiler, keine Ahnung, aber es gibt wahrscheinlich den Standard-Compiler, den jeder verwendet. Und dort ist es natürlich relativ einheitlich. Bei JavaScript läufst du immer in einer anderen Engine, in einem anderen Browser und kannst damit gar nicht wissen, dass das überall funktioniert. Und das ist ja immer so diese Schwierigkeit mit JavaScript. Und bei JSON sind wir dann auch noch außerhalb von JavaScript. JSON-Implementierungen gibt es in jeder Sprache, in Python, in Go. Und wie die dann agieren und funktionieren, ist ja wieder eine andere Sache. Das ist immer super schwierig bei diesen allgemeingültigen Standards und die vielleicht auch gar nicht hundertprozentig definiert sind, weil keine Ahnung, ob jetzt JSON an sich das Format genau definiert, was das für ein Datentyp überhaupt ist und wie viel Bit der hat oder Byte der hat zur Repräsentation.
Andy Grunwald (00:24:52 - 00:26:16)
Ja, ich spreche natürlich eins zu eins von der Umsetzung des Parsing-Standards. Also wie sollst du welchen Wert betrachten und behandeln? Und auch die Runtime-Engines von JavaScript in den Browsern vereinheitlichen sich da mehr und mehr. Also die V8 von Google, die ist ja mehr und mehr in diversen Browsern drin oder WebKit oder ähnliches. Aber auf jeden Fall ist es auch so, dass, wir hatten ja vorhin gesagt, JavaScript selbst hat keinen Integer-Datentyp, sondern nur einen Number-Datentyp, was dann wiederum ein Float ist. Das führt natürlich dazu, dass JSON-Parser in anderen Sprachen Zahlen ebenfalls so behandelt, als wenn sie Floats wären. Das macht ja schon irgendwie Sinn, weil JSON heißt ja JavaScript Object Notation. Also scheint es ja schon sinnvoll, die Werte so zu dekodieren, wie es JavaScript machen würde. Das führt aber auch dazu, dass der Python-Build in JSON-Parser zum Beispiel Probleme mit großen Integer bekommt, weil wenn diese große Zahl aus JSON geparst wird in eine native Python-Repräsentation, dann wird sie intern als float behandelt und nicht als Integer. Und das führt natürlich dann bei großen Zahlen zu Ungenauigkeiten, wie der Wolfgang schon sagte. Also alles schon sehr, sehr schwierig und da muss man ganz, ganz, ganz, ganz genau aufpassen, wie die JSON-Parsing-Implementation sich da verhält. Also im Endeffekt verhält sich die JSON-Parsing-Repräsentation richtig, so wie es JavaScript machen würde, wenn man JSON nutzen würde.
Wolfi Gassler (00:26:17 - 00:26:50)
Man muss eben als Programmierer in einer anderen Programmiersprache, wenn man zum Beispiel mit JSON hantiert, eben auch wissen, was da dahinter steckt, damit man diese ganzen Datentypen und Nummern richtig verwendet, wenn man zum Beispiel in JSON importiert. Und da traue ich mich fast zu wetten, dass das ganz viele Nicht-JavaScript-Entwickler oder sogar JavaScript-Entwickler nicht so am Schirm haben. Und ehrlich gesagt, ich hatte das auch nicht am Schirm. Ich habe es mal irgendwo gelesen, aber das vergisst man wieder und im Alltag braucht man das ja nie, bis man dann in den Bug reinläuft. Also in einem Bug, den man dann selber produziert hat aufgrund der Repräsentation von Nummern.
Andy Grunwald (00:26:50 - 00:27:03)
Und wenn wir schon bei Floats sind, beziehungsweise von Integerwerten, die intern als Fließkommazahlen repräsentiert werden, dann kommt immer ein sehr prominentes Beispiel in meinen Kopf und zwar sind das Währungsbeträge.
Wolfi Gassler (00:27:04 - 00:27:15)
Was ist das Problem mit Währungen? Bei mir sind es immer sehr kleine Zahlen, die da auf meinem Bankkonto stehen, da gibt es keine Rundungsfehler. Aber Andi, in deinem Fall, wenn man so ganz große Zahlen hat, was gibt es da für Probleme?
Andy Grunwald (00:27:15 - 00:27:36)
Die Größe der Zahl ist erstmal irrelevant, denn auch bei 10,52 Dollar kann es zu Rundungsfehlern kommen, was dann im Endeffekt zu 10,51 Dollar oder 10,53 Dollar resultiert. Jetzt sagst du, das ist ja nur ein Cent. Frag doch mal das Finanzamt oder frag doch mal die Anzahl der Transaktionen, die durch deinen Shop gehen, wie relevant denn dieser eine Cent wird.
Wolfi Gassler (00:27:36 - 00:30:18)
Ich habe mal vor Jahrzehnten ist es schon fast ein Shop programmiert, also schon mit einem Shop-System, aber ich habe da customised einen Preisberechner rein programmiert, der Gewichtsware berechnet. Also so, was man zum Beispiel aus dem Supermarkt kennt oder so, wenn du Obst abwiegst, dann gibt es da einen Kilopreis und dann je nach Gewicht wird das dann umgerechnet. Also sowas in der Richtung, so Gewichtsfahre. Und ich hatte da wirklich dieses Problem, ich habe diese Preise von der Schnittstelle bekommen. Da fängt sich schon mal wieder an. War das JSON? Was ist das für ein Format? Ihr habt das von irgendeiner Schnittstelle bekommen, habt dann angefangen herumzurechnen selbst, diese Gewichtspreise herumzurechnen und habt es dann wieder mit einer anderen API abgleichen müssen bzw. habt ihr dann wieder Bestätigungen zurückbekommen für einen Auftrag usw. Und ich bin fast verzweifelt mit dem ganzen Ding, weil diese Rückmeldungen von einer Bestätigung von einem Auftrag waren wieder andere Preise, weil dieses System irgendwie anders gerechnet hat. Das heißt, da war dann statt 3,50 Euro habe ich plötzlich 3,52 Euro zurückbekommen, weil das System irgendwie anders gerechnet hat. Und wenn du viel dividierst oder multiplizierst, dann hast du genau diese ganzen Ungenauigkeiten und Probleme, Und hast dann wirklich bei so einem kleinen Betrag auch unter Umständen 2 Cent Unterschied, der natürlich schon relevant ist. Und wenn du mit verschiedenen Systemen zusammenarbeitest, dann hast du auch keinen Einfluss darauf. Also das ist extrem schwierig, da wirklich einen guten Ansatz zu finden, wenn du mit verschiedenen Systemen arbeitest. Wenn du natürlich nur selbst das System baust, dann kannst du bei Währungen eigentlich recht easy damit umgehen, indem du keine Floats verwendest, also keine 3,50€ als 3,50€ in dem Float oder Double abspeicherst, sondern das Ganze in den Integer umwandelst. Das heißt die 3,50€ werden umgewandelt in 350 und die 350 speicherst du dann als Integer ab, beziehungsweise im Idealfall oder sinnvollerweise rechnest du das dann auf auf Cent um, weil es ja eine sinnvolle Größe ist, oder vielleicht auf Zehntelcent, wenn du unbedingt willst. Das heißt, du multiplizierst das mal 1000 und hast dann 3500 z.B. für 3,50€ und dann arbeitest du nur in dem Integer-Feld und hast weniger Probleme, solange du nicht dividierst. weil da kommst du sofort wieder in den Gleitkommabereich rein und wenn du jetzt zum Beispiel irgendwelche Gewichtswaren berechnest und dir irgendwie einen Grammpreis oder so über Division ausrechnest, dann hast du schon wieder ein Problem. Also sobald du eine Division drin hast, bist du sofort wieder weg mit der Genauigkeit. Aber üblicherweise im Bankwesen oder wenn du mit Geld arbeitest, hast du ja nur Plus und Minus im Idealfall und dann bist du sicher, solange du im Integer-Bereich bleibst.
Andy Grunwald (00:30:18 - 00:30:26)
Und warum multipliziere ich 3,50 Euro mit 1000 und nicht mit 100? Also warum nehme ich eine dritte Nachkommastelle dazu?
Wolfi Gassler (00:30:27 - 00:30:55)
Dadurch, wenn du zum Beispiel dividierst oder die Preise jetzt zum Beispiel auf irgendein Gewicht umrechnest, hast du dann eine höhere Präzision und kannst damit noch eine höhere Präzision erreichen. Und meines Wissens, Banken arbeiten auch mit Zehntelcent, wenn ich das jetzt richtig im Kopf habe. Falls jemand im Bankwesen arbeitet, bitte gern um Rückmeldung. Aber hat eben mal so im Kopf, dass man da unter Umständen noch eine höhere Präzision haben will, um da auch nochmal gewisse Rundungsfehler zu vermeiden.
Andy Grunwald (00:30:55 - 00:31:27)
Besonders bei der Handhabung von Währungsbeträgen merkt man halt, dass Gleitkommararithmetik Rundungsfehler verursachen kann. Eine Gleitkommarzahl ist eine annähernde Darstellung eines Dezimalwerts, der binär gespeichert wird und somit ist es nicht möglich 0,1 präzise und exakt darzustellen, was dann natürlich speziell im Bereich Geld eine sehr schwierige Geschichte wird. Besonders wenn man Millionen von Transaktionen hat, weil dann kommen nämlich, dann multipliziert sich halt auch ein Rundungsfehler-Cent schon sehr hoch.
Wolfi Gassler (00:31:27 - 00:32:11)
Im Datenbankbereich hat sich das übrigens so durchgesetzt, dass man dann einen eigenen Datentyp hat, der Decimal oder Dezimal heißt und da gibt man wirklich an, wie viele Stellen will man vor diesem Komma und wie viele Stellen will man nach dem Komma speichern und dann werden die Zahlen wirklich als Integer-Zahlen jeweils abgespeichert. Das heißt, ich kann da genau selbst definieren, was für eine Genauigkeit will ich haben. Ich kann dieses Komma auch verschieben. Das heißt, wenn ich weiß, dass ich ganz kleine Zahlen immer habe und vor meinem Komma eigentlich immer nur zwei Zahlen, zwei Ziffern habe, dann kann ich das dort auch drin definieren und kann mir hinten dann wieder eine höhere Genauigkeit rausholen. Also der wandelt das dann intern sozusagen wieder auf eine, wenn man so will, auf eine Integer-Repräsentation, auf eine Ganzzahl-Repräsentation um.
Andy Grunwald (00:32:11 - 00:32:29)
Also die Faustregel ist hier niemals eine Währung als Float in der Datenbank abspeichern, nämlich die große Internet-Empfehlung ist, dass man sie als Dezimal mit vier Nachkommastellen präzise abspeichert, weil wenn man nämlich die Nachkommastellen definiert, dann kommt es da auch nicht so zu Rundungsfehlern, weil man die ganze Sache begrenzt.
Wolfi Gassler (00:32:30 - 00:32:49)
Ich glaube sogar, dass Float und Double mittlerweile auch anders gehandhabt wird, in MySQL zumindest, und die auch in so eine Repräsentation übergehen. Ich glaube, man kann die klassische Gleitkomma-Darstellung, bin mir gar nicht sicher, ob man die überhaupt noch so machen kann in der MySQL-Datenbank. hat sich auch einiges geändert.
Andy Grunwald (00:32:49 - 00:32:53)
Der MS-SQL-Server von Microsoft hat sogar einen eigenen Datentypen, Money und Small Money.
Andy Grunwald (00:32:56 - 00:33:00)
Anscheinend die Geldbeträge, mit denen du hantierst, Wolfgang. Small Money.
Andy Grunwald (00:33:02 - 00:33:14)
Also laut Internet wird die ganze Sache dann aber auch als BigInt auf der Festplatte gespeichert. Deswegen sagt man auch generell, okay, nutzt mal ein Dezimal, 19.4, und dann seid ihr da einigermaßen.
Wolfi Gassler (00:33:15 - 00:35:30)
Und was übrigens auch noch so ein großes Problem ist und was ich zuerst erwähnt habe, auch wenn man mit anderen Systemen arbeitet. Ich hatte gerade gestern eine Episode von unserem befreundeten Index-Out-of-Bounds-Podcast gehört und die haben gesprochen über fremden Code und wie man mit fremden Code arbeitet und wie schwierig das ist. Und auch da wieder, Libraries sind ja auch fremder Code, wenn man so will, aber auch wenn man mit anderen Leuten zusammenarbeitet. Das ist natürlich halt extrem relevant, wenn es dann um solche Dinge geht. wie handhabt denn dieser fremde Code oder nur diese Funktion diese Datentypen und welche Berechnung kommt da zum Einsatz. Also in Shop-Systemen ist es teilweise so, dass du gar kein Plus und Minus verwendest, sondern es gibt eigene Funktionen in dem Shop-System, die Add oder Sub oder so heißen und da kannst du dann zentral festlegen, wie mit Datentypen umgegangen wird, damit du das eben zentral hast und überall gültig hast. Und wenn du mit anderen Leuten zusammenarbeitest oder mit anderem Code, mit anderen Libraries, dann musst du dir natürlich sicher sein, was passiert da. Und wenn wir dann in Skriptsprachen sind, in JavaScript, PHP oder was auch immer, dann werden da ja auch Datentypen einfach so hin und her konvertiert, ohne dass man was weiß, umgecastet. Und da läuft man natürlich dann auch gern in Probleme. Du irgendeine Library verwendest und du denkst dir, die macht irgendwie coole Berechnungen mit deinem Preis und da geht es um Euro und du verlierst dann die Präzision in dieser Library, dann hast du natürlich auch ein Problem und das musst du dir auch bewusst sein. Oder wenn du zum Beispiel in SQL was berechnest, so wie ich am Anfang erwähnt habe, wenn du eine Division in SQL machst, was wird denn dann da verwendet für diese Division? Wird dann float, double, new decimal, was für ein decimal verwendet? Also auch da, das läuft ja transparent im Hintergrund ab, ohne dass man das mitbekommt. Und da können sich extrem leicht Fehler einschleichen. Aber man kann es natürlich auch zum Vorteil verwenden. Ich weiß nicht, ob du diese Geschichte kennst. Diese Entwickler, die sich dann im Bankenbereich immer diese Rundungsfehler selber abgesaugt haben, da wo gerundet wird, und haben sich dann das auf ihr eigenes Konto überwiesen, was die Bank so verliert durchs Runden. Und am Ende sind die mit sehr, sehr viel Geld ausgestiegen, weil sie sich einfach diese mini, mini, mini Beträge sich einfach rausgeholt haben aus dem System. Können wir gern verlinken, wenn ich die Geschichte nochmal finde.
Andy Grunwald (00:35:31 - 00:35:46)
Wolfgang, jetzt testen wir auch mal dein Wissen. Quizfrage. Was passiert denn, wenn ich auf einem Integer, der kein Vorzeichen repräsentiert, also unsigned Integer, ein 0-1 mache, wenn ich versuche in den negativen Bereich zu gehen, bei einem nicht vorzeitig behafteten Integer?
Wolfi Gassler (00:35:46 - 00:35:55)
In welcher Programmiersprache oder SQL oder Excel? Wo mache ich denn das? In der Bash? Kann Bash überhaupt zahlen? Anderes Thema.
Wolfi Gassler (00:35:56 - 00:36:39)
Ja, das ist die Informatikerantwort. Wenn du keine Ahnung hast, dann stellst du mal eine Gegenfrage, in was für einem Kontext man sich denn da befindet. Das ist immer ganz, ganz wichtig. Du bist ja auch so ein Kontext-Fan. Darum kann man sich immer auf die Programmiersprache rausreden. Weil ich bin mir fast sicher, dass das jede Programmiersprache anders handhabt. Also wenn man das in PHP macht, gut, da gibt's kein Unsigned, das ich fix setzen kann, höchstwahrscheinlich. Da würde mir wahrscheinlich irgendwas umkommodieren, dieser Interpreter, und dann irgendein Mull-Asch-Bucken. Wenn du das in C machst, ganz klassisch, da bekommt man dann wahrscheinlich irgendeine ganz große Zahl, minus 40 Millionen irgendwas. Da gibt's wahrscheinlich sicher irgendeinen Underflow, Overflow, irgendeinen Flow, vermute ich mal. Das sind so die Klassiker, wo man sich selber ins Knie schießt in C.
Andy Grunwald (00:36:39 - 00:36:44)
Also was ganz klar ist, man bekommt auf keinen Fall nicht minus 1 raus, weil man hat ja keinen Minuswertebereich.
Wolfi Gassler (00:36:44 - 00:36:53)
Vielleicht nur zur Vollständigkeit. Was ich mir erwarten würde, ist ein Fehler. Das heißt, dass ich irgendwo einen Fehler bekomme, hey, ich mach da was Unerlaubtes. Das wäre ja eigentlich das Schöne.
Andy Grunwald (00:36:53 - 00:37:22)
Ja, und da kommen wir jetzt in diesem Es-ist-kompliziert-Bereich. Also, es ist wirklich so, wenn du bei einer Sprache unterwegs bist, die Unsigned-Integer-Datentypen hat, das ist ja die erste Baustelle, dann kriegst du bei einem 0-1 in der Regel den Overflow und es fängt dann ganz oben wieder an. Ja, so nach dem Motto, du bist ja erst in der Schlange und stellst dich bei der Achterbahn ganz hinten wieder an. Somit bist du der letzte in der Schlange, somit kriegst du den höchsten Wertebereich, die höchstmögliche Zahl aus dem Wertebereich. Jetzt ist es doch nun mal so.
Wolfi Gassler (00:37:22 - 00:37:31)
Super, jetzt denke ich ständig an diese Achterbahn und ich verstehe die Lösung nicht einmal mehr. Also Achterbahn ist definitiv ein schlechtes Beispiel, um mir das zumindest zu erklären.
Andy Grunwald (00:37:32 - 00:37:41)
Also wenn du auf einem Uint32, also auf einem Unsigned Integer mit 32 Bit ein 0-1 machst, dann ist das Ergebnis eine 10-stellige Zahl.
Andy Grunwald (00:37:44 - 00:37:50)
Theoretisch ja, oder halt genau das Maximum. Aber das ist dieser Off-by-one-Error, von dem wir immer reden.
Andy Grunwald (00:37:53 - 00:38:12)
Aber der Clou ist ja, hat deine Programmiersprache überhaupt einen Unsigned Integer? Weil, das Lustige ist eigentlich, Python zum Beispiel hat keine built-in Unsigned Integer Datentypen. Java hat auch keine built-in Unsigned Integer Datentypen. Es gibt eine Integer Class, die kann das. aber der native datentyp ist nicht existent.
Wolfi Gassler (00:38:12 - 00:38:22)
Und du bekommst dann auch einen underflow wenn du bei java sowas machst also es gibt gar keinen unsigned das heißt du kannst gar nicht zwingend machen du bekommst dann trotzdem den minuswert ganz genau.
Andy Grunwald (00:38:22 - 00:38:49)
Ruby ist ganz geil weil ruby Einfach zwischen den Datentypen hin und her konvertiert und der ganze Prozess ist sehr transparent. Das bedeutet auch wenn du sagst du möchtest 32 oder 8 Bit Integer und du packst da eine ganz große Zahl rein, dann konvertiert der intern automatisch zu einer Big Num. Ich weiß nicht ganz ob das geil ist oder ob ich das schrecklich finde. Ich habe mir da noch keine Meinung drüber gebildet. Es ist auf jeden Fall so ein bisschen Magie wie Ruby halt auch so ist, finde ich.
Wolfi Gassler (00:38:49 - 00:39:29)
Man muss ja auch dazu sagen, warum das Ganze meistens so schwierig ist und keine Fehlermeldungen ausspuckt, ist da, dass wir da über native Datentypen sprechen, die meistens einfach nicht gecheckt werden, weil es sind halt sehr rudimentäre Operationen und wenn du da noch irgendwelche komplizierten Checks einbaust, dann kann es natürlich sein, dass du auch Performance-Probleme bekommst. Aber theoretisch wäre es ja kein Problem, das einzubauen. Und wie du richtig sagst, wenn du eine Klasse machst, die das alles checkt, könntest du das natürlich genauso machen. Aber du bläst deine Sprache natürlich schon extrem auf damit. Und ich vermute mal, ohne jetzt ein Sprachdesigner zu sein, dass das schon ein Grund ist, warum das teilweise so dreckig, würde ich mal sagen, gehandhabt wird.
Andy Grunwald (00:39:29 - 00:39:42)
Du kannst dich halt, wenn du eine Sprache designst, auf den Standpunkt stellen, okay, der Programmierer muss schon wissen, was er da tut. Deswegen, du kannst halt die Arbeit auf den Programmierer abwälzen. Und genau das haben sie bei C gemacht. Wenn du C programmierst, der C wälzt.
Wolfi Gassler (00:39:42 - 00:39:45)
Alles auf die auf die Programmierer ab. Da gibt es überhaupt nichts.
Andy Grunwald (00:39:46 - 00:39:55)
In der C-Programmierer-Sprache, Wird die ganze Thematik einfach mitgehändelt? Das bedeutet, du merkst gar nicht, dass du einen Overflow hast. Und das kann natürlich zu richtigen Bugs führen.
Wolfi Gassler (00:39:55 - 00:40:01)
Also es wird nicht gehändelt, sondern es macht halt einfach nichts. Es zählt nach unten und du bekommst halt eine große Zahl oder so.
Andy Grunwald (00:40:01 - 00:40:05)
Ja, also es wird halt schon gehändelt, weil das Programm läuft einfach weiter. Es crasht nicht.
Wolfi Gassler (00:40:05 - 00:40:09)
Ja, es ist halt nach, so wie es definiert ist mathematisch, wird einfach durchgezogen, ja.
Andy Grunwald (00:40:10 - 00:40:55)
Ja, ob es jetzt im ursprünglichen C-Standard als so soll das sein definiert ist, weiß ich jetzt nicht. Auf jeden Fall gibt es bei CLang, beim CLang-Compiler jetzt ein Compiler-Flag, was unter der Kategorie Undefined Behavior geführt wird. Und da kannst du sagen, okay, wenn du mein C-Programm kompilierst und wir haben ein Integer Under oder Overflow, dann lass das C-Programm bitte abstürzen. Der Grund ist, dass es nicht undefined behavior ist, aber es ist sehr oft nicht gewollt. Also ich kenne keinen Softwareentwickler, der sagt, okay, pass mal auf, ich möchte jetzt hier, dass mein Integer overflowed oder underflowed. Aber jetzt haben wir hier über dieses Integer underflow und overflow gesprochen, jetzt jeder denkt sich, ach Quatsch, mit so vielen Zahlen arbeite ich gar nicht. Wo kommt denn der ganze Quatsch mal in der Realität vor? Wo hast du sowas schon mal gesehen oder wo denkst du, kriegen wir nochmal richtig Probleme?
Wolfi Gassler (00:40:56 - 00:41:14)
Ja, jetzt könnte man natürlich wieder dieses Jahr 2038-Problem erwähnen, das wir eh schon ständig erwähnt haben und was wahrscheinlich mittlerweile eh jeder kennt, der irgendwie mit Unix-Timestamps zu tun hat, dass im Jahr 2038 die Unix-Timestamps überlaufen, wenn man 32-Bit speichert und dann ein großes Problem haben wird. Aber, Andi, kennst du das 2036-Problem?
Andy Grunwald (00:41:16 - 00:41:20)
Ja, kenne ich. Und ich kannte es vor der Vorbereitung des Podcasts auch noch nicht.
Wolfi Gassler (00:41:20 - 00:41:27)
Ja, ich natürlich auch nicht. Ich habe es nur in unseren Notes ganz intelligent, ohne eine Ahnung zu haben, was eigentlich dahinter steckt.
Andy Grunwald (00:41:27 - 00:41:58)
Das nochmal zum Recap. Das Jahr 2038 Problem hat mit der UNIX-Zeit zu tun, mit dem UNIX-Timestamp. Der beginnt am 01.01.1970. Die Speicherung dessen in einem 32-Bit-Integer führt zu einem Integer Overflow am 19. Januar 2038, was dann die Zeit durch den Overflow auf den 13. Dezember 1901 zurückführt, wenn man das jetzt wieder in Zeit berechnen würde. Jetzt gibt es aber auch noch das Jahr 2036 Problem.
Wolfi Gassler (00:41:58 - 00:42:04)
Warum eigentlich 1901? Müsste es nicht 1970 sein? Die Unix Timestamp fängt ja 1970 zählen an.
Andy Grunwald (00:42:05 - 00:42:20)
Gut aufgepasst Wolfgang, aber wir reden von einem Signed Integer 32. Das bedeutet, wir gehen vom Maximum des positiven Wertebereichs ins Maximum des negativen Wertebereichs und deswegen sind wir bei Minus eine ganz lange Zahl.
Wolfi Gassler (00:42:20 - 00:42:44)
Das heißt ungefähr kann man in einem Range 70 Jahre abbilden, oder? Das heißt 70, 140, 2038, das kommt ungefähr hin. Also im Minusbereich 70 Jahre und im positiven Bereich 70 Jahre. Wenn man das jetzt aber, also man kann es nicht rückwirkend machen, aber wenn man, doch man könnte eigentlich definieren in Zukunft, wenn der Bereich Minus ist, dann shiftet das Ganze, dann könnt ihr nochmal 70 Jahre rausholen.
Andy Grunwald (00:42:44 - 00:42:51)
Das ist korrekt, dafür ist aber eine Softwareänderung notwendig und da kannst du das Problem gleich fixen und dann ins 64 nehmen, oder?
Wolfi Gassler (00:42:51 - 00:42:59)
Ich bin gegen diese guten Lösungen, die dann langfristig laufen. Ich würde da nochmal 70 Jahre herausholen. Die Mainframes machen das sicher auch so.
Andy Grunwald (00:42:59 - 00:43:13)
Aber das viel spannendere Problem ist das 2036 Problem. Das 2038 Problem haben wir gerade erklärt und ist groß und breit in der Industrie vertreten. Das Jahr 2036 Problem ist glaube ich deutlich subtiler und zwar dreht sich das um Das Zeitsynchronisationsprotokoll NTP.
Wolfi Gassler (00:43:13 - 00:43:18)
Verwende ich auf allen meinen Servern natürlich. Hätte es dann 2036 aufzuarbeiten?
Andy Grunwald (00:43:18 - 00:43:50)
Die Startzeit vom Zeitsynchronisationsprotokoll NTP ist nicht der 01.01.1970. Die Startzeit ist der 01.01.1900. In älteren NTP-Implementierungen wurde was verwendet? Ein Integer 32. Das bedeutet, auf allen Devices, wo eine ältere NTP-Version installiert ist, wird nochmal ein Integer 32 gearbeitet, was bei der Zeit 01.01.1900 anfängt zu zählen. Der Überlauf ist am 07.02.2036.
Wolfi Gassler (00:43:50 - 00:43:53)
Aber von welchen Implementierungen sprechen wir da, von wirklich alten?
Andy Grunwald (00:43:53 - 00:44:13)
Mit hoher Wahrscheinlichkeit sind moderne Cloud-Server nicht betroffen, sondern eher Embedded-Systeme, die in irgendwelchen Stahlwerken oder ähnliches verbaut werden, die seit Ewigkeiten nicht geupdatet werden. Wir reden hier von den Computern, Chipsystemen, die in irgendeiner Ecke von irgendeiner großen Firma stehen und die Staub fangen und die einfach laufen, die keiner auf dem Schirm hat.
Wolfi Gassler (00:44:13 - 00:44:26)
Und die springen dann auf 1900 zurück, demnach, oder? Wenn sie dann einen Overflow haben. Die Frage ist, ob dem Stahlwerk das nicht egal ist. Die leben vielleicht dann einfach 1900 weiter. Also dieses Ding kommuniziert mit anderen Systemen. Dann wird es schwierig.
Andy Grunwald (00:44:26 - 00:44:40)
Die springen auf den 1.1.1900 zurück, weil sie eine nicht vorzeichenbehaftete Integer 32 Implementierung genutzt haben und keine vorzeichenbehaftete wie bei dem Jahr 2038 Problem. Ja, spannende Zeiten kommen auf uns zu, würde ich sagen.
Andy Grunwald (00:44:42 - 00:44:51)
Und wenn wir gerade bei Zeit sind, wie oft würdest du dir wünschen, dass Zeit rückwärts laufen kann, Wolfgang? Dass du Sachen nochmal erleben kannst, dass du Sachen korrigieren kannst.
Wolfi Gassler (00:44:52 - 00:44:54)
Ganz allgemein oder wie oft ich mir das heute schon gewünscht hätte?
Andy Grunwald (00:44:54 - 00:44:57)
Kannst du eigentlich eine Frage beantworten ohne eine Gegenfrage zu bestellen?
Wolfi Gassler (00:44:57 - 00:45:04)
Siehst du, jetzt wäre ich gern wieder in die Vergangenheit gereist und hätte dir eine dumme Frage gestellt noch, eine andere. Aber warum? Kannst du das?
Andy Grunwald (00:45:04 - 00:45:14)
Ich kann es nicht, aber in der IT passiert das öfter. Und die meisten Softwareentwickler wissen das nicht oder bauen das nicht ein. Wolfgang, erklär uns doch mal bitte, wann kann die Zeit rückwärts laufen?
Wolfi Gassler (00:45:15 - 00:45:21)
Ja, dein Beispiel mit dem 2036-Problem war ja im Prinzip schon rückwärts laufen. Wir springen da wieder auf 1900 zurück, oder?
Andy Grunwald (00:45:21 - 00:46:00)
Ja, das ist richtig. Das ist aber eine andere Problemklasse. Da reden wir über Integer Overflow. Und man muss ja auch sagen, okay, wenn die Zeit rückwärts laufen kann, das ist nicht wirklich ein Problem mit Zahlen, sondern es wird halt oft in der Programmierung genutzt, sondern es ist eher ein Problem mit der realen Implementierung, was man da benutzt. In klassischen Implementierungen ist es eigentlich so, dass man die aktuelle Zeit erhebt, um irgendwas zu messen. Zum Beispiel die Zeit zwischen zwei Events oder... Man nutzt die Zeit, auf jeden Fall die aktuelle Zeit, also den 13. März, 9.53 Uhr, um diesen Wert mit irgendwas zu vergleichen. Und man geht von der Annahme aus, dass Zeit immer nur in eine Richtung geht, immer vorwärts.
Wolfi Gassler (00:46:01 - 00:46:04)
Also meine Zeit geht immer vorwärts. Ich weiß nicht, wie deine Zeit so ist.
Andy Grunwald (00:46:04 - 00:46:57)
Dann nutzt du, glaube ich, andere Computer oder lebst auf einer anderen Erde als ich. Weil Zeit läuft eigentlich nicht immer vorwärts. Und zwar gibt es die sogenannte Leap Second. Leute, die schon länger in der Informatik sind, haben davon schon mal gehört. Leute, die irgendwie erst neuerdings mit modernen Linux-Körneln und so weiter und so fort zu tun haben, da ist das kein Thema mehr, weil Linux das inzwischen ganz gut abfangen kann. Aber früher hat das immer zu sehr komischen Problemen geführt. Was ist die Leap Second? Und zwar geht es um die Erde, um die Planeten auf denen wir leben. Die Erde bei ihrer Drehung um sich selbst benötigt im Mittel etwas länger als 24 Stunden. Das bedeutet die mittlere Eigenrotation der Erde ist zu langsam. Das bedeutet, zur Korrektur der Abweichung der koordinierten Weltzeit wird ab und zu mal eine Sekunde abgezogen, glaube ich, oder? Ja, abgezogen wird die, weil der liebst hängt.
Wolfi Gassler (00:46:57 - 00:47:53)
Ich vermute mal schon, aber meine Frage stellt sich ja immer, das ist ja nicht irgendwann, das ist ja nicht wahllos, dass da irgendwo eine Sekunde wegfällt, sondern das ist ja ein ganz genau definierter Zeitpunkt, wann diese Sekunde wegfällt. Das ist ja so wie im Februar. Du hast gemerkt, ich habe schon Februar gesagt, weil Februar würdest du schon wieder nicht verstehen, die österreichische Variante. Also der Februar, der hat ja hin und wieder einen Tag weniger in dem Schaltjahr. Und das ist ja eigentlich das gleiche Konzept. Und alle Date Libraries, wenn ich jetzt am 1. März ausrechnen will, wie viele Tage sind vergangen zum 27., dann bekomme ich da ja normalerweise das richtige Ergebnis raus. Das heißt, meine Date Libraries machen das mir schon richtig. Das heißt, eigentlich könnten die das ja bei der Sekunde auch machen, weil die ganz genau wissen, wo diese Sekunde verloren geht. Nur scheinbar machen das diese Date Libraries nicht, vermute ich mal. Also du bist wahrscheinlich in einem hochspezialisierten Bereich, vielleicht wird es da angewandt.
Andy Grunwald (00:47:53 - 00:48:29)
Also ich kenne keine Date Implementierung, die die Leap Second Events mit kalkuliert, aber das ist der eine Fall. Es gibt aber auch der andere Fall, dass einfach die Zeit auf deinem Server, auf dem du deine Software laufen lässt, einfach rekonfiguriert wird. Zum Beispiel, weil der NTP-Server, mit dem es kommuniziert, einfach nicht mehr gibt. Dann hast du auf jeden Fall einen Timedrift und irgendwann kommt der Admin vorbei und sagt, hey, die Zeit ist ja falsch, ich konfiguriere die einfach mal. Oder deine lokale Serverzeit ist auf deine Zeitzone eingestellt und deine lokale Serverzeit läuft nicht auf UTC. Aber dein Programm hat keine UTC-Umberechnung mit einprogrammiert und puffs, springst du einfach mal Zeit zurück, wenn du in UTC plus irgendwas bist.
Wolfi Gassler (00:48:30 - 00:48:41)
So und jetzt kommt dann meine Killerfrage, wenn du jetzt schon der Leap Second Spezialist bist. Was ist mit der Unix Timestamp? Die zählt ja in Sekunden. Zählt dir die Leap Second mit oder nicht?
Andy Grunwald (00:48:41 - 00:49:04)
Sehr gute Frage. Ich kenne die Antwort nicht ganz genau, aber ich würde mir sie mal herleiten. Da die Unix Timestamp ja eigentlich von der Wall Clock genommen wird, müsste der die eigentlich mitzählen. Weil die World Clock ist ja die aktuelle Zeit auf dem Server, in der wir uns bewegen. Und davon holt die sich die Unix Timestamp. Und wenn die aktuelle Zeit einfach eine Sekunde zurückspringt, dann müsste die Unix, der Unix Timestamp, die eigentlich mitzählen.
Wolfi Gassler (00:49:04 - 00:49:28)
Ihr habt natürlich in der Zwischenzeit schnell gegoogelt und so wie das aussieht, hat die Unix Timestamps keine Leap Seconds, weil sie immer gesyncht ist mit UTC. Also genau so, wie du es jetzt hergeleitet hast. würde ich mal als richtig bezeichnen, sonst wird sich unsere nette Community, unsere Hörerschaft garantiert bei uns melden, so wie mit 200 anderen Dingen, die wir wahrscheinlich heute irgendwie leicht fälschlich erwähnt haben. Wir freuen uns schon auf das Feedback.
Andy Grunwald (00:49:28 - 00:49:57)
Aber generell reden wir hier natürlich von einer gewissen Zeit, und zwar reden wir von der Wall Clock Time, die unerwartet zurück- beziehungsweise vorspringen kann. Und in der Programmierung, habe ich gerade schon erwähnt, wird sie oft genutzt, um die Dauer von zwei Punkten zu messen oder um alle x Sekunden einen Prozess zu starten, wie zum Beispiel einen Ticker oder einen Timer. Jetzt stellt sich natürlich die große Frage, Wolfgang, wie baue ich das denn richtig? Zeitberechnung, Datumsberechnung und Co. ist ja einer der drei, vier, fünf harten Elemente der Softwareentwicklung. Also wie schütze ich mich vor zurücklaufenden Uhrzeiten?
Wolfi Gassler (00:49:58 - 00:50:54)
Ja, du hast ja üblicherweise mehrere Möglichkeiten auf Zeit zuzugreifen und die klassische ist einfach auf die Systemzeit zuzugreifen, also wirklich auf die Zeit mit Datum und so weiter. Oder du kannst halt einfach mitzählen und die Monotonic Clock verwenden, die halt einfach am Server mitzählt. ohne zu wissen, was jetzt genau für ein Datum ist und die kannst du dann verwenden, die mitzählende Uhr, um zum Beispiel die Sekunden einfach zu berechnen, wenn dir die so kritisch wichtig sind natürlich. Für die meisten Anwendungsfälle muss man ja auch sagen, wenn du irgendwo eine leap second hast und eine second vergisst, dann wird halt die Funktion vielleicht einmal mehr aufgerufen oder sowas, weil eine Sekunde verloren geht. Aber sonst kannst du natürlich ganz hart einfach diese mitzählende Uhr verwenden und dann, wenn du sagst drei Sekunden, wird einfach hart drei Sekunden mitgezählt, egal ob sich die Systemzeit jetzt ändert oder nicht. Aber ich habe ehrlich gesagt dieses Ding noch nie verwendet. Wie greife ich da in der Programmiersprache drauf zu? Habe ich da eigene Funktionen wahrscheinlich, oder?
Andy Grunwald (00:50:54 - 00:51:28)
Jede Programmiersprache hat in der Regel in der Standard Library einen Zugriff auf die Monotonic Clock, ja. Das ist einer der häufigsten Fehler, die ich in Recruiting-Case-Studies sehe, weil viele Case-Studies haben ein Element drin, ja berechne mal bitte irgendwie die Dauer, wie lange ein HTTP-Request gedauert hat. Und für solche Anwendungsfälle sollte man in der Regel einen Montoni-Clock nutzen und nicht die aktuelle Zeit, weil die aktuelle Zeit kann zurück- und vorspringen. Und wenn man da ja Subtraktionen macht, Startzeitpunkt hat der tpRequest Endzeitpunkt und dann rechnet man Endzeitpunkt minus Startzeitpunkt, Startzeitpunkt minus Endzeitpunkt.
Wolfi Gassler (00:51:28 - 00:51:35)
Endzeitpunkt minus Startzeitpunkt meinst du? Die größere Zahl minus der kleineren Zahl, ganz einfach, sagen wir mal so.
Andy Grunwald (00:51:35 - 00:51:51)
Dann rechnet man Endzeitpunkt minus Startzeitpunkt und dann bekommt man einfach eine negative Zahl raus, bei einem vorzeichneten Behafteten Integer. Ja, das wird ja alles immer komplizierter, umso mehr mit Datentypen wir sprechen. Aber für solche Elemente nutzt man eigentlich eine Motonic-Clock und nicht die aktuelle Wall-Clock.
Wolfi Gassler (00:51:51 - 00:52:05)
Wobei ich würde das jetzt vielleicht nicht gerade als Fehler bezeichnen, aber wenn man natürlich viel damit macht, könnte man natürlich auf sowas umsteigen. Aber um jetzt mal schnell zu checken, wie lange dauert irgendwie ein Request oder so, finde ich, ist das schon ausreichend.
Andy Grunwald (00:52:05 - 00:52:13)
Meines Erachtens nach ist das ein Fehler, weil wenn du nämlich die Leap Second hast, dann hast du in deinen Dashboards überall mega Spikes in den Performance-Zeiten und Co.
Wolfi Gassler (00:52:13 - 00:52:28)
Ja, ich sag ja, wenn du das regelmäßig trackst, ist es sicher sinnvoll, aber wenn du jetzt nur mal schnell während der Entwicklung irgendwas testest oder so, dann ist es meiner Meinung nach komplett ausreichend. Wenn du natürlich ganze Statistiken fährst, kann das unter Umständen schon eine Auswirkung haben, das stimmt natürlich.
Andy Grunwald (00:52:28 - 00:52:35)
Und machen wir uns mal nichts vor, ob du jetzt time.now nimmst oder time.monotonic now, also es ist ja kein großer Unterschied.
Wolfi Gassler (00:52:35 - 00:52:45)
Ja, hast du mich überzeugt. Ich werde es in Zukunft verwenden. Jetzt habe ich wieder was gelernt, Andi, sehr gut. Also ich habe ganz viel gelernt, aber was ganz Konkretes, das ich in Zukunft machen werde.
Andy Grunwald (00:52:45 - 00:53:00)
Und das nächste Problem ist wirklich, wirklich skurril. Und zwar geht es um eine Modulo-Operation. Wolfgang, ich hatte dich am Anfang der Episode gefragt, wie viel Mathematik mit der Softwareentwicklung zu tun hat. Und du hast gesagt, essentieller Part. Wie oft verwendest du die Modulo-Operation in deinem Source Code?
Wolfi Gassler (00:53:03 - 00:53:16)
Ich glaube, der Klassiker ist eigentlich immer, wenn man durch Listen öfters durchläuft und einfach immer plus 1 macht, damit man dann wieder am Anfang von dem Array anfängt mit dem Index. Das ist, glaube ich, so der Case, der mir am öftesten unterkommt.
Andy Grunwald (00:53:16 - 00:53:20)
Das bedeutet in der Regel, dass du Modulo-Operationen mit zwei positiven Zahlen machst.
Andy Grunwald (00:53:21 - 00:53:23)
Hast du schon mal eine Modulo-Operation mit einer negativen Zahl gemacht?
Wolfi Gassler (00:53:24 - 00:53:47)
Ja, habe ich. Und ich habe mich auch damals gefragt, was denn da eigentlich rauskommt, weil ich mir selber nicht sicher war und habe es dann in der Programmiersprache eingegeben und gecheckt, was wirklich rauskommt. Weil man kann das Ganze ja positiv rechnen, einfach dieses Vorzeichen ignorieren im positiven Space rechnen und dann wieder dieses Minus davor schreiben. Oder im mathematischen Sinn, da kommt dann was anderes raus. Also das ist gar nicht so leicht zu definieren.
Andy Grunwald (00:53:48 - 00:54:18)
Und genau darum geht es bei dieser Problemklasse. Modulo-Operationen mit negativen Zahlen. Das ist eher eine Designentscheidung der Programmiersprache, wie die einzelnen Programmiersprachen ihre mathematischen Bibliotheken gestalten. Nehmen wir mal als Beispiel minus 13 Modulo 3. Entsprachen wie Python, Lua, Haskell, Ruby und Dart kommt dort 2 raus. Entsprachen wie JavaScript, Go, PHP, Rust und Scala kommt da minus 1 raus. Und ich so, hä? Warum ist das so, Wolfgang? Ist Mathematik nicht eigentlich idempotent? Müsste Modulo nicht eigentlich immer das gleiche rauskommen?
Wolfi Gassler (00:54:18 - 00:55:32)
Ja, die klassische Division mit Rest ist meines Wissens nur für positive Zahlen definiert. Und irgendwann hat man sich halt überlegt, okay, für negative Zahlen wäre das aber auch ganz praktisch. Und ich kann jetzt natürlich von zwei Seiten rechnen. Das heißt, wenn ich jetzt minus 13 Modulo 3 rechne, ich könnte jetzt natürlich sagen, ich multipliziere diese 3 mit minus 5. 3 mal minus 5 ist minus 15 und um jetzt auf minus 13 zu kommen, addiere 2, plus 2, dann bin ich bei minus 13. Ihr könnt das natürlich aber auch anders sehen, aber ich könnte natürlich auch sagen, ich multipliziere jetzt diese 3 von meinem Modulo 3 mit minus 4, dann bin ich bei minus 12. und dann addiere ich minus 1, bin ich auch wieder bei minus 13. Das heißt einmal kann die Lösung sein plus 2 oder einmal kann die Lösung sein minus 1. Das heißt je nachdem, ob ich erlaube, dass das Resultat von meiner Modulo-Operation positiv ist oder auch negativ sein kann. Und das sind die zwei Definitionen, die in den zwei Programmiersprachen Gruppen, würde ich es mal nennen, Aber glücklicherweise hat ja ein alter Bekannter, Donald Knuth, den ja jeder, der im IT-Bereich irgendwie unterwegs ist, eigentlich kennen sollte. Warum, Andi, sollte man den kennen?
Andy Grunwald (00:55:33 - 00:55:38)
Okay, warum sollte ich jemanden, der so heißt, kennen? Warum sollte ich Donald Knuth kennen?
Wolfi Gassler (00:55:43 - 00:55:51)
Und du hast ja da deine Bachelor-Arbeit Ghostwriten lassen irgendwo. Dieser Ghostwriter, hat der Word verwendet oder LaTeX?
Andy Grunwald (00:55:51 - 00:56:00)
Ich hab LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX.
Wolfi Gassler (00:56:00 - 00:57:53)
LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTeX, LaTe weil dieser Donald Knuth lebt übrigens noch irgendwie glaub einsam auf einer Insel und lässt sich die E-Mails nur ausgedruckt schicken einmal im Monat, ist ein sehr bekannter Informatikprofessor, hat auch den Turing Award bekommen und wofür er eigentlich bekannt ist, ist seine ganzen Definitionen, die er im Informatikbereich gemacht hat und unter anderem hat der auch den Modulu-Operator definiert, später mal, was dort rauskommen soll. Und nach dem richten sich eigentlich auch sehr viele Programmiersprachen. Und der hat auch noch tausende andere Definitionen rausgebracht. Da gibt's die große Buchreihe, The Art of Computer Programming, von ihm. Da schreibt er immer noch dran. Ich glaube, es gibt jetzt den neunten Band oder den achten Band. Und pro Band investiert er Jahre, um da alle Definitionen im Computerbereich reinzuschreiben und Problemstellungen und von Bäumen über Graphen. Da ist wirklich jeder Algorithmus drin in diesen Büchern. Super kompakt, sehr hardcore mathematisch definiert, muss man auch sagen. Also es ist so ein klassisches Werk, das man zumindestens an jeder Uni findet und man sollte da wirklich mal reinschauen, ist wirklich impressive, was da in diesen Büchern drin steht. Ist ein sehr schrulliger Typ, man kann auch so Vorlesungen noch online anschauen, die er macht regelmäßig. Ist natürlich auch schon in die Jahre gekommen, ist jetzt 85. aber hat wirklich viel bewegt im Computerbereich und unter anderem eben auch diesen Moduloot definiert. Und damit ist der Knut auf der Python-Lua-Haskell-Ruby-Tatseite, weil der Divisor, also das Vorzeichen vom Divisor, bestimmt das Resultat, also in dem Fall man rundet ab.
Andy Grunwald (00:57:53 - 00:58:30)
So, jetzt könnte man sich natürlich hinstellen und sagen, das ist doch gar kein Problem für mich, denn ich habe meine komplette Infrastruktur in Ruby. Dann ist das ja kein Problem. Oh, warte! Was ist da hinten? Ich glaube, die Microservice-Fraktion meldet sich gerade. Da habt ihr natürlich ein klitzekleines Problem, wenn ihr ziemlich viele Modulo-Operationen macht und verschiedene Microservices habt. Einen in Python, einen in Ruby, einen in Go, einen in JavaScript. Gegebenenfalls solltet ihr da mal ein bisschen tiefer reinschauen, weil das sind Bugs. Ich bin mir nicht sicher, ob man die wirklich gut tracken kann. Also, ich glaub, das sind so klassische Bugs, die jagt man vier Tage, und dann am Ende ist es irgendwie so ein Einzeichen-Change oder so was.
Wolfi Gassler (00:58:30 - 00:58:41)
Ihr habt mir gerade überlegt, was ein gutes Beispiel wäre, wo ich eine Minuszahl-Modulo rechne, aber mir ist ehrlich gesagt gerade kein Beispiel angefallen. Obwohl ich das mal irgendwann in der Vergangenheit verwendet habe, aber keine Ahnung mehr für was.
Andy Grunwald (00:58:41 - 00:59:04)
Natürlich gibt es noch viel, viel, viel, viel mehr Probleme mit Zahlen, mit Integern und Floats. Wir haben noch gar nicht über die Portabilität zwischen 32- und 64-Bit-Architekturen gesprochen. Was passiert eigentlich mit Fehlern bei impliziter und expliziter Typ-Konversation von String nach Integer? Wie werden verschiedene Basen, Oktal, Dezimal und so weiter, damit reingerechnet?
Wolfi Gassler (00:59:04 - 00:59:17)
Und eigentlich mein Lieblingsthema in Datenbanken, was verwende ich denn für einen Primary Key? Was sind UUIDs? Wie werden UUIDs abgespeichert? Wie mache ich dieses Ganze? Also da können wir glaube ich noch eine ganze Episode füllen mit diesen Themen.
Andy Grunwald (00:59:17 - 01:00:05)
Ja, und der Klassiker bei einem Typo ist bei einer IF-Abfrage UND UND versus einen einfachen UND, wie der Wolfgang schon initial in der Episode erwähnt hatte. Ganz klassische Bit-Operationen bei einem AND oder OR. Schneller getippt, sehr hart zu finden, würde ich sagen. Wenn ihr bis hierhin durchgehalten habt, Gratulation! Ihr habt die Vorlesung bestanden. Für alle Leute, die jetzt gerade schlafen, eigentlich sollten wir jetzt mal so einen Wecker-Klingelton irgendwie einspielen, damit die ganzen Leute wach werden. Vielen Dank für's dranbleiben. Ich hoffe, das war ein bisschen interessant für euch. Ich hoffe, wenn ihr irgendwie alte Industrieanlagen habt, die NTP-Implementierung haben, wäre cool, wenn ihr die bis Jahr 2036 fixen könntet. Ich wäre euch sehr dankbar, denn ich hoffe, das Stahlwerk hier nebenan im Duisburger Ruhrpott hat dadurch keine Explosionen oder ähnliches.
Wolfi Gassler (01:00:05 - 01:00:51)
Und sonst, wenn Leute jetzt eingeschlafen sind, auch kein Problem, weil ihr habt mittlerweile herausbekommen, dass es ganz viele Einschlaf-Podcasts gibt und die wirklich boomen. Insofern, wenn wir da eine gewisse Hörerschaft covern können, auch kein Problem. Bin ich offen für alles. Und sonst, wenn ihr irgendwelche Fehler gefunden habt, was ja fast bei so einem Thema immer der Fall ist, bitte schaut vorbei in unserer Community oder wenn ihr irgendwelche anderen Rückmeldungen habt, Erfahrungen, Ideen zu dem ganzen Zahlenkomplex. Lasst uns das wissen, lasst es die anderen Community-Mitglieder wissen. Wir haben da immer rege Diskussionen und freuen uns natürlich auch darüber, noch ein bisschen weiter zu diskutieren. Und wer in der Community vorbeischaut und Andi auf einen Fehler darauf hinweist, den er in der Episode gemacht hat, der bekommt von mir ein Bier.