hotti: 'Wenn die Minute 64 Sekunden hätte...

... und die Stunde 64 Minuten, ja dann könnte ich ja eine Zeitangabe like
23:59:59 wie folgt in einen numerischen Wert umrechnen:

printf("%d\n", (23 << 12) + (59 << 6) + 59); # Bitweise

zum Vergleich, herkömmlich:
printf("%d\n", (23*64*64) + 59*64 + 59); # 98043

Abstrakt:
64^2   64^1   64^0

Nu hat dummerweise aber eine Minute 60 Sekunden und eine Stunde 60 Minuten und der Tag endet mit 86399 Sekunden. Hmm. Ich will das aber _bitweise_ berechnen und brauch da mal einen Denkanstoß. Brauch ich da ne Maske oder so?

Hotti

  1. Moin Moin!

    ... und die Stunde 64 Minuten, ja dann könnte ich ja eine Zeitangabe like
    23:59:59 wie folgt in einen numerischen Wert umrechnen:

    printf("%d\n", (23 << 12) + (59 << 6) + 59); # Bitweise

    Exakt identisch zu 23 * 2^12 + 59 * 2^6 + 59
    also               23 * 4096 + 59 * 64 + 59

    zum Vergleich, herkömmlich:
    printf("%d\n", (23*64*64) + 59*64 + 59); # 98043

    Abstrakt:
    64^2   64^1   64^0

    Hä?

    Möchtest Du in Base64 rechnen?

    Nu hat dummerweise aber eine Minute 60 Sekunden und eine Stunde 60 Minuten und der Tag endet mit 86399 Sekunden. Hmm. Ich will das aber _bitweise_ berechnen und brauch da mal einen Denkanstoß. Brauch ich da ne Maske oder so?

    Du brauchst mal etwas Bettruhe, Du denkst wirr.

    Möchtest Du in BCD statt in binär rechnen? Warum willst Du auf Krampf mit Bitoperatoren arbeiten? Kann Dein Zielsysten nicht multiplizieren?

    Mal so am Rande: Nicht jede Minute hat 60 Sekunden.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
    1. Moin Moin!

      Moin,

      Abstrakt:
      64^2   64^1   64^0

      Hä?

      Hoch mein Lieber, nicht "Hä" ;-)

      Möchtest Du in Base64 rechnen?

      Andere Baustelle!

      Du brauchst mal etwas Bettruhe, Du denkst wirr.

      Lass mich doch maln bischen spinnen. Das Übliche ist oft auch das Üble, das sagte auch der alpine Dülfer einst, als er nicht weiterkam und die später nach ihm benannte Dülferquerung erfand, die er im Grunde auch nur bei einer Spinne abgeguckt hatte.

      Möchtest Du in BCD statt in binär rechnen? Warum willst Du auf Krampf mit Bitoperatoren arbeiten? Kann Dein Zielsysten nicht multiplizieren?

      Guck Dir doch mal die übl(ich)e Rückrechnung an:

        
      # Sekundenangabe in hms zurückrechnen  
      sub s2hms{  
      	my $s = shift;  
      	$s %= 86400; # Periode rausrechnen  
      	my($h, $hrest) = intrest($s, 3600); # integer + rest  
      	my($m, $s) = intrest($hrest, 60);  
      	return($h, $m, $s);  
      }  
      
      

      Dieser Code wäre doch schiel vöner mit Bitoperatoren, die auch dem Perl-Interpreter recht willkommen sind.

      Mal so am Rande: Nicht jede Minute hat 60 Sekunden.

      Ach du Scheise ;-)

      Hotte

      --
      Wenn der Kommentar nicht zum Code passt, kann auch der Code falsch sein.
      1. Moin!

        Möchtest Du in BCD statt in binär rechnen? Warum willst Du auf Krampf mit Bitoperatoren arbeiten? Kann Dein Zielsysten nicht multiplizieren?

        Guck Dir doch mal die übl(ich)e Rückrechnung an:

        Sekundenangabe in hms zurückrechnen

        sub s2hms{
        my $s = shift;
        $s %= 86400; # Periode rausrechnen
        my($h, $hrest) = intrest($s, 3600); # integer + rest
        my($m, $s) = intrest($hrest, 60);
        return($h, $m, $s);
        }

        
        >   
        > Dieser Code wäre doch schiel vöner mit Bitoperatoren, die auch dem Perl-Interpreter recht willkommen sind.  
          
        Keins der auf Computern existenten Zahlensysteme ist kompatibel zur Basis 60. Weder Binär- noch BCD-Arithmetik hilft dir hier.  
          
        Im Prinzip willst du ein System, welches von (0) bis (59) zählt und dann auf (1)(0) weiterspringt, und nicht auf (60). (Klammern verdeutlichen die Ziffern)  
          
        Da helfen dir aber keine Bitoperatoren. Menschliche Uhrzeit ist scheiße zu bearbeiten im Rechner. Deswegen gibts ja auch die Unix-Timestamps, die einfach nur Sekunden zählen. Das ist viel einfacher zu behandeln, und für irgendeine "schöne" Anzeige konvertiert man dann halt.  
          
         - Sven Rautenberg
        
        1. Man kann sich doch mit Bit-Operatoren behelfen - siehe mein Posting.

          Gruß, LX

          --
          RFC 1925, Satz 6a: Es ist immer möglich, einen weiteren Umweg einzufügen.
          RFC 1925, Satz 11a: Siehe Regel 6a
        2. hi,

          Da helfen dir aber keine Bitoperatoren. Menschliche Uhrzeit ist scheiße zu bearbeiten im Rechner.

          Schön gesagt  **G**

          Deswegen gibts ja auch die Unix-Timestamps, die einfach nur Sekunden zählen. Das ist viel einfacher zu behandeln, und für irgendeine "schöne" Anzeige konvertiert man dann halt.

          Mal Überschlafen. Vielleicht kommt mir des Nachts die Erleuchtung und es ist gar nicht mal so selten, dass mir ein cooler (eleganter) Hack im Traum einfällt ;-)

          Hotte

          --
          Fixe Idee: Flurstück im Landkreis Gotha. Beliebtes Ausflugziel.
        3. Hallo,

          Im Prinzip willst du ein System, welches von (0) bis (59) zählt und dann auf (1)(0) weiterspringt, und nicht auf (60). (Klammern verdeutlichen die Ziffern)

          und da dieses System weit zurückreichende historische Wurzeln hat und auch heute noch viel verwendet wird (Zeit- und Winkelangaben), hat es sogar eine eigene Bezeichnung: Sexagesimal.

          Schönen Sonntag noch,
           Martin

          --
          Dieser Satz wurde in mühsamer Kleinstarbeit aus einzelnen Wörtern zusammengesetzt.
            (Hopsel)
  2. Statt

    h * 60 * 60 + m * 60 + s

    kannst Du binär folgendes nutzen:

    (h << 12) - (h << 9) - (h << 4) + (m << 6) - (m << 2) + s

    Gruß, LX

    --
    RFC 1925, Satz 6a: Es ist immer möglich, einen weiteren Umweg einzufügen.
    RFC 1925, Satz 11a: Siehe Regel 6a
    1. Für diejenigen, die jetzt rätselnd in der Ecke stehen:

      (h << 12) - (h << 9) + (h << 4) + (m << 6) - (m << 2) + s

      einige Umformungen:

      h*2^12   -  h*2^9   +  h*2^4    +  m*2^6  -  m*2^2   + s
       h*4096   -  h*512   +  h*16     +  m*64   -  m*4     + s
       h * (4096 - 512 + 16)           +  m * (64 - 4)      + s
       h * 3600                        +  m * 60            + s

      Na? Klingelt's?

      Gruß, LX

      --
      RFC 1925, Satz 6a: Es ist immer möglich, einen weiteren Umweg einzufügen.
      RFC 1925, Satz 11a: Siehe Regel 6a
      1. Für diejenigen, die jetzt rätselnd in der Ecke stehen:

        (h << 12) - (h << 9) + (h << 4) + (m << 6) - (m << 2) + s

        einige Umformungen:

        h*2^12   -  h*2^9   +  h*2^4    +  m*2^6  -  m*2^2   + s
        h*4096   -  h*512   +  h*16     +  m*64   -  m*4     + s
        h * (4096 - 512 + 16)           +  m * (64 - 4)      + s
        h * 3600                        +  m * 60            + s

        Na? Klingelt's?

        Berauschend!!!!!! Ich bin begeistert!!!!

        Tausend Dank.

        --Horst

    2. Ich sehe gerade, da hatte sich ein Tippfehler eingeschlichen.

      (h << 12) - (h << 9) - (h << 4) + (m << 6) - (m << 2) + s

      Richtig muss es natürlich heißen:
      (h << 12) - (h << 9) + (h << 4) + (m << 6) - (m << 2) + s

      Gruß, LX

      --
      RFC 1925, Satz 6a: Es ist immer möglich, einen weiteren Umweg einzufügen.
      RFC 1925, Satz 11a: Siehe Regel 6a
      1. hi,

        Richtig muss es natürlich heißen:
        (h << 12) - (h << 9) + (h << 4) + (m << 6) - (m << 2) + s

        Ich war jetzt kurz davor... Danke!!!!
        Also ich hatte gerade die Minuten am Wickel und dasda (m << 6) - (m << 2) auch schon. An den Stunden bin ich gescheitert ;-)

        Schaffn wir es, das bis morgen umzudrehen?

        Hotti

        1. Mit "umdrehen", meinst Du da jetzt den umgekehrten Fall - also die Umwandlung von Sekunden in Stunden, Minuten und Sekunden ohne Fließkommafunktionen, lediglich mit Bitshift, Addition, Subtraktion und Modulo?

          Gruß, LX

          --
          RFC 1925, Satz 6a: Es ist immer möglich, einen weiteren Umweg einzufügen.
          RFC 1925, Satz 11a: Siehe Regel 6a
          1. Mit "umdrehen", meinst Du da jetzt den umgekehrten Fall - also die Umwandlung von Sekunden in Stunden, Minuten und Sekunden ohne Fließkommafunktionen, lediglich mit Bitshift, Addition, Subtraktion und Modulo?

            Ja ;-)

            Aber das muss ohne Modulo gehen. wir haben v.l.n.r. 6 Bit für die Stunden, 6 Bit für die Minuten und 6 Bit für die Sekunden. Wenn da das Hin- und Hergeshifte vorher nicht gewesen wäre bräuchten wir nun Masken um die Zahlen da wieder rauszuziehen;

            |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|  Sekunden insgesamt SG
             h h h h h h m m m m m m s s s s s s

            1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0   Stundenmaske   HM
             0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0   Minutenmaske   MM
             0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1   Sekundenmaske  SM

            Wenn die Minute 64 Sekunden hätte (tja...) sähe das so aus:

            Stunden H = (SG & HM) >> 12
            Minuten M = (SG & MM) >> 6
            Sekunden S = SG & SM

            Aber so einfach gehts nicht. Hast Du Lust da weiterzumachen, oder führt dieser Ansatz in eine Sackgasse?

            Rolf

            1. Mit "umdrehen", meinst Du da jetzt den umgekehrten Fall - also die Umwandlung von Sekunden in Stunden, Minuten und Sekunden ohne Fließkommafunktionen, lediglich mit Bitshift, Addition, Subtraktion und Modulo?

              Ja ;-)

              Um mit C.F. Gauss zu rechnen, hätten wir auch einen algebraischen Ansatz mit 3 Gleichungen, geg.: S(ekunden), ges.: h, m, s

              1. Gleichung
              S = h*3600 + m*60 + s

              2. Gleichung
              m = h/60

              3. Gleichung
              s = h/3600

              Wenn S = 86399 ist, muss h = 23, m = 59 und s = 59 rauskommen, viel Spass beim Rechnen, ich gehe jetzt Schlafen (Danke Alexander).

              Horst (Nachname nicht näher bestimmt)

              --
              Dülferquerung siehe Wiki.
            2. Moin!

              Wenn die Minute 64 Sekunden hätte (tja...) sähe das so aus:

              Stunden H = (SG & HM) >> 12
              Minuten M = (SG & MM) >> 6
              Sekunden S = SG & SM

              Aber so einfach gehts nicht. Hast Du Lust da weiterzumachen, oder führt dieser Ansatz in eine Sackgasse?

              Wie ich dir schon versuchte klarzumachen: Die Zahlenbasis 60 für die Sekunden und Minuten ist inkompatibel zur Zahlenbasis 2 des Computers. Mindestens was die Binärarithmetik und Bitoperationen angeht.

              Der Trick von LX, um aus Einzelwerten für Stunde, Minute und Sekunde eine Sekundenanzahl zu machen, ist simpel: Ein Bitshift nach links entspricht einer Multiplikation mit 2. Statt also h*3600 + m*60 + s zu rechnen, bastelt er sich die Multiplikatoren (3600 und 60) durch Addition und Subtraktion von Zweiterpotenzen. Wobei schon das nicht in deinem eigentlichen Sinne sein dürfte, denn Addition und Subtraktion sind keine Bitoperationen.

              Umgekehrt funktioniert das noch weniger.

              Dir schwebt vor, einfach durch Ausblenden von Bits aus einer Sekundenanzahl die Zahlen für Stunden, Minuten und Sekunden zu ermitteln.

              Funktioniert nicht so einfach. Bzw. die Lösung würde bestimmt sehr kompliziert und aufwendig, so dass eine Rechenlösung schneller ist (Benchmarking überlasse ich dir, genauso übrigens für die Vorwärtslösung von LX).

              Aber das muss ohne Modulo gehen. wir haben v.l.n.r. 6 Bit für die Stunden, 6 Bit für die Minuten und 6 Bit für die Sekunden. Wenn da das Hin- und Hergeshifte vorher nicht gewesen wäre bräuchten wir nun Masken um die Zahlen da wieder rauszuziehen;

              Die Sache ist: Wir haben keine 6 Bit für die Sekunden.

              011111 - sind 31 Sekunden
              100000 - sind 32 Sekunden
              111111 - sind 63 Sekunden - also 3 Sekunden und 1 Minute.
              111100 - sind 60 Sekunden - also exakt 1 Minute.

              Wie man also sieht: Bit 5 auf 1 sagt absolut nichts über die Anzahl der Sekunden allein aus. Selbst Bit 0 sagt nichts über die Anzahl der Sekunden allein aus.

              Du kannst natürlich wieder diese Bitshift-Operation anwenden, um durch 2 zu teilen, und dann Zwischenergebnisse speichern, wieder multiplizieren, und vom Ursprungswert abziehen, um ein Modulo zu simulieren. Denn anders kommst du nicht an die Zahl der Sekunden ran: s = t%60. Modulo ist eine komplexe Operation, die man nicht "mal eben" durch eine einzige oder sehr wenige Bitoperationen ersetzen könnte.

              - Sven Rautenberg

              1. In JavaScript ist die Lösung mit dem Bitshift in einigen Browsern tatsächlich schneller, da auf eine Fließkommaumwandlung komplett verzichtet werden kann. Andererseits ist die Variante der Multiplikation auch nicht wesentlich langsamer, so dass eine praktische Anwendung insofern unpraktisch ist, als dass der Code nicht so leicht verständlich ist.

                Allerdings muss ich Dir widersprechen, wenn Du sagst, dass Addition, Subtraktion etc. nicht auch allein mit Bit-Operationen ausgeführt werden können - die CPU in Deinem PC macht das nämlich genau auf diese Weise und die ganze Informatik basiert auf diesem Prinzip.

                Recht hast Du allerdings darin: Es ist wenig sinnvoll, außer vielleicht als Lernbeispiel, diese Operationen manuell nachzubauen.

                Gruß, LX

                --
                RFC 1925, Satz 6a: Es ist immer möglich, einen weiteren Umweg einzufügen.
                RFC 1925, Satz 11a: Siehe Regel 6a
                1. Moin!

                  In JavaScript ist die Lösung mit dem Bitshift in einigen Browsern tatsächlich schneller, da auf eine Fließkommaumwandlung komplett verzichtet werden kann. Andererseits ist die Variante der Multiplikation auch nicht wesentlich langsamer, so dass eine praktische Anwendung insofern unpraktisch ist, als dass der Code nicht so leicht verständlich ist.

                  Hotti will hier was in Perl basteln.

                  Allerdings muss ich Dir widersprechen, wenn Du sagst, dass Addition, Subtraktion etc. nicht auch allein mit Bit-Operationen ausgeführt werden können - die CPU in Deinem PC macht das nämlich genau auf diese Weise und die ganze Informatik basiert auf diesem Prinzip.

                  Die CPU hat aber auch den Vorteil, dass sie die einzelnen Bits anfassen kann, ohne von den restlichen Bits beeinflusst zu werden. Eine Additionseinheit baut sich das Resultat bitweise mit logischen Operationen zusammen. Das funktioniert so einfach jedoch nicht, wenn man in einer Hochsprache mit Bitoperatoren und Integerwerten arbeiten muss.

                  Recht hast Du allerdings darin: Es ist wenig sinnvoll, außer vielleicht als Lernbeispiel, diese Operationen manuell nachzubauen.

                  Da stimmen wir überein. :)

                  - Sven Rautenberg

                  1. Moin!

                    In JavaScript ist die Lösung mit dem Bitshift in einigen Browsern tatsächlich schneller, da auf eine Fließkommaumwandlung komplett verzichtet werden kann. Andererseits ist die Variante der Multiplikation auch nicht wesentlich langsamer, so dass eine praktische Anwendung insofern unpraktisch ist, als dass der Code nicht so leicht verständlich ist.

                    Hotti will hier was in Perl basteln.

                    Genau. Hotti hat fixe Ideen und einen Holzkopf.

                    Recht hast Du allerdings darin: Es ist wenig sinnvoll, außer vielleicht als Lernbeispiel, diese Operationen manuell nachzubauen.

                    Da stimmen wir überein. :)

                    Ja, ich schlage nun auch ein. ACK!

                    Das Kernproblem ist, wie Du, Sven schon gestern schriebst, der Übertrag; der binär gesehen also bei 64 stattfindet und nicht bei 60 oder 24, wie das die dämlichen Uhren so machen. Insofern ist nur eine algebraische Lösung sinnvoll für Umrechnungen zwischen h:m:s und Sekunden.

                    Btw., in der kurzen Nacht heute ist mir Götz von Berlichingen erschienen... das ist auch eine Art der Erleuchtung ;-)

                    Viele Grüße,
                    Hotti

                    --
                    die; # geht immer
                    1. Moin Moin!

                      Hotti will hier was in Perl basteln.

                      Genau. Hotti hat fixe Ideen und einen Holzkopf.

                      Eine Maschine, die Perl laufen (im Gegensatz zu kriechen und humpeln) lassen kann, ist in aller Regel gut genug bestückt, um mit ein paar Integer- und Modulo-Divisionen keine Probleme zu haben. Nimm die vorhandenen Routinen in Perl und z.B. in DateTime und verlaß dich darauf, dass sie schnell genug sind.

                      Das hin- und herschieben von Bits in Perl zur Performance-Optimierung bringt nichts, das geht im Rest von Perl vollkommen unter. Wenn Du unbedingt Bits schubsen willst, laß die Finger von Perl und schreib stattdessen direkt Assembler-Code, optimiert auf eine CPU (und nur eine!) Deiner Wahl.

                      Ansonsten kannst Du ganz entspannt davon ausgehen, dass aktuelle C-Compiler durchaus effektiven Code generieren, wenn man sie denn läßt. gcc -O2 ist für die meisten Zwecke gut genug. Wenn man für eine ganz spezielle CPU extrem optimierten Code haben will, läßt man den gcc mit einer Tonne Spezial-Optionen laufen oder nimmt hochoptimierte Compiler vom Hersteller (z.B. Intel) mit entsprechendem Tuning. Irgendwo her müssen die phantastischen Benchmark-Ergebnisse ja kommen! ;-)

                      Das Kernproblem ist, wie Du, Sven schon gestern schriebst, der Übertrag; der binär gesehen also bei 64 stattfindet und nicht bei 60 oder 24, wie das die dämlichen Uhren so machen. Insofern ist nur eine algebraische Lösung sinnvoll für Umrechnungen zwischen h:m:s und Sekunden.

                      Darf ich mal auf das DCF77-Protokoll verweisen?

                      Die Leute, die sich das ausgedacht hatten, mußten für extrem einfache Systeme planen. Wir sprechen da über die berühmt-berüchtigte 74XX-TTL-Baureihe. Multiplikation und Division kann man da vollkommen vergessen, selbst Addition und Subtraktion ist viel Aufwand mit 74XX-ICs. Die ersten DCF77-Funkuhren hatten Format und Stromaufnahme eines modernen Mini-PCs, aber weniger Rechenleistung als ein Taschenrechner.

                      Der Trick:
                      1. Aufteilen in Einer und Zehner. Statt Stunden, Minuten und Sekunden schlägt sich das DCF-Protokoll mit Zehner-Stunden, Einer-Stunden, Zehner-Minuten, Einer-Minuten, Zehner-Sekunden, Einer-Sekunden.
                      2. "Rechnen" in BCD. Man benutzt vier Bits, aber nur die ersten zehn Kombinationen von 0000 bis 1001 sind erlaubt.

                      Einige CPUs haben extra für das Rechnen in BCD zusätzliche OpCodes, z.B. der Z80 (DAA), so dass man tatsächlich die Uhrzeit die ganze Zeit BCD-codiert vorhält. Dann ist die Darstellung tatsächlich recht einfach: BCD-codiertes Byte in den Akku laden, Bits 4 bis 7 auf 0011 setzen, als ASCII interpretieren und als Einer-Stelle darstellen. BCD-Codiertes Byte nochmal in den Akku laden, Akku 4 Bit nach rechts schieben, Bits 4 bis 7 auf 0011 setzen, als ASCII interpretieren und als Zehner-Stelle darstellen.

                      Alexander

                      --
                      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
                      1. Hi!

                        1. Aufteilen in Einer und Zehner. Statt Stunden, Minuten und Sekunden schlägt sich das DCF-Protokoll mit Zehner-Stunden, Einer-Stunden, Zehner-Minuten, Einer-Minuten, Zehner-Sekunden, Einer-Sekunden.

                        Das DCF-Protokoll überträgt keine Sekunden. Es wird ja schon knapp eine ganze Minute benötigt, um Datum und aktuelle Uhrzeit zu übertragen - mit jeder Sekunde ein Bit. Die Sekunden werden von den Uhren selbst hochgezählt. Sie synchronisieren sich mit der nullten Sekunde, die sie an der vorangegangenen 59. Sekunde erkenne, die quasi als Null-Bit übertragen wird (null im Datenbanksinn, keine Integer-0).

                        Lo!