Interessantes Phänomen mit Microsoft BASIC

  • Hallo,


    ich wollte euch mal etwas ( für mich ) interessantes berichten.
    Zur Zeit befasse ich mich wieder mit meinem Olympia People Computer.
    Dieser arbeitet wie zum Beispiel der Victor Computer mit CP/M und MS-DOS.
    Der Computer hat eine 8086 CPU und 128Kb RAM.
    Ich habe jetzt in diesen Computer ein kleines Programm in BASIC eingegeben (BASIC86
    von MICROSOFT). Das gleiche Programm habe ich in einen Commodore CBM 610 eingegeben.
    Das Programm ist eine Version von Conway´s Game of Life.
    Auf dem Olympia Computer läuft es extrem langsam ab, bis zu 30 - 45 Sekunden bis zum
    nächsten Schritt. Auf dem Commodore rennt es förmlich, ca. 3 Sekunden bis zur nächsten Anzeige.
    Andere BASIC-Programme laufen aber "normal" auf den Olympia ab.
    Irgendwie finde ich die Sache recht interessant.


    Gruß Björn

  • Na ja, so ungewöhnlich ist das nicht (verschiedene Ausführungszeiten). Habe eine große Reihe von Vergleichsmessungen auf verschiedenen PCs mit allen mir bekannten Varianten von MS-DOS BASIC Compilern gemacht, und habe ähnlich große Abweichungen festgestellt.
    Das liegt (bei gleicher Maschine) z.B. auch daran, wie alt der BASIC Interpreter ist (typischerweise sind neuere Versionen meist schneller, wenn auch weniger platzsparend - da gibt's tatsächlich eine Ableitung daraus, d.h. je platzsparender der BASIC Compiler z.B. Code produzierte, desto langsamer war er).

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


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

  • Mit wieviel MHz läuft der Olympia?
    Ich vermute mal mit 4-5 MHz?
    Daß der CBM mit seinem 2 MHz 6509 (im Grunde ein 6502) schneller ist liegt ja eigentlich auf der Hand.
    Der 8086 ist eine Gurke.
    Er hat keine eigenen Pins für Adress- und Datenbus, die müssen sich die gleichen Pins teilen.
    Es muß ständig zwischen Daten- und Adressbus umgeschaltet werden.
    Also braucht allein der Speicherzugriff schon mal doppelt soviele Takte, wie bei einem Prozessor mit getrenntem Adress- und Datenbus.
    Dann kommt noch hinzu, daß der 6502 bei den meisten Befehlen weniger Takte für die Ausführung benötigt, als die meisten anderen Prozessoren.
    Und natürlich ist das alles eine Frage der Programmiertechnik - in diesem Fall des BASIC-Interpreters - Da Du ja im Prinzip gleiche BASIC-Programme vergleichst.


    Der CBM-Geschwindigkeitsvorteil dürfte je nach Testszenario noch größer werden:
    - Meist wurde der 8088 statt des 8086 eigesetzt. Der hat nicht wie der 8086 einen 16 Bit Datenbus, sondern nur einen 8 Bit Datenbus. Dadurch sind seine Speicherzugriffe noch langsamer.
    - Der CBM 610 hat durch seine ungewöhnliche Banking-Architektur mehr zu knabbern, als ein 6502-System mit linearer Speicheraufteilung. Ein CBM 8032 mit 2 MHz (Stichwort Proxa 7000) läuft merklich schneller, als der CBM 610.


    Mein Lieblingsbeispiel für 'die Überlegenheit des PC' aus der damaligen Praxis:
    Vergleiche mal Visicalc auf einem CBM 8032 mit Multiplan auf einem PC-XT.
    Ich habe das seinerzeit leidvoll mit angesehen.
    Vom CBM mit Visicalc war ich es gewohnt, daß eine kleinere Tabelle in Sekundenbruchteilen neuberechnet wurde.
    Auf dem PC mit Multiplan habe ich fassunglos mit angesehen, wie der gleiche Vorgang mehrere Sekunden gedauert hat.
    Dieser §&@#*?! wurde uns seinerzeit als technischer Fortschrtitt verkauft.

  • Interessant ist noch folgendes Beispiel. Mit 3 verschachtelten FOR - NEXT Schleifen
    arbeitet der Commodore wie ich es erwartet habe. Nach dem durchlaufen der Schleifen
    gibt er das Ergebnis richtig aus. Der Olympia macht das nicht, jedenfalls nicht bei 3 Schleifen.
    Bei 2 funktioniert es noch.
    Übrigens, der auf dem Olympia läuft bei mir Microsoft BASIC 5.28 von 1983.

  • Krass - das ist die Art von Fehler die man in komplexeren Programmen oft vergeblich sucht, wer denkt denn an sowas? Bei Applesoft bin ich mal böse hereingefallen, als ich Variablennamen wie Pixel1 und Pixel2 (3,4) verwendet habe. Applesoft unterscheidet aber nur die ersten 2 Zeichen. Ich habe mir also meine (eine) Variable immer wieder selbst überschrieben!


    Gruß, Jochen

  • Das mit den ersten zwei Zeichen ist bei Commodore Basic auch so.
    Da ich Basic-Programmierung anhand des CBM 8032 Handbuchs gelernt habe, wusste ich das aber von Anfang an, somit ist mir das nie passiert. :D

  • Interessant ist noch folgendes Beispiel. Mit 3 verschachtelten FOR - NEXT Schleifen
    arbeitet der Commodore wie ich es erwartet habe. Nach dem durchlaufen der Schleifen
    gibt er das Ergebnis richtig aus. Der Olympia macht das nicht, jedenfalls nicht bei 3 Schleifen.
    Bei 2 funktioniert es noch.


    Naja, ich kenne jetzt beide beteiligten BASIC-Varianten nicht im Detail, aber es gibt eine plausible Erklärung: Die innere Schleife muss abwärts zählen, dafür gibt es in vielen Dialekten explizit die Option STEP mit dem Wert -1. Andernfalls stellt der Interpreter fest, dass der Zielwert schon von vorneherein überschritten ist und führt die innere Schleife gar nicht aus.
    Ich wundere mich eher, dass das Commodore da so "intelligent" mitdenkt. Wobei ich das durchaus für kritisch halte, weil man als Programmierer evtl. damit rechnet, dass solche Schleifen erst gar nicht durchlaufen werden, wenn das Ziel kleiner als der Start ist.
    Beispiel: Ein Array, dessen Index bei 1 anfängt und der durchgearbeitet werden soll:


    FOR INDEX=1 TO ANZAHL_ELEMENTE : .... : NEXT INDEX


    Wenn der Array leer ist, macht nur die zweite Version das, was der Programmierer erwartet, während die erste Version völlig unerwartet zwei Durchläufe macht und dabei noch auf undefinierte Speicherbereiche zugreift.

  • Genau, da fehlt ein STEP -1 nach dem inneren FOR...NEXT - aber ich bin auch erstaunt, dass das CBM BASIC da "mitdenkt" ...

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


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

  • Sorry, Fehler von mir. Das STEP-1 fehlt in der tat, bei beiden Computern :wand:
    Jetzt dauert die Programmausführung auch nicht einige Sekunden, sondern einige Minuten,
    auf beiden Systemen. Jetzt gibt der Olympia Computer auch das richtige Ergebnis raus.
    Wundert nur, das der eine das Ergebnis anzeigt, der andere nicht in den fehlerhaften Programmen.

  • Andernfalls stellt der Interpreter fest, dass der Zielwert schon von vorneherein überschritten ist und führt die innere Schleife gar nicht aus.
    Ich wundere mich eher, dass das Commodore da so "intelligent" mitdenkt.


    Ich frage mich schon einige Zeit, ob das Commodore Basic mitdenkt oder ein Fehler hat.


    Wenn ich ein


    FOR i = a TO b
    NEXT i


    in C schreibe, wuerde ich sowas erwarten:


    i = a
    while (i >= a && i <= b)
    {
    i++;
    }


    Dann laeuft die Schleife 1 mal durch solange i = a ist, AUCH wenn b < a ist.
    Deshalb stoert mich das Ergebnis c=0!

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

  • aber ich bin auch erstaunt, dass das CBM BASIC da "mitdenkt" ...


    Ich frage mich schon einige Zeit, ob das Commodore Basic mitdenkt oder ein Fehler hat.


    Deshalb hatte ich "intelligent" in Anführungszeichen gesetzt ;)



    Du hast das nicht nach C übersetzt, das wäre
    for (i=a;i<=b;i++) {...}
    (modulo Syntaxfehler :tüdeldü: ), sondern das Ganze in eine While-Schleife umkodiert. Im Übrigen wird diese Schleife bei b<a ebenfalls nicht durchlaufen, weil die Bedingung dann von vorneherein nicht erfüllt ist.
    Deine Vorstellung wird bei fußgesteuerten Schleifen (do .. while oder repeat .. until) Realität, wenn nämlich die Bedingung erst am Ende eines Durchlaufs getestet wird:


    i=a;
    do {
    i++;
    } while (i<=b);


    (Auch hier die Warnung: bin kein C-Fachmann ...)


    Bei for-Schleifen in BASIC ist nicht von vornherein klar, wann die Prüfung stattfindet. Gerade dort ist es m.E. durchaus möglich, dass die Prüfung am Ende der Schleife passiert - das ist implementationsabhängig, und man sollte an dieser Stelle tatsächlich die Spezifikationen der Sprache zu Rate ziehen. Oder viel testen :D

  • Du meinst hier?


    Dann laeuft die Schleife 1 mal durch solange i = a ist, AUCH wenn b < a ist.


    solange i == a ist


    Das meinte ich.
    Ich hab's mathematisch gesehen, aber in dem Zusammenhang ist i == a besser, eindeutiger, also weniger zweideutig. :-)

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

  • Du hast das nicht nach C übersetzt, das wäre
    for (i=a;i<=b;i++) {...}
    (modulo Syntaxfehler :tüdeldü: ), sondern das Ganze in eine While-Schleife umkodiert.


    Ich habe nicht gesagt, ich uebersetze die BASIC FOR NEXT.
    Ich habe geschrieben, ich erwarte. Genau deshalb hab ich es als while geschrieben.


    Aber ich kann auch for nehmen, macht genau das gleiche:
    for ( i = a; i >= a && i <= b; i++) { }


    Aber wie auch immer:
    M.E., wenn ich in BASIC
    FOR i = 100 TO 1
    sind alle i im Bereich 1 - 100 gueltig. Und dann muss die Schleife 1 mal durchlaufen werden.


    In der o.g. for() waere das:
    for ( i = 100; i>= 100 && i <= 1; i++) { }

    DENKFEHLER!! Stimmt, hab vorhin Bloedsinn geschrieben.


    Je nachdem ob while() oder do-while() gibt's Unterschiede.
    Trotzdem lass ich meine obige Aussage fuer die gueltigen Werte 1 bis 100 stehen.



    Spezifikationen der Sprache


    BASIC und Spezifikationen? Mal was ganz neues. :-)



    Schoenen Abend

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

  • Du meinst hier?



    solange i == a ist


    Das meinte ich.
    Ich hab's mathematisch gesehen, aber in dem Zusammenhang ist i == a besser, eindeutiger, also weniger zweideutig. :-)


    :D:D:D
    Nein, das meinte ich nicht. Im Fließtext brauche ich kein ==, weil der Kontext ganz klar auf einen Vergleich hinweist und keine Zuweisung ;)


    Nein, es ging um Deine Bedingung im while:


    (i>=a && i<=b)


    Diese Bedingung ist falsch, wenn i=a ist und b<a, denn dann ist "i<=b" nicht erfüllt. Und es werden beide Teile der Bedingung geprüft.
    (Was übrigens auch nicht immer der Fall ist, die sog. Kurzschlussauswertung kann dazu führen, dass Teile solcher Ausdrücke nicht ausgewertet werden, wenn das Ergebnis vorher schon feststeht. Wär hier aber irrelevant, denn hier ist der zweite Teil eben sehr wichtig.
    Ich selber kenne das von Object Pascal, da kann man das dann per Compilerschalter aktivieren oder deaktivieren, weil es auch unangenehme Nebeneffekte haben kann.)

  • Ich habe geschrieben, ich erwarte.


    BASIC und Spezifikationen? Mal was ganz neues.


    Du meinst Spezifikation im Sinne von Norm? Das habe ich durchaus auch in Frage gestellt. Aber dann solltest Du auch nicht zu viel erwarten. ;)


    Ich meinte die Spezifikation der jeweiligen Implementierung, die gibt es durchaus und zum Teil auch sehr präzise. Da wird genau beschrieben, wann die Laufvariable inkrementiert wird, wann und wie oft die Bedingungen überprüft werden können, ob die Laufvariable geändert werden darf etc.


    Edit: sorry, ich habe tatsächlich "Sprache" geschrieben, wo ich "Implementierung" im Kopf hatte.

  • Nein, es ging um Deine Bedingung im while:


    (i>=a && i<=b)


    Diese Bedingung ist falsch


    Wie vorher schon geschrieben, ist mir da ein Denkfehler unterlaufen.


    Ich sag immer: Nur ein gefundener Fehler ist ein guter Fehler!


    In diesem Sinne

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

  • Das Programm habe ich aus dem Buch "BASIC Computer Games".
    Als PDF gibt es das Buch hier .
    Es steht auf Seite 100 und heißt dort LIFE.


    Das habe ich jetzt abgetippt und es verhält sich unter Locomotive BASIC 1.1 und Microsoft BASIC-80 Rev. 5.21 genau so wie in dem abgedruckten Beispiel:


    Die Ausgabe INVALID taucht bei allen Generationen ab der 23. auf, es geht aber dennoch weiter. Habe ich etwa einen Tippfehler drin, oder verhält sich das Programm bei Euch genauso?


    Schönes Wochenende,
    Mr. AMS

  • Nach meinem Verständnis tauch die INVALID Meldung auf, wenn Teile der Population den Rand des Bildschirms erreichen und dort gestoppt werden, um einen Überlauf in den Routinen zum Anzeigen zu vermeiden. Wenn man stattdessen eine Wrap-Around Logik einbaut (also was nach unten aus dem Bildbereich herauswandert, kommt von oben wieder herein) kann man die INVALID Meldung weglassen.


    Gruß, Jochen