Primzahlenberechnung in BASIC (wie SM Baker on a Z8000 CoPro)

  • Ja, das ist gar nicht so doof ... und funktioniert. Es ist nur halt auf 8Bit Maschinen recht sinnlos, weil Du den Zahlenraum in Bits / für echte Binärzahlen da flott ausschöpfst. Und dazu kommt dann, daß große Zahlen da ein anderes internes Format benutzen.Das heißt natürlich nicht, daß man das nicht trotzdem so machen kann und dann jeweils umwandeln.

    Ist auf alle Fälle ein schöne Variante - und wohl auch ziemlich schnell.

    -- 1982 gab es keinen Raspberry Pi , aber Pi und Raspberries

  • und mit Timings


    "all" ist die ganze Sieb Berechnung, aber ohne die Ausgabe der Zahlen

    "ohne DIM" ist ohne die Vorbelegung des Arrays mit "1" Werten


    Sieb des Erathostenes 200 Primzahlen , 4,7 sec 1000 Primzahlen , 26,6 sec
    ge-"modd"-et nach #23 200 Primzahlen , 3,4 sec 1000 Primzahlen , 19,0 sec




    ist ja mal eindeutig ...





    d64 File ist im Anhang

  • Genau, ich schrieb „I“, meinte aber „2*I“ (sonst markiert man ja die Primzahl auch aus). Alle N * I mit N<I wurden ja in vorangegangenen Schleifen schon behandelt.


    Wenn man bei 2*I = I+I anfängt, verliert man zwar etwas Zeit, hat aber einen Algorithmus, der komplett ohne Multiplikation und Division auskommt. Wenn dann das BASIC noch mit echten Integerzahlen und Integerarithmeik rechnet ( zB Atari GFA Basic) sollte es echt flott gehen. Und es schreit geradezu nach Assemblerprogrammierung ! Man braucht halt viel Speicher


    Roland

  • Zur Information anbei eine Grafik, die ich vor ein paar Jahren mal aus BYTE Sieve Benchmark-Ergebnissen zusammengestellt habe.

    Ich habe gerade nochmal mein Postscript Programm auf unserem Büro-Kopierer/Scanner laufen lassen und der braucht 0.14 Sekunden für die 10 Durchläufe...etwa so viel wie eine CRAY-1.


    Das zweite Textdokument ist der BYTE Artikel mit Folgeartikeln in kompakter und besser lesbarer Form (die Original-Scans sind 18 MB groß und wegen Farbscan etwas unscharf) mit ein paar Ergänzungen von mir.


    Im Programm werden jeweils nur die 2-er Zahlen übersprungen, der Rest ist der klassische Eratosthenes Algorithmus wie man ihn z.B. im Knuth findet.

    Es werden dabei die 1899 Primzahlen zwischen 3 und 16384 gefunden und der Test wird 10 mal wiederholt, um eine messbare Zeiten zu bekommen.


    Der Benchmark war 1983 im BYTE Magazin veröffentlicht worden und diente dann viele Jahre als Referenz um schnell mal Integer-Leistungen von Rechnern und Programmiersprachen zu vergleichen.

    Es geht dabei nicht darum, den schnellsten Primzahlentest zu haben, sondern einen gleichen Algorithmus auf unterschiedlichen Rechnern/Compilern/Interpretern zu vergleichen.


    Martin


    PS: Die Original BYTE Kopien von 1983 gibt es natürlich auf z.B. archive.org.

  • guidol - Sehe den Thread jetzt erst mir genauer an.... Du hast ein echtes Programmier-Sakrileg begangen !!!


    10 REM "Calulate Primenumbers"

    15 CLS

    16 SM=TIMER

    20 PRINT "Calculate Prime-Numbers up to which Limit?"

    30 INPUT L

    40 +-FOR N=3 TO L

    50 + +-- FOR D=2 TO(N-1)

    60 | | IF(INT(N/D)*D)=N THEN GOTO 100

    70 + +-- NEXT D

    80 | PRINT N;"-";

    90 | GOTO 110

    100 | REM

    110 +-NEXT N

    120 PRINT

    130 PRINT "Limit has been reached."

    131 EM=TIMER-SM

    132 PRINT "It took ";EM/1000;" secs"

    140 END


    Das ist das Originallisting (abgesehen von "TIMER") des ersten Beitrags. Ich hab' mal versucht, das mit "ASCII-Mitteln" zu verdeutlichen.

    Du springst aus dem inneren einer Schleife bei Zeile 60 über das abschliessende NEXT hinweg.

    Was meinst Du was beim BASIC-Interpreter dann passiert ?

    Da gibt es u.a. auch einen Stack. Dort werden bspw. Rücksprungadressen oder auch Variableninhalte zwischengespeichert, sozusagen je nach Situation.

    Ein PASCAL-Compiler würde das trotz angepasster Syntax nicht kompilieren, weil er das erkennen würde.

    Für solche Sachen wurde eigentlich die WHILE Schleife erfunden.

    Die Zeile 90 kannst Du Dir übrigens komplett sparen.

    "The biggest communication problem is we do not listen to understand. We listen to reply." - Stephen Covey


    Webseite und Blog ist immer noch - seit fast 20 Jahren - online.

  • Ich habe die Aenderungen gerade mal von MBASIC in die IoTBASIC Version von slenz auf dem ESP32-Lite uebernommen:



    Enter Prime-Number Limit:

    ?1000

    It took 0.25699 secs


    ?2000

    It took 0.521 secs


    ?5000

    It took 1.32799 secs


    ?10000

    It took 2.697 secs


    ?16000

    It took 4.373 secs


    Fuer mehr reicht der Speicher bei der DIM Anweisung nicht ;)


  • Du springst aus dem inneren einer Schleife bei Zeile 60 über das abschliessende NEXT hinweg.

    Was meinst Du was beim BASIC-Interpreter dann passiert ?

    ;) Ich hatte es vom SM Baker Listing im YT-Video nur blind eingetippt und nicht auf die Logik geschaut - Sorry :)

  • Hier mal von der BYTE das Programm. Ergebnis ist kompiliert in QB 4.5 fast nicht messbar (unter 1 Sekunde).

    Mit dem PC-BASIC unter Windows (was bekanntermaßen langsam ist) kann man aber richtig große Sekundenzahlen erreichen ;)


    Das Listing ist nur mit einer Abfrage am Anfang (wieviele Iterationen) ergänzt, außerdem mit der Ausgabe der Prim-Zahlen und mit der Laufzeit.

    Eventuell muss dann wieder das "TIMER" gegen was gleichwertiges getauscht werden, wenn Du das in anderen BASIC-Interpreter/Compiler laufen lässt.

    Der Screenshot bezieht sich auf EINEN Durchlauf (anfängliche Eingabe = 1).


    5 DEFINT A-Y

    10 DIM FLAGS(8191)

    20 INPUT "How many iterations ? ",N

    25 Z=TIMER

    30 FOR M = 1 TO N

    40 COUNT = 0

    50 FOR I = 0 TO 8190

    60 FLAGS(I) = 1

    70 NEXT I

    80 FOR I = 0 TO 8190

    90 IF FLAGS(I) = 0 GOTO 170

    100 PRIME = I + I + 3

    105 PRINT PRIME;:IF I>=8189 THEN PRINT ELSE PRINT ",";

    110 K = I + PRIME

    120 WHILE K <= 8190

    130 FLAGS(K) = 0

    140 K = K + PRIME

    150 WEND

    160 COUNT = COUNT + 1

    170 NEXT I

    180 NEXT M

    190 PRINT "BYTE Sieve: ";COUNT;"primes in";TIMER-Z;"secs"

    200 END


    Das hier läuft in PC-BASIC/MBASIC/BASICA/GWBASIC/QBASIC.

    "The biggest communication problem is we do not listen to understand. We listen to reply." - Stephen Covey


    Webseite und Blog ist immer noch - seit fast 20 Jahren - online.

  • Hier eine Variante, die trotz einem DIM von 255 Primzahlen bis 2.7 Millionen rechnen koennen soll :)


    braucht ca. die doppelte Zeit (8.6sec zu 4.3sec) fue die Primzahlen bis 16000 auf dem ESP32-Lite:

    It took 8.68799 secs

  • ... machen die BASIC Versionen eigentlich einen Unterschied wenn man explizit Integer Variablen verwendet?


    Beispielsweise durch "I%" anstelle von "I"? Oder durch DIM I AS INTEGER bei neueren BASICs.


    Die ganze Rechnerei bis zu ca. 16000 braucht ja keine Fließkommazahlen weil nur maximal I+I+3 summiert wird (in der BYTE Version).

    Wenn man nichts deklariert, verwenden die meisten BASICs ja ihren Standardtyp, der dann eher eine REAL Fließkommazahl ist.


    Bei den "modernen" BASIC Varianten für die Microcontroller weiß ich nicht, ob die da überhaupt unterscheiden - wenn nicht sind sie natürlich viel langsamer als sie sein müssten.

  • Da gab es mal Regeln, wie man schnell checken kann, ob sich durch 3,7,9 teilen lässt?

    3: Wenn die Quersumme der Zahl durch 3 teilbar ist, ist auch die Zahl durch 3 teilbar. Man kann die Quersummenbildung so oft wiederholen, bis das Ergebnis einstellig ist. 3,6,9 -> teilbar, Rest -> nicht teilbar.

    7: kenne ich keine Regel für

    9: unnötig, da 9 keine Primzahl. Alles was durch 9 teilbar wäre, fällt schon bei 3 raus.

  • Da gab es mal Regeln, wie man schnell checken kann, ob sich durch 3,7,9 teilen lässt?

    3: Wenn die Quersumme der Zahl durch 3 teilbar ist, ist auch die Zahl durch 3 teilbar. Man kann die Quersummenbildung so oft wiederholen, bis das Ergebnis einstellig ist. 3,6,9 -> teilbar, Rest -> nicht teilbar.

    7: kenne ich keine Regel für

    9: unnötig, da 9 keine Primzahl. Alles was durch 9 teilbar wäre, fällt schon bei 3 raus.

    Gemeint war natürlich z.B. 29, was nicht durch 3 teilbar ist.

    Teilbar durch 6 entfällt, da keine geraden Zahlen bearbeitet werden

    Teilbar durch 9: stimmt natürlich


    "Eine Zahl ist durch 7 teilbar, wenn diejenige Zahl durch 7 teilbar ist, die du erhältst, wenn du das Doppelte der letzten Ziffer vom Rest der Zahl abziehst. So wäre zum Beispiel bei 161 das Doppelte der letzten Ziffer 2, und 16 − 2 = 14 16-2=14 16−2=14."


    Tatsächlich müssen nur gerade Zahlen rausgeworfen werden und alle die auf 5 enden. Der Rest könnte mit der 3 und 7 Regel geprüft werden.

    Ich gehe mal davon aus, dass genau dass in dem Quelltext steht, da muss ich mich aber erst einlesen, kann nur VB, C++ und HTML.


    Wie sieht es eigentlich hiermit aus?

    Sieb von Atkin – Wikipedia

    ::solder::Ich "darf" beruflich basteln...

  • Da gab es mal Regeln, wie man schnell checken kann, ob sich durch 3,7,9 teilen lässt?

    3: Wenn die Quersumme der Zahl durch 3 teilbar ist, ist auch die Zahl durch 3 teilbar. Man kann die Quersummenbildung so oft wiederholen, bis das Ergebnis einstellig ist. 3,6,9 -> teilbar, Rest -> nicht teilbar.

    7: kenne ich keine Regel für

    9: unnötig, da 9 keine Primzahl. Alles was durch 9 teilbar wäre, fällt schon bei 3 raus.


    da gibt es noch mehr (ist allerdings eher was für das Kopfrechnen und hilft hier nicht):


    Eine Zahl mit 4 - 6 Stellen ist durch 7 (bzw 11, bzw 13) teilbar, wenn der Absolutwert der Differenz der ersten 3 Stellen und der nächsten 3 Stellen durch 7 (bzw 11, bzw 13) teilbar ist


    Beispiel 592.696

    ABS (592 - 696) = 104


    104 ist 8*13, also ist 592696 durch 13 teilbar (13*45.492)


    Beispiel 56.791

    ABS(56 - 791) = 735

    735 ist 7*105, also ist 56.791 durch 7 teilbar (7*8.113)


    Warum ist das so ? Kleiner Tip: schaut euch mal das Produkt 7*11*13 an !


    Roland

  • Ich habe früher auf dem PC viel mit UBASIC in der Richtung experimentiert.

    Gibt es irgendeinen Trick, wie man den Start-Screen mit der Versionsnummer laenger sehen kann?

    Vom UBASIC habe ich nun v8.74, 8.8 und 9

    Bei der 9 sehe ich kurz sowas blitzen wie 9.4c - aber hier in der DOSBOX gehts dann gleich immer auf einem neuen Screen zu:

    Words for long variables 844 (Words for internal calculation 844)

    Free text area = 37455 bytes

  • in der DOSbox : Ctrl + PageDown setzt die Zahl der Zyklen runter, die die Emulation benutzen darf. Es wird dann alles langsamer. Ctrl + PageUp setzt das wieder in die andere Richtung hoch. D.h.: vorm Start mal CTRL+SeiteRunter Key bemühen, sollte evtl was bringen.


    Kann auch sein, daß das nicht die Originalbelegung ist: Man kann aber mit Ctrl+F1 die Keys ansehen/einstellen. DecCycles und IncCycles sind die Buttons dafür.

    -- 1982 gab es keinen Raspberry Pi , aber Pi und Raspberries

  • ... machen die BASIC Versionen eigentlich einen Unterschied wenn man explizit Integer Variablen verwendet?


    Beispielsweise durch "I%" anstelle von "I"? Oder durch DIM I AS INTEGER bei neueren BASICs.


    Die ganze Rechnerei bis zu ca. 16000 braucht ja keine Fließkommazahlen weil nur maximal I+I+3 summiert wird (in der BYTE Version).

    Wenn man nichts deklariert, verwenden die meisten BASICs ja ihren Standardtyp, der dann eher eine REAL Fließkommazahl ist.


    Bei den "modernen" BASIC Varianten für die Microcontroller weiß ich nicht, ob die da überhaupt unterscheiden - wenn nicht sind sie natürlich viel langsamer als sie sein müssten.



    Das ist das, was ich oben mal mit "Umbau auf Chars" oder "Poken" sagen wollte.


    Natürlich macht das einen gewaltigen Unterschied. Und wenns nicht beim Speed ist (was es aber machen müßte), dann zumindest beim verfügbaren RAM, der plötzlich Faktor 5 oder so "mehr" wird - was natürlich für so ein Sieb praktisch ist.


    Das normale BASIC kennt das aber nicht. I% bzw. DIM AS INTEGER sind schon eher solche Mid-80s Konstrukte. Die kamen wohl erst nach dem großen Erfolg von PASCAL.

    -- 1982 gab es keinen Raspberry Pi , aber Pi und Raspberries

  • Gibt es irgendeinen Trick, wie man den Start-Screen mit der Versionsnummer laenger sehen kann?

    Vom UBASIC habe ich nun v8.74, 8.8 und 9

    Bei der 9 sehe ich kurz sowas blitzen wie 9.4c - aber hier in der DOSBOX gehts dann gleich immer auf einem neuen Screen zu:

    Words for long variables 844 (Words for internal calculation 844)

    Free text area = 37455 bytes

    Die Versionsnummer steht als String in der Datei, ein Blick mit einem Hex-Editor ans Ende der Datei ist am einfachsten.

  • Die Versionsnummer steht als String in der Datei, ein Blick mit einem Hex-Editor ans Ende der Datei ist am einfachsten.

    Ja ;) ist wie bei MBASIC - haette ja eine einfache Moeglichkeit geben koennen :) z.B. ein VER Befehl....


    Also hier die 9er Version, die ich habe:

    UBASIC86(32) for IBM-PC version 9.0w

    Copyright 1998 by Yuji KIDA


    und

    UBASIC86(32) for IBM-PC version 8.74

    UBASIC86(32) for IBM-PC version 8.8c


    aber UBASIC geht schon bei kleinen Zahlenbereichen der Speicher fuer DIM aus :(

    Enter Prime-Number Limit:

    ? 200

    91:54:52

    Variable area full. in 140


    LIST 140

    140 dim A(L)


    GW-BASIC unter vDOS schafft es mit DIM auf bis zu 15000 ;)

  • @guidol Probier mal, alle Integer-Variablen mit Prozent am Ende zu schreiben. Also DIM A%(L%). Dann geht bestimmt mehr.


    Ich fand damals solche Leistungen in ca. 2 Sekunden schon bemerkenswert:

  • hier mal noch probehalber mit POKEs ; bringt aber nicht wirklich wesentlich was (geht sicher noch bißchen besser)


    im Vergleich mit dem normalen BASIC Array() - was ja dann immer eine Fließkommazahl ist - hätte man da wohl mehr (d.h. hier weniger Zeit) erwartet , ist aber stattdessen ziemlich genau der gleiche Sekundenwert geworden



    Sieve + Modd mit POKEs 200 Primzahlen ; 3,6 sec
    1000 Primzahlen ; 19,6 sec
  • im Vergleich mit dem normalen BASIC Array() - was ja dann immer eine Fließkommazahl ist - hätte man da wohl mehr (d.h. hier weniger Zeit) erwartet , ist aber stattdessen ziemlich genau der gleiche Sekundenwert geworden

    Warum hattest du einen Geschwindigkeitsvorteil erwartet? Alle Berechnungen werden bei POKE und PEEK doch nach wie vor als Fließkomma durchgeführt.

    Du hast sogar noch mehr Fließkomma/Integer-Umwandlungen, als wenn du alles in einem Fließkomma-Array speicherst. Ich hätte daher sogar erwartet, dass es langsamer wird.

    Das einzige, was du sparst, ist Platz. Aber das könnte man genauso mit einem Integer-Array erreichen, also A%(). Auch das spart nur Platz, bringt aber keinen Geschwindigkeitsvorteil.

    • i-Telex 7822222 dege d

    • technikum29 in Kelkheim bei Frankfurt

    • Marburger Stammtisch

    Douglas Adams: "Everything, that is invented and exists at the time of your birth, is natural. Everything that is invented until you´re 35 is interesting, exciting and you can possibly make a career in it. Everything that is invented after you´re 35 is against the law of nature. Apply this list to movies, rock music, word processors and mobile phones to work out how old you are."

  • Ich habe aber auch mal ausprobiert ob der oft zitierte GOTO Sprung aus einer FOR/NEXT Schleife Speicherverlust bedeutet : beim MSBASIC 5.28 und GW-BASIC verliert man da keinen Speicher. Das scheint also wohl auch so ein urbaner Mythos zu sein. ::vodoo::


    Es mag sicher einzelne BASICs geben, bei denen das Problem der verlorenen FOR Schleifenparameter auf dem Stapel auftritt, das gilt aber nicht generell.


    Da bin ich ja froh, denn ohne ungestraftes GOTO wäre BASIC ja kein BASIC.


    Man kann das leicht mit einem kleinen Programm und der FRE() Funktion vor und nach der Schleife ausprobieren.


    Wenn man es noch härter testen möchte, und der FRE(0) Funktion magische Heilkräfte zuschreibt, definiert man am Anfang noch ein möglichst großes Feld, z.B. mit DIM X(16500) sodass beim ersten FRE(0) nur noch ein paar Bytes RAM übrig bleiben. Dann müsste das Testprogramm abstürzen sobald der Stapelspeicher ausgeht.

  • Man kann das leicht mit einem kleinen Programm und der FRE() Funktion vor und nach der Schleife ausprobieren.

    Falls wir von Commodore Basic 2 sprechen:


    Die Schleifenvariablen werden nicht im Speicher sondern auf dem Prozessor-Stack abgelegt. Bei FRE(0) siehst du das gar nicht.

    Du müsstest die Schleife auch gar nicht bis 16000 laufen lassen, denn bei einer Schachtelungstiefe von 8 ist nach meiner Erinnerung Schluss.

    In deinem Beispiel heilt sich vermutlich der Stack, weil du nicht schachtelst, sondern immer wieder die gleichen Schleifenvariablen verwendest.


    Ein aussagefähiger Test sähe ungefähr so aus:

    Mehr als 8 Schleifen hintereinander mit unterschiedlichen Schleifenvariablen, aus denen jeweils rausgesprungen wird. Dann sollte ein Überlauf passieren.


    Das sind jetzt auch nur theoretische Überlegungen, die ich nicht ausprobiert habe. Und meine Erinnerung über die genau Arbeitsweise von Basic 2 ist auch schon ziemlich verblasst. Kann also sein, dass ich auch daneben liege.


    EDIT: Ich hab's jetzt doch gerade mal ausprobiert und 20 Schleifen mit unterschiedlichen Schleifenvariablen hintereinander gepackt, die alle mit GOTO verlassen werden. Nach 10 Schleifen kommt der Out of Memory Error. Das kann auch gar nicht anders sein, weil für den Interpreter sind das 10 geschachtelte Schleifen.

    In der Praxis dürften solche Konstrukte aber selten auftreten. Ich denke, sobald man eine Schleifenvariable noch mal verwendet, wird bis zu dem Punkt der Stack bereinigt. Von daher hat das nicht so die große Relevanz.


    Aber mit dem Primzahlenproblem hat das nicht mehr viel zu tun. Deswegen sollten wir das hier nicht weiter vertiefen.

    • i-Telex 7822222 dege d

    • technikum29 in Kelkheim bei Frankfurt

    • Marburger Stammtisch

    Douglas Adams: "Everything, that is invented and exists at the time of your birth, is natural. Everything that is invented until you´re 35 is interesting, exciting and you can possibly make a career in it. Everything that is invented after you´re 35 is against the law of nature. Apply this list to movies, rock music, word processors and mobile phones to work out how old you are."

    3 Mal editiert, zuletzt von detlef ()

  • Es mag sicher einzelne BASICs geben, bei denen das Problem der verlorenen FOR Schleifenparameter auf dem Stapel auftritt, das gilt aber nicht generell.

    Ja, z.B. das Microsoft BASIC 2 vom C64!

    -------------------------------------------------------------------------------
    Suche Rechentechnik aus Deutschland, bzw. Computer Deutscher Hersteller - z.B.

    ANKER, AKKORD, CTM (CTM 70, CTM 9000, CTM 9032), DIEHL/ DDS, DIETZ, FEILER, ISE,
    HOHNER GDC, KIENZLE, KRANTZ, NIXDORF, OLYMPIA, PCS/CADMUS, RUF, SALOTA, S.E.I.,
    SIEMAG, SIEMENS, TAYLORIX, TRIUMPH ADLER - TA, WAGNER, WALTHER, WANDERER,...

    -------------------------------------------------------------------------------

  • Naja, das ist in Commodore bzw. Microsoft Basic schon ganz schlau gelöst, dass das den Stack irgendwie selber bereinigt.

    Ich hatte mir das damals beim PET mal angeschaut (im BASIC-ROM), aber leider fast alles vergessen.

    • i-Telex 7822222 dege d

    • technikum29 in Kelkheim bei Frankfurt

    • Marburger Stammtisch

    Douglas Adams: "Everything, that is invented and exists at the time of your birth, is natural. Everything that is invented until you´re 35 is interesting, exciting and you can possibly make a career in it. Everything that is invented after you´re 35 is against the law of nature. Apply this list to movies, rock music, word processors and mobile phones to work out how old you are."

    Einmal editiert, zuletzt von detlef ()