Bitweise Shift In Basic.... Nicht Ganz So Trivial

  • Hallo,


    um bestimmte Algorithmen auch in BASIC zu implementieren, benötigt man oft bitweise "shift" (bits "schieben" um 1 oder mehrere Stellen links oder rechts im Binärsystem) .


    Bytes (0-255) so zu bearbeiten ist noch relativ trivial und effizient zu implementieren:


    10 PRINT "BITWISE SHIFT IN BASICA"
    20 INPUT "BYTE VALUE (0-255) ";A%
    30 PRINT "VALUE IN HEX=";HEX$(A%)
    40 B%=255 AND (A%+A%)
    50 PRINT "LEFT SHIFT=";HEX$(B%)
    60 REM BASICA ALWAYS TAKE NUMBERS AS A FLOAT !
    70 REM SO YOU MUST USE INT() FUNCTION TO GET AN INTEGER RESULT
    80 B%=INT(A%/2)
    90 PRINT "RIGHT SHIFT (HEX)=";HEX$(B%)


    Das was schon weniger effizient ist, die Division durch 2, ist schon häßlich, aber die Kröte schluckt man noch.


    Wenn man aber 16-Bit Integer bitweise "schieben" will, wird es richtig ineffizient, weil man scheinbar das nur noch mit FLOAT Rechenoperationen hinbekommt.


    10 PRINT "16-BIT INTEGER SHIFT IN BASICA"
    20 INPUT "INTEGER VALUE (0-65535) ";A
    30 IF A<>INT(A) THEN PRINT"FLOAT IS NOT THE SAME AS INTEGER.":GOTO 20
    40 IF A>65535! OR A<0! THEN PRINT"NOT IN INTEGER VALUE RANGE.":GOTO 20
    50 PRINT "VALUE IN HEX=";HEX$(A)
    60 B=A+A:IF B>65535! THEN B=B-65536!
    70 PRINT "LEFT SHIFT=";HEX$(B)
    80 REM BASICA ALWAYS TAKE NUMBERS AS A FLOAT !
    90 REM SO YOU MUST USE INT() FUNCTION TO GET AN INTEGER RESULT
    100 B=INT(A/2)
    110 PRINT "RIGHT SHIFT (HEX)=";HEX$(B)


    Hat jemand eine elegantere Idee zum Bearbeiten von 16-Bit Werten in BASIC ?

    "Probleme kann man niemals mit derselben Denkweise lösen, durch die sie entstanden sind."


    ... und schaut auch mal bei meinem Blog vorbei ...

  • Moin moin

    Hat jemand eine elegantere Idee zum Bearbeiten von 16-Bit Werten in BASIC ?


    Gibt es ein bitweises UND?
    Welches BASIC benutzt du eigentlich?

    ;------------------------------------
    ;----- ENABLE NMI INTERRUPTS
    (aus: IBM BIOS Source Listing)

  • Gibt es ein bitweises UND?


    Ich meine AND funktioniert bitweise. Kannst du ja mal an verschiedenen Werten für A und B testen: PRINT A AND B


    Quote

    Welches BASIC benutzt du eigentlich?


    BASICA. Das ist ein Microsoft-BASIC für frühe IBM-PCs

  • Ich meine AND funktioniert bitweise. Kannst du ja mal an verschiedenen Werten für A und B testen: PRINT A AND B


    Dann ist es doch einfach:
    Shift links
    A = A + A
    A = A and 65535

    ;------------------------------------
    ;----- ENABLE NMI INTERRUPTS
    (aus: IBM BIOS Source Listing)

  • Moin moin


    Gibt es ein bitweises UND?
    Welches BASIC benutzt du eigentlich?


    Bitweise gibt es AND, OR und XOR für BASICA/GWBASIC, welches ich benutze (weil es auf den ältesten IBM PCs auch noch gut läuft und sozusagen zur Originalausstattung der ersten PCs gehört hatte).


    Wenn man PowerBASIC z.B. nutzt, gibt es auch ein bitweises "Shift" als Operator. Mir ging's aber eher um die Möglichkeiten, was man noch tun kann, wenn man eben *nicht* den Shift-Operator in der Sprache hat.
    Eine Idee war auch, ein Assemblerprogramm einzubinden, wie z.B. das hier (Anhang). Aber das Beispielprogramm z.B. läuft nur mit QBASIC/QB 4.5, und kann auch nur 8-Bit und nicht 16-Bit Zahlen "bitweise schieben".

    Files

    • BITWISE.ZIP

      (869 Byte, downloaded 18 times, last: )

    "Probleme kann man niemals mit derselben Denkweise lösen, durch die sie entstanden sind."


    ... und schaut auch mal bei meinem Blog vorbei ...


  • Dann ist es doch einfach:
    Shift links
    A = A + A
    A = A and 65535


    Nein. a) weil 65535 erstmal wieder ein FLOAT-Wert in BASIC ist (leider werden sozusagen alle Zahlen erstmal als FLOAT im Interpreter behandelt), und b) weil nur das Links-Shift "einfach" ist, Rechts-Shift ist mind. eine Division + Abschneiden der Nachkommastellen.
    Und die (Float) Division kostet Zeit, viel Zeit.

    "Probleme kann man niemals mit derselben Denkweise lösen, durch die sie entstanden sind."


    ... und schaut auch mal bei meinem Blog vorbei ...

  • Geht's dir um Geschwindigkeit oder um eine allgemeine Funktion?


    Wenn AND, OR, XOR doch bitweise arbeitet, ist es doch egal ob intern gefloatet wird oder nicht.
    Was gibt den folgendes aus?
    print 2 and 1
    print 3 and 1
    print 3.14 and 1


    Beim Links-Shift sollte das AND aber schneller sein als die Vergleiche in deinem ersten Post.
    Und den Rechts-Shift geht nicht besser.

    ;------------------------------------
    ;----- ENABLE NMI INTERRUPTS
    (aus: IBM BIOS Source Listing)

  • Geht's dir um Geschwindigkeit oder um eine allgemeine Funktion?


    Erstmal um Geschwindigkeit, weil ich ein C-Sourcecode in BASIC übersetzen möchte, und in der C-Source wird innerhalb von Schleifen extensiv "geshifted".



    Kapier' ich nicht. AND, OR und XOR ist was anderes als die SHR/SHL bzw. die Schieberegister-Operation.
    D.h. auch wenn AND, OR und XOR funktionieren, kann ich noch lange nicht effizient bitweise schieben...

    "Probleme kann man niemals mit derselben Denkweise lösen, durch die sie entstanden sind."


    ... und schaut auch mal bei meinem Blog vorbei ...

  • D.h. auch wenn AND, OR und XOR funktionieren, kann ich noch lange nicht effizient bitweise schieben...


    B = A + A; B = B and 65535
    ist aber effizienter als hier:

    60 B=A+A:IF B>65535! THEN B=B-65536!


    Ok, ein Geschwindigkeitsrekord gewinnst mit beiden nicht.
    Kann den BASICA Assembler aufrufen?



    und in der C-Source wird innerhalb von Schleifen extensiv "geshifted"


    Geht's den wirklich um Shifts, oder ist der Shift eine schnellere Umsetzung einer 2^n Multiplikation?

    ;------------------------------------
    ;----- ENABLE NMI INTERRUPTS
    (aus: IBM BIOS Source Listing)


  • Kapier's weiterhin nicht was Du mir sagen willst. Ich hatte ja schon darauf hingewiesen, das BASICA/GWBASIC/QBASIC erstmal alle Zahlen (also auch die Zahl 65535) als FLOAT ansieht.
    Wenn Du "B AND 65535" in BASIC ausführst, ist das NICHT das Gleiche, wie wenn Du das z.B. in C (mit einem C Compiler) und dem Datentyp INTEGER machst.


    BASICA / QBASIC kann mit CALL bzw. USR() auch Assembler (im Interpreter) aufrufen. Dabei musst Du aber auch DEF SEG, VARSEG und VARPTR einsetzen. Außerdem musst Du im Assemblerteil natürlich erstmal den Stack retten, und die Parameterübergabe-Mechanik verstehen, dann Deine eigentlichen Berechnungen durchführen, die Parameter zurückgeben, und den Stack wiederherstellen - das RETF am Schluß nicht zu vergessen.

    "Probleme kann man niemals mit derselben Denkweise lösen, durch die sie entstanden sind."


    ... und schaut auch mal bei meinem Blog vorbei ...

  • Mit "B AND 65535" will ich mir das "IF B>65535! THEN B=B-65536!" sparen.



    Bitweise gibt es AND, OR und XOR für BASICA/GWBASIC


    Wenn Du "B AND 65535" in BASIC ausführst, ist das NICHT das Gleiche, wie wenn Du das z.B. in C (mit einem C Compiler) und dem Datentyp INTEGER machst.


    Und das widerspricht sich !!!!
    Wenn AND bitweise arbeitet, sollte es wie in C mit Integern funktionieren. Wenn es das nicht tut, was macht es denn?

    Was gibt den folgendes aus?
    print 2 and 1
    print 3 and 1
    print 3.14 and 1

    ;------------------------------------
    ;----- ENABLE NMI INTERRUPTS
    (aus: IBM BIOS Source Listing)

  • Doch, habe ich. Und hab's ich gerade am lebenden Objekt getestet.
    Allerdings war mir nicht mehr bewusst, das bei Zahlen >= 32768 ein Overflow auftritt.
    Anscheinend wird bei AND etc mit 16 bit Signed gearbeitet.
    Warum sagst du das nicht gleich. :)

    ;------------------------------------
    ;----- ENABLE NMI INTERRUPTS
    (aus: IBM BIOS Source Listing)

  • ?


    Das ist so ähnlich wie die Idee, bei Zahlen über 32767 stattdessen negative Zahlen (im Bereich -1 bis -32767) zu nutzen.
    Ich habe aber - wenn ich mit Ganzzahlen (16 Bit, nicht 32 Bit) rechne, dann oft als Ergebnis negative Zahlen... mit einer Berechnung ohne Korrekturaddition wird's dann wieder schwierig.
    In meinem Beispiel-Code gibt man außerdem die Zahlen nicht als Hexadezimalwert ein. Mhhmmm vielleicht kann man ja HEX$() danach noch nutzen, aber das ist sicherlich auch eine Performancebremse.

    "Probleme kann man niemals mit derselben Denkweise lösen, durch die sie entstanden sind."


    ... und schaut auch mal bei meinem Blog vorbei ...