Achthundertsiebenundneunzig

So nach und nach mache ich meine Software 64-bit-fähig. Man möchte nicht meinen, dass gerade bei den Assembleraufrufen doch einige Unterschiede sind, die zumindest ich nicht erwartet hätte.

So führe ich in manchen Programmen hochgenaue Berechnungen durch. Dafür habe ich früher gern die 80-bittigen Extended Gleitkommazahlen genommen.
Aber .. tja .. die gibt es nicht mehr auf 64-bit Prozessoren. Sondern höchstens noch die üblichen 64-bit Doubles. Und die werden nicht in die FPU, sondern in die 128-bit-MMX-Register geladen. Und zwar zwei Doubles pro Register.
Das mag ja optimiert sein für die Performance von irgendwelcher Parallelbearbeitung von Multimediastreams, aber für wissenschaftliche Berechnungen bietet es keinen Vorteil. Die Genauigkeit bleibt auf der Strecke.

Trotzdem wird 64 bit als der große Fortschritt dargestellt.
Dabei braucht 64 bit mehr Speicher, und ist – nach einigen meiner stichprobenartigen Messungen – wenn überhaupt, nur unwesentlich schneller als 32 bit, manchmal sogar langsamer.

Bei 32-bit-Programmen ist etwa die Berechnung des Sinus ein einziger Funktionsaufruf. Bei 64 bit wird erst umständlich der Quadrant bestimmt, dann in einer Lookup-Table nachgeschaut. Das kostet freilich Zeit. Und ist – wie schon gesagt – ungenau.

Weil ich jetzt schon (unter bestimmten Voraussetzungen) Probleme mit der Genauigkeit bekomme, erschien es mir notwendig, wenigstens ein anderes Rundungsverhalten einzustellen. Aber das ist so ein Kuddelmuddel! Da muss man irgendwelche Flags setzen, und die werden dann doch nicht übernommen, und lauter so ein Zeugs.
Wenn man nämlich Doubles zu int64 runden muss, kann es in einem bestimmten Zahlenbereich einen Overflow geben. Eigentlich sollte dadurch eine Exception ausgelöst werden. Aber Pfeifendeckel! Die Exceptions sind maskiert, und auch da muss man erst wieder Flags setzen.

Das Ändern der Exception Mask ist mies dokumentiert, und bis jetzt funktioniert es einfach nicht richtig. Ich habe den Eindruck, dass sich da etwas gegenseitig überschreibt.

Über Anne Nühm (breakpoint)

Die Programmierschlampe.
Dieser Beitrag wurde unter Uncategorized abgelegt und mit , , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

