Ankündigung

Einklappen
Keine Ankündigung bisher.

Bitmasken

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Bitmasken

    Hallo,

    ich habe um den Typ einer CSV-Spalte festzustellen folgende Typ-Flags:
    Code:
    	const TYPE_FLAG           = 4;
    	const TYPE_INTEGER        = 8;
    	const TYPE_DATE           = 16;
    	const TYPE_DATETIME       = 32;
    	const TYPE_UNIX_TIMESTAMP = 64;
    	const TYPE_DOUBLE         = 128;
    	const TYPE_VARCHAR        = 256;
    	const TYPE_TEXT           = 512;
    Sortiert nach ihrer "Grobheit".
    Gehen wir der Einfachheit halber von aus, dass der erste Flag bei 2^0 = 1 beginnt.

    Ich durchlaufe nun einige hoffentlich repräsentative Zeilen eines CSV und ordne einem Array-Element (Index = Spaltennummer) nun per Bitverknüpfung | (bzw. +) den treffenden Typen zu. Wenn in einer Spalte (natürlich in verschiedenen Zeilen) ein Unix-Timestamp und ein Text mit maximaler Länge von 255 gefunden wird, bekommt dieses Element also den Wert $current = self::TYPE_UNIX_TIMESTAMP | self::TYPE_VARCHAR; /* 64 + 256 = 320 */

    Nun möchte ich am Ende dieses Analyse zusammenfassen, das heißt, der gröbste Typ bekommt den Zuschlag (befinden sich in ein und der selben Spalte also TYPE_UNIX_TIMESTAMP und TYPE_VARCHAR bekommt TYPE_VARCHAR natürlich den Zuschlag).
    Wie wäre der cleverste Algorithmus, das nun dynamisch zu machen?
    Eine for-Schleife, deren Initiierungswert 512 wäre und dessen Wert sich dann jedesmal halbiert?

    Im Moment habe ich folgenden Code:
    PHP-Code:
    <?php
                $type 
    $current self::TYPE_TEXT
                      
    self::TYPE_TEXT
                      
    $current self::TYPE_VARCHAR
                        
    self::TYPE_VARCHAR
                        
    $current self::TYPE_DOUBLE
                        
    self::TYPE_DOUBLE
                        
    $current self::TYPE_UNIX_TIMESTAMP
                        
    self::TYPE_UNIX_TIMESTAMP
                        
    $current self::TYPE_DATETIME
                        
    self::TYPE_DATETIME
                        
    $current self::TYPE_DATE
                        
    self::TYPE_DATE
                        
    $current self  
                        
    /* usw. */
    ?>
    Wobei ich nichtmal weiß, ob dieses Konstrukt überhaupt ohne Klammerung funktioniert.

    Sprich, wenn ich in $current = 1023 (was die Zuordnung aller TYPEs wäre, da 1023 = (2 * 512) - 1), soll in meiner Variable 512 stehen, da es der größte gefundene TYPE ist.
    Reicht es zur nächstgrößten 2er-Potenz zu laufen und diese zu halbieren?

    Habt ihr mich überhaupt verstanden? =)

  • #2
    Ich glaube nicht, dass die Trinitäten ohne Klammerung der else Zweige funktionieren.

    Die rein mathematische Lösung wäre der ganzzahlige Wert eines 2er Logarithmus von 1023,
    also z.B.
    log2(1023) = 9,998 ; floor (9,99 = 9
    1 + 4 +8 = 13 ; log2(13) = 3,700 ; floor (3,700) = 3

    möglicherweise ist dieser Weg aber wesentlich rechenintensiver. Gibt es keine passende Bit-Operation?

    EDIT:
    Oder mal ganz blöd - wie wärs mit ner String-Variante wie einer Kombination aus
    strlen() und strpos(), bzw. strrev() und strpos(), um
    die am weitesten links stehende eins zu finden (und deren Offset von rechts aus gesehen).

    strlen((binär) 1023) = 10 ;
    strpos ((binär) 1023) , '1') = 0 ;
    10-(0+1) = 9 ; (die eins resultiert aus 2^0)

    strlen((binär) 13) = 4 ;
    strpos ((binär) 13) , '1') = 0 ;
    4-(0+1) = 3 ;

    Ohne führende Nullen kann man sogar die strlen() Geschichte einsparen.
    .

    Kommentar


    • #3
      log2(1023) = 9,998 ; floor (9,99 = 9
      Na das ist doch schonmal genial, 2^9 = 512, genau was ich haben möchte. Dann muss der Algorithmus nichtmal wissen, welche Potenz maximal gesucht wird (das heißt ich kann später ohne Änderung weitere TYPEs hinzufügen.

      Ich habe momentan folgende Lösung:
      PHP-Code:
      <?php
                  
      for ($i 4$i 2048$i *= 2) {
                      if (
      $i $current) {
                          
      $type $i 2;
                          break;
                      }
                  }
      ?>
      (1, 2 und 4 sind von UNSIGNED, SIGNED, NULL belegt)

      Ich nehme deine Lösung, die gefällt mir. Danke!

      Edit:
      EDIT:
      Oder mal ganz blöd - wie wärs mit ner Kombination aus
      strlen() und strpos(), bzw. strrev() und strpos(), um die am weitesten links stehende eins zu finden (und deren Offset von rechts aus gesehen).
      Wow das ist mal schnell:
      Code:
      echo pow(2, strlen(decbin($bitmaske)) - 1);
      Danke das nehm ich jetzt schlussendlich!

      Kommentar


      • #4
        Vielleicht wären Bit-Operationen in Verbindung mit Konstanten mal ein gutes Kurztutorial, um die Arbeitsweise mit Flags in Funktionen zu beschreiben.

        Kommentar


        • #5
          Tu dir keinen Zwang an

          Kommentar

          Lädt...
          X