21 Antworten zu Achthundertsiebenundneunzig

  1. Leser schreibt:

    Ich finde schon, dass 64-Bit ein Fortschritt sind – wenn auch aus Laiensicht, einfach durch die folgende Überlegung: Klar, es braucht mehr RAM, aber es ermöglicht auch die Nutzung von mehr RAM (zumindest unter minderwertigen Betruebssystemen aus Redmond, richtige Betriebssysteme konnten das ja schon immer). Dadurch, dass mehr RAM genutzt werden kann, steht auch mehr für Programme zur Verfügung, die genutzten Programme können also insgesamt komplexer werden.
    Was es mit dem Wegfall der 80-Bit-Variablen auf sich hat, und wie sich das kompensieren lässt, weiß ich nicht – aber wenn es dafür wirklich keinen Ersatz gibt, dann kann ich wieder mal nur über Microsoft lachen, dass sie sowas fabrizieren. Wie erbärmlich dieser sogenannte (möchtegern-)“Softwarehersteller“ doch wieder mal ist!

    Like

    • breakpoint schreibt:

      Auch diesmal ist Microsoft nicht der Sündenbock.
      Verantwortlich sind die Prozessorhersteller (esp. Intel), die in 64-bit-Prozessoren keine FPU und Extended-Unterstützung mehr einbauen.

      Soweit ich das überblicke (aber möglicherweise habe ich ja was übersehen), gibt es tatsächlich keinen Ersatz für sehr genaue Floating Point Numbers. Die Genauigkeit ist jetzt begrenzt auf 64 bit. Nach IEEE sind das gerade mal 52 bit für die Mantisse und 11 für den Exponenten.

      Like

      • DerMaskierte schreibt:

        Der 64-Bit-Befehlssatz ist aber im wesentlichen von AMD verbrochen worden. Zwar entwickelt inzwischen Intel den Befehlssatz weiter, aber die Streichung von FPU und Extended-Unterstützung hast du AMD zu verdanken.

        Like

        • breakpoint schreibt:

          Aha, das wusste ich nicht.
          Ich ging davon aus, dass Intel hier zumindest der Vorreiter ist.

          Like

          • DerMaskierte schreibt:

            Intel wollte im 64-Bit-Bereich seine Itanium-Architektur voran bringen, die sie gemeinsam mit HP entwickelt hatten. AMD hat dann das Heft in die Hand genommen und die x86-Architektur auf 64-Bit erweitert.

            Like

            • breakpoint schreibt:

              Danke. So war das also.
              Und die hochpräzise Floatingpointarithmetik ist dabei auf der Strecke geblieben. Braucht ja niemand.

              Like

            • ednong schreibt:

              Ich meine, ist schon bedauerlich mit der FPU. Was für Dinge berechnest du denn, wo eine derartige Genauigkeit verlangt wird?

              Like

            • breakpoint schreibt:

              Das eine ist eine – ursprünglich rein private – mathematische Spielerei, aber manche Leute sind auch bereit, dafür Geld auszugeben.
              Das andere ein Tool für technische Zwecke, das aber über etliche Zehnerpotenzen präzise funktionieren soll.

              Nur in Extremfällen (die ich beim Testen aber mitberücksichtigen muss) kann es Probleme mit der Genauigkeit geben. Das ist mit bei extended Zahlen nie aufgefallen, aber bei Doubles kann es vorkommen.

              Like

            • Leser schreibt:

              Trotzdem kann ich mir nicht vorstellen, dass da einfach so ein Stück Genauigkeit mal eben ersatzlos gestrichen wird? Lassen sich vielleicht 2 64-Bit-Variablen so „verschränken“, dass sie ein hohes Vielfaches der ursprünglich genauesten 80-Bit-Variable bieten?
              OK, das ist eindeutig eine Laien-Frage, ich kenne mich damit ja nicht aus, das einzige was mir einfiele wäre eine Art Array-Konstrukt mit 64x64Bit, aber sowas lässt sich sicher auch effizienter machen? Vielleicht mal in anderen „Programmiererkreisen“ rumfragen?
              Und wenn nicht, gibt es ja auch immer noch den 32-Bit-Kompatibilitätsmodus, in dem muss doch die alte Variable auch noch zur Verfügung stehen? Und wenn man schon mit einer 32-Bit-Architektur 80 Bit große Variablen berechnen konnte, dann muss das doch auch mit einer 64-Bit-Architektur gehen? Eher sogar noch 160 Bit, rein vom logischen Deken her. Aber wie gesagt, ich bin Laie, kenne mich mit Programmiererei überhaupt nicht aus, weiß gerade mal so ungefähr was eine Variable ist 😉

              Like

            • breakpoint schreibt:

              Ach, wenn das so einfach wäre, würde ich mir ja ein Array mit 12 Bytes hernehmen, und dann mit 96bit Genauigkeit rechnen.

              Momentan nutzen 32-bit-Anwendungen noch die FPU. Aber es würde mich nicht überraschen, wenn in drei oder vier Jahren das wegfallen würde, weil es ja „niemand mehr nutzt“.
              16-bit-Anwendungen laufen ja auf 64-bit-OS auch nicht mehr.

              Like

            • Leser schreibt:

              Also gibt es zumindest noch eine FPU auf dem Chip, das ist doch schon mal was…
              Ich verstehe allerdings den Wegfall der Abwärtskompatibilität hier wirklich nicht. Und ich kann problemlos in meinem 64-Bit-OS einen DOS-Emulator starten, und DOS ist ja ein 16-Bit-Programm (Betriebssystem möchte ich es nicht nennen), darin laufen dann auch 16-Bit-Programme, die alten Originale…

              Like

            • breakpoint schreibt:

              Der DOS-Emulator selbst ist aber eine 32- bzw. 64-bit-Anwendung, und der „emuliert“ (bildet also per SW nach) die 16 bit eben nur.
              Ich habe irgendwo noch ein 16-bit-Programm, das ich manchmal brauche. Das lasse ich dann in einer 32-bit-XP-VM laufen, weil es auf 64 bit nicht mehr geht.

              Like

            • engywuck schreibt:

              Wenn auf einem Prozessor im 32bit-Mode 16bit-Code ausgeführt werden soll ist das recht umständlich: aus dem Protected Mode (also 32bit) heraus wird ein virtueller 8086-Modus genutzt, also quasi eine frühe Form (also für PCs :-)) der Hardware-Virtualisierung. Das Betriebssystem muss extra einen speziellen „Treiber“ vorsehen, der alle im protected mode illegalen Befehle abfängt und emuliert, Zugriffe auf Speicher regelt etc pp. Alles recht umständlich.

              Aus dem 64bit-Modus ist der 32bit-Modus ein Kompatibilitätsmodus. Daraus dann auch noch virtual 8086 ansprechbar zu machen wurde wohl als zu kompliziert angesehen, was ich durchaus verstehen kann 🙂

              Heute wäre es allerdings über Hardware-Virtualisierung (VT-x bzw. AMD-V) möglich, auf 64bit-Prozi im 64bit-Modus einen virtuellen Prozessor laufen zu lassen (hier natürlich 32bit emuliert), der wiederum VM86 nutzt. Und jetzt darfst du dreimal raten, warum das in „Mainstream-Betriebssystemen“ nicht „nativ“ unterstützt wird sondern nur mit speziellen Programmen dazwischen (oder gleich als echte komplette VM). Hardware darüber anzusprechen wird auch beliebig kompliziert.

              Kurz: wer 16bit noch nutzen *muss* nutzt halt ein 32bit-Betriebssystem und bemüht sich um Updates, der Rest genießt 64bit-Betriebssysteme und schweigt.

              Like

        • engywuck schreibt:

          jein. Schon der P4 mit Netburst-Architektur konnte x87-FP eigentlich nicht mehr richtig bzw. war *wesentlich* langsamer. Der kam allerdings drei Jahre oder so vor AMDs 64bit-Variante heraus und war gar anfangs noch 32bit.

          Auch hat Intel schon vorher mit MMX, später SSE die 64-bit FP vorangetrieben (bzw. war MMX sogar nicht nur 32bit-FP Beschleunigung?)

          Dass 80bit FP überhaupt nutzbar war war IIRC eigentlich ein Betriebsfehler. Das war *eigentlich* nur eine interne Erweiterung, um 64bit besser berechnen zu können. Allerdings brauchte man Befehle, um bei Interrupts die internen Zwischenwerte sichern und später zurücklesen zu können…

          Ich vermute stark, dass für die allerallermeisten Anwendungen Double Precision (64bit) ausreicht und beim großen Rest auch 80bit zu wenig ist.

          [1] sagt aber an, dass manche Compiler, z.B. gcc, float128 (112 bit Mantisse) als Datentyp kennen und implementieren. Alternativ musst halt über den Einbau einer entsprechenden Library (die entweder float128 oder gleich arbitrary precision liefert) nachdenken.

          Allerdings ist Double Precision auf ca. 16 Dezimalstellen genau, du könntest also die Entfernung Erde-Sonne auf Millimeter genau angeben. Wie oft drischt denn dein Programm auf die armen Zahlen ein, dass sich solche Ungenauigkeiten merklich auswirken?

          Dass moderne Prozessoren keine trigonometrischen Funktionen mehr implementiert haben ist übrigens nicht unbedingt ein Fehler, siehe [2] oder [3]
          Viele Compiler haben schon lange auf Libraries als Ersatz für FSIN zurückgegriffen – genauer ist es allemal, anständig gemacht kann das sogar schneller sein. Auf dem Pentium dauerte FSIN laut [4] mindestens 16 bis 126 Zyklen (mehr, wenn > Pi/4) und war „non pairing“, das ist nicht sonderlich schnell – beim 387 waren es gar 122-771.

          [1] http://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format
          [2] https://randomascii.wordpress.com/2014/10/09/intel-underestimates-error-bounds-by-1-3-quintillion/
          [3] https://blogs.oracle.com/jag/entry/transcendental_meditation
          [4] http://www2.deec.uc.pt/~jlobo/tc/opcode_f.html

          Like

          • breakpoint schreibt:

            Das Problem ist (bisher) lediglich bei extensiven Tests aufgetreten. Bei Kunden hoffentlich nicht.

            Normalerweise habe ich mit solchen prozessornahen Themen ja gar nichts zu tun, so dass ich mich mit Details nicht auskenne.

            Like

            • engywuck schreibt:

              und ich Naivling dachte immer, dass man um Assembler richtig einzusetzen (und du schreibst ja von Assembleraufrufen und gesetzten Flags) „prozessornahen Themen“ zumindest nicht ganz abgeneigt sein muss 😉

              So du das aber wirklich nicht willst: GMP bzw. deren Erweiterung GMPR haben einen ordentlichen Ruf, untersttzen beliebige Genauigkeit und sollen auch noch halbwegs schnell sein. Dazu sind sie noch LGPL, also problemlos verwendbar. Wie das mit der Geschwindigkeit relativ zum bisherigen aussieht müsstest du natürlich testen, ebenso, ob du nicht dadurch „zu genau“ wirst (FSIN etc. haben ja nur 13bit Genauigkeit in x87, nicht dass du dich da an irgendeiner Stelle implizit darauf verlässt).

              Aber ganz abgesehen davon: als jemand der mal Physik studiert hat sage ich dir: mehr als zweite Näherung braucht doch eh keiner 😉

              Like

            • breakpoint schreibt:

              Normalerweise arbeite ich nicht mit Assembler, nur wenn mir irgendwelche seltsamen Phänomene auffallen, steppe ich halt auch mal in den vom Compiler umgesetzten Assemblercode rein.

              Eine externe Library einzusetzen, habe ich noch nicht erwogen. Im Endeffekt läuft das doch trotzdem auf Prozessorcalls hinaus – oder ist strunzlangsam.

              Die Probleme, die ich jetzt hatte, sollten eigentlich nicht praxisrelevant sein, da sie nur in ganz extremen Bereichen auftreten.
              Andererseits weiß man natürlich nie, auf welche Ideen die Endanwender kommen.

              „mehr als zweite Näherung braucht doch eh keiner“
              Es ist nicht alles Physik.

              Like

  2. idgie13 schreibt:

    Das sind so Sachen, die kein Entwickler braucht und kein „Laie“ versteht (a la „was haben die doofen Entwickler denn wieder geändert? Das hat doch mal funktioniert?“).

    Ich hoffe, Du kannst Dein Problem bald lösen!

    Like

    • breakpoint schreibt:

      Leider habe ich das Problem bisher nicht lösen können, gehe aber davon aus, dass es eigentlich keine praktische Relevanz hat, sprich, es sollte hoffentlich! normalerweise nicht auftreten. Es sei denn, .. 😦

      BTW, welche Datentypen hast du denn für deine Fraktalberechnungen benutzt?

      Like

  3. Pingback: Tausendneunzig | breakpoint

  4. Pingback: Am Anfang war das Bit – #Blogparade zur Digitalisierung @OttoGroup_Com //1482 | breakpoint

Hinterlasse einen Kommentar