Forth Benchmarks
Vintage Computer Festival Europa 2011
30 April 2011
Forth Benchmarks
Warum?
Forth Versionen
Forth Crashcourse
Forth Kernel
Benchmarks
Warum Forth Benchmarks
Hackerfunk.ch im Dezember 2010
Warum Forth Benchmarks
Eine Diskussion über Z80 und 6502
Warum Forth Benchmarks
die MHz Angabe einer CPU sagt wenig über die Leistungsfähigkeit aus
Warum Forth Benchmarks
Assembler Benchmarks sind schwer portierbar zwischen CPU Architekturen
Warum Forth Benchmarks
Forth ist auf den meisten CPU Architekturen vorhanden
Warum Forth Benchmarks
Forth ist besser standardisiert als z.B. BASIC
Forth Versionen
Forth 77
Forth Versionen
FIG-Forth (FIG = Forth Interest Group)
Forth Versionen
Forth 79
Forth Versionen
Forth 83
Forth Versionen
ANSI Forth (1994)
Forth Versionen
Forth 200x
Forth Versionen
Forth ist immer erweiterbar
eine fehlende Funktion kann nachgerüstet werden
aus einem Forth 77 System kann ein Forth 83 (oder ein Forth 200x) System entstehen
ein Forth System veraltet nicht!
Forth Crashcourse 1
Eine kurze Einfuehrung in Forth
die Befehle (Wörter) der Benchmarkprogramme werden erklaert
Syntax
Ein Wort ist eine Sequenz von beliebigen Zeichen (außer Leerzeichen).
Ein "WORT" ist die Funktionseinheit eines Forth Systems (vergleichbar mit Prozeduren oder Funktionen)
Wörter werden durch Leerzeichen voneinander getrennt.
gültige Forth Wörter:
- wort
- !@#$%^&*()
- 1234567890
- VCFe12-Benchmark
Sicherheit
Wichtig: in Forth gibt es nur die Sicherheitsnetze, welche der Programmierer selbst anbringt
d.h. normalerweise KEINE!
Forth steht dem Programmierer nicht im Weg
Was ist Forth
Ein ultimativ erweiterbares Programmiersystem
wenig Regeln, keine Syntax
der Programmierer hat volle Kontrolle über Forth .... und das System
Stack
Das auffälligste Merkmal von Forth ist der Stack (Stapelspeicher). Wenn man eine Zahl eintippt, wird diese auf den Stack geschoben.
Der Stack ist ein LIFO (Last In, First Out) Speicher.
Mit ".s" kann man sich den Inhalt des Stacks anschauen.
1 2 3 .s
“.” (Dot)
Mit “.” kann man die Zahl des jeweils obersten Stackelements (TOS, Top of Stack) ausdrucken
1 2 3 . . . [RTN]
Arithmetik
Die arithmetischen Operatoren +, -, *, / und mod arbeiten immer auf den obersten beiden Stack-Elementen (Postfix-Schreibweise):
2 2 + . [RTN]
2 1 - . [RTN]
7 3 mod . [RTN]
Arithmetik 2
Klammern sind überflüssig, die Reihenfolge der Ausführung und die Operanden ergeben sich eindeutig durch die Anordnung der Wörter:
3 4 + 5 * .
3 4 5 * + .
Stackkommentare
Bei der Dokumentation von Forth Wörtern werden die Änderungen des Stacks in Klammern angedeutet
Beispiele:
. ( n -- )
+ ( n n - n )
SWAP
vertauscht die beiden obersten Elemente des Stacks
SWAP ( x y -- y x )
DUP
erstellt vom obersten Stack-Element eine Kopie
DUP ( x -- x x )
DROP
entfernt das oberste Stack-Element (spurlos)
DROP ( x -- )
OVER
legt eine Kopie des 2ten Stackeintrages auf den Stack
OVER ( x1 x2 - x1 x2 x1 )
NIP
entfernt das zweit-oberste Stack-Element (wieder spurlos)
NIP ( x y -- y )
TUCK
schiebt eine Kopie des obersten Stack-Elements unter das zweite Element
TUCK ( x1 x2 -- x2 x1 x2 )
ROT
rotiert die obersten 3 Stackelemente
ROT ( x1 x2 x3 -- x2 x3 x1 )
-ROT
rotiert die obersten 3 Stackelemente (andersherum)
-ROT ( x1 x2 x3 -- x3 x1 x2 )
Kommentare
\ das ist ein Kommentar bis zum Zeilenende
( das ist ein Kommentar bis zur schliessenden Klammer ) .s
.( Dieser Kommentar wird bei der Ausführung ausgegeben )
\, ( und .( sind normale Forth-Wörter und muessen daher durch Leerzeichen vom nachfolgenden Text getrennt werden.
Wörter definieren
Definitionen sind das Äquivalent zu Prozeduren in anderen Programmiersprachen:
: quadrat ( n -- n^2 ) dup * ;
5 quadrat .
7 quadrat .
Wörter definieren (2)
“:” startet die Definition,
quadrat ist der Name des neuen Forth Wortes.
Der Kommentar beschreibt den Stack-Effekt
Die Worte "dup *" werden nicht ausgeführt, sondern in die Definition hineincompiliert.
: quadrat ( n -- n^2 ) dup * ;
Wörter definieren (3)
Das neu definierte Wort kann man genauso verwenden wie ein “eingebautes” Wort, man kann es natürlich auch in weitere Definitionen einbauen:
: zur-dritten ( n -- n^3 ) dup quadrat * ;
-5 zur-dritten .
: zur-vierten ( n -- n^4 ) quadrat quadrat ;
3 zur-vierten .
Wörter umdefinieren
Neue Wörter mit Namen von bestehenden Wörtern überlagern die bestehenden.
Neue Definitionen benutzen die neuen Wörter, schon eingebaute benutzen weiterhin die alte Definition.
: * + ;
5 quadrat . [RTN] 25
5 5 * . [RTN] 10
WORDS
listet alle Wörter, die Forth kennt, sortiert von jüngsten zu den ältesten Definitionen
der Befehl heisst in FIG-FORTH/FORTH-77/79 Systemen "VLIST"
WORDS ( -- )
FORGET
FORGET ccc ( -- )
löscht die Definition von “ccc” und alle Definitionen, die nach “ccc” definiert wurden! Redefinierte Wörter werden wieder sichtbar.
FORGET *
5 5 * . [RTN] 25
Constant
CONSTANT ccc ( n -- )
definiert ein Konstanten-Wort mit dem Namen “ccc” und dem Wert “n”
wird die neue Konstante als Wort benutzt, legt sie ihren Wert auf den Stack
12 CONSTANT DUTZEND [RTN]
DUTZEND ( -- 12 )
Variable
VARIABLE ccc ( -- ) ( F83/ANSI Forth )
definiert eine Variable mit dem Namen “ccc”, oder
VARIABLE ccc ( n -- ) ( FIG/F79 Forth )
definiert eine Variable mit dem Namen “ccc” und dem Wert “n”
Variable (2)
VARIABLE BETRAG [RTN]
BETRAG ( -- addr )
legt die Speicheradresse der Variable auf den Stack
! (STORE)
! ( x addr -- )
schreibe den Wert x in die Speicherstelle mit Adresse “addr”
200 BETRAG !
speichert den Wert 200 in die Variable “BETRAG”
@ (FETCH)
@ ( addr -- x )
legt den in der Speicherstelle “addr” gepeicherten Wert auf den Stack
BETRAG @ . [RTN] 200
liest den Wert der Variable “BETRAG” und gibt den Wert am Bildschirm aus
+! (PLUS-STORE)
+! ( n addr -- )
addiert den Wert “n” zum Wert in der Speicherstelle “addr”
10 BETRAG +!
Speicherzugriff
@, !, +! funktionieren mit Variablen aber auch mit jeder anderen Speicherstelle sie sind die Forth-Entsprechung für (Basic) “PEEK” und “POKE”
Kontrollstrukturen
Kontrollstrukturen können in Forth nur in Definitionen verwendet werden (nicht im interaktiven Modus). Eine IF-Struktur sieht so aus:
: abs ( n1 -- +n2 )
dup 0 < if
negate then ;
5 abs .
-5 abs .
Kontrollstrukturen (2)
IF nimmt ein Flag vom Stack. Ist es ungleich 0 ("wahr"), wird der folgende Code ausgeführt, ansonsten zum zugehörigen THEN (oder ELSE) gesprungen.
“<” vergleicht die beiden obersten Stackelemente und produziert ein Flag:
1 2 < .
2 1 < .
1 1 < .
Kontrollstrukturen (3)
weitere Vergleichsworte sind =, >, <>, <=, >= (nicht alle Kombinationen aus Typen und Vergleichsworten sind Standard Forth Wörter, können aber bei Bedarf einfach erzeugt werden).
Kontrollstrukturen (4)
Optional kann man auch einen ELSE-Abschnitt verwenden:
: min ( n1 n2 -- n )
2dup < if
drop
else
nip
then ;
Anmerkung: Der Stackkommentar von 2dup ist
( n1 n2 -- n1 n2 n1 n2 )
Logische Operatoren
Ein true-Flag hat alle bits gesetzt, false keines (F83/ANSI Forth):
hex true u. decimal true . false .
Anmerkung: in FORTH77/79 und FIG-Forth ist true "1"
Anmerkung: jede Zahl ungleich "0" wird als logischtrue interpretiert
Logische Operatoren (2)
Zum Verknüpfen von Flags kann man die Wörter AND, OR, XOR und 0= und INVERT verwenden. Dabei arbeiten AND, OR, XOR, und INVERT bitweise, produzieren also nur aus wohlgeformten Flags wieder neue gültige Flags:
1 2 and .
1 2 or .
1 3 xor .
1 invert .
Logische Operatoren (3)
0= dagegen nimmt beliebige Zahlen als Eingabe und produziert ein Flag.
1 0= .
Um aus einer Zahl ein wohlgeformtes Flag zu machen, verwendet man 0<>:
1 0<> .
Logische Operatoren (4)
Die Eigenschaft "alle bits gesetzt" kann man verwenden, um IFs zu vermeiden:
: foo ( n1 -- n2 ) 0= if 14 else 0 then ;
0 foo .
1 foo .
Ohne IF
: foo ( n1 -- n2 ) 0= 14 and ;
0 foo .
1 foo .
Schleifen
Die einfachste Schleife ist die Endlosschleife:
: endless ( -- )
0 begin
dup . 1+
again ;
endless
BEGIN macht nichts (zur Laufzeit), AGAIN springt zurueck zum BEGIN.
Schleifen (2)
Eine Schleife mit einer Ausstiegsbedingung an beliebiger Stelle sieht so aus:
: log2 ( +n1 -- n2 )
2 / 0 begin
over 0>
while
1+ swap 2 / swap
repeat nip ;
7 log2 .
8 log2 .
WHILE konsumiert ein Flag; ist es gleich 0 (falsch), wird hinter dem REPEAT fortgesetzt. REPEAT springt zurück zum BEGIN, wie AGAIN.
Schleifen (3)
Und hier ist eine Schleife mit Ausstieg am Ende:
: log2 ( +n1 -- n2 )
-1 begin
1+ swap 2 / swap
over 0 <= until
nip ;
UNTIL konsumiert ein Flag; ist es wahr (<>0), wird die Schleife verlassen.
Schleifen (4)
?DO nimmt zwei Zahlen vom stack ( n1 n2 -- ), und die Schleife zwischen ?DO und LOOP wird dann n1-n2 mal ausgeführt. Auf den Zähler kann man mit I zugreifen:
: fac ( n -- n! )
1 swap 1+ 1 ?do
i *
loop ;
5 fac .
7 fac .
Returnstack
Neben dem normalen Stack (dem Daten-Stack) gibt es in Forth den Return-Stack, der vor allem dazu dient, die Rücksprungadressen bei Definitionsaufrufen zu speichern.
Returnstack (2)
Dieser Stack ist auch für Programmierer zugänglich:
: foo ( n1 n2 -- )
.s >r .s
r@ .
>r .s
r@ . r> .
r@ . r> . ;
1 2 foo
>R schiebt also ein Element vom Daten- auf den Return-Stack, R> umgekehrt, und R@ kopiert das oberste Return-Stack-Element auf den Datenstack.
Returnstack (3)
Der Returnstack wird dazu verwendet, Daten zwischenzuspeichern, wenn eine alleinige Speicherung auf dem Datenstack zu kompliziert ist:
: 2swap ( x1 x2 x3 x4 -- x3 x4 x1 x2 )
rot >r rot r> ;
Da die Rücksprungadresse und die Schleifenkontrollparameter von Zählschleifen auf dem Returnstack liegen, müssen alle Elemente, die in einer Definition bzw. Zählschleife auf den Returnstack geschoben werden, vor dem Ende der Definition bzw. Zählschleifen wieder entfernt werden.
Elemente, die ausserhalb auf den Return-Stack geschoben wurden, können in der Definition bzw. Zählschleife nicht verwendet werden. Wenn man sich beim Return- Stack verzählt, endet das meistens in einem Crash:
: crash ( n -- ) >r ;
5 crash
Speicher
Speicher kann reserviert werden mit:
create speicher 20 cells allot
Dies erzeugt ein Wort “speicher”, welches bei der Ausführung eine Adresse liefert, und reserviert an dieser Adresse Platz für 20 Zellen.
Speicher (2)
Mittels Adressarithmetik können wir auf einzelne Elemente zugreifen:
3 speicher 5 cells + !
Das Wort "cells" definiert die Wortgroesse der CPU und des Forth Systems
: cells 2 * ; ( 8/16 bit CPU )
: cells 4 * ; ( 32bit CPU )
: cells 8 * ; ( 64bit CPU )
Speicher (3)
Mit "," kann man Speicher reservieren und initialisieren:
create v3
5 , 4 , 3 , 2 , 1 ,
v3 @ .
v3 1 cells + @ .
v3 2 cells + @ .
Speicher (4)
, ( n -- )
reserviert Platz für eine Zelle im Speicher, nimmt einen Wert vom Stack und speichert diesen Wert im reservierten Speicher
c, ( 8b -- )
speichert ein Byte statt eine Zelle
Speicher (5)
Man kann natürlich auch Speicher reservieren, ohne eine neues Wort zu produzieren:
here 10 cells allot .s
HERE liefert dabei die Anfangsadresse des Speichers, die man möglichst irgendwo abspeichern sollte (z.B. in einer Variable), sonst findet man den Bereich nicht wieder.
Speicher (6)
Der mit ALLOT verwaltete Speicher kommt aus dem Dictionary (das auch Wörter speichert) und wird als Stack verwaltet; mit
-10 cells allot
können die letzten 10 angelegten Zellen wieder freigegeben werden.
Speicher (7)
CREATE ccc
legt ein neues Wort "ccc" im Speicher an, ohne weiteren Speicher zu reservierten
Zur Laufzeit legt das neue Wort "ccc" die Addresse auf den Stapel, welche direkt dem Wort im Speicher nachfolgt
Der Programmierer kann per ALLOT einen beliebig grossen Speicher nach dem Wort reservieren
CREATE kann benutzt werden, um Speicherstellen per Name ansprechen zu können
Speicher (8)
Beispiel für CREATE und ALLOT:
CREATE tabelle 1024 ALLOT
Dies reserviert an der Speicherstelle, welche durch das neue Wort "tabelle" bereitgestellt wird, 1024 Byte
ʻ (TICK)
‘ ccc ( -- xt )
sucht Forth-Wort “ccc” und legt das “execution token (xt)” auf den Stapel
execute ( xt -- ?? )
führt das Wort, auf das der “xt” zeigt, aus. In Wort-Definitionen wird das Wort ['] verwendet.
recursion
das Forth-Wort recursive (in einigen System auch "recurse". "self" oder "myself" genannt)
ruft das aktuell definiert Wort rekursiv auf
: fib1 ( n1 -- n2 )
dup 2 < if drop 1 exit then
dup 1- recursive
swap 2- recursive + ;
PAUSE!
Forth Kerne
- Die Geschwindigkeit eines Forth Systems basiert auf der Implementierung
- Die Implementierung ist abhängig von der CPU Archtektur ...
- ... und der Abwägung zwischen Geschwindigkeit und Speicherverbrauch.
- Neil Franklin wird in seinem Vortrag im Detail auf Forth Implementierungen eingehen.
Forth Kerne
Wir schauen und die Implementation verschiedener Forth System anhand des Wortes "square" an
: SQUARE DUP * ;
Forth Kerne - ITC
Indirect Threaded Code
wird in den meisten Forth Implementationen benutzt
guter Kompromiss zwischen Speicherverbrauch und Geschwindigkeit
Forth Kerne - DTC
Direct Threaded Code
wird in einigen Forth Implementationen benutzt
kann schneller sein als ITC oder STC
Forth Kerne - STC
Subroutine Threaded Code
jedes Forth Wort ist ein nativer Subroutine Aufruf (JMP oder CALL)
Forth Kerne - TTC
Token Threaded Code
sehr speicherplatzsparend
Programm ist relozierbar und prozessorabhaengig (Bytecode)
langsam, da weitere Indirektion
Forth Kerne - Native Code
Native Code
kein Threading
Forth compiler erzeugt direkten Maschinencode
Forth Benchmarks - Integer
Integer Benchmark
32000 constant intMax variable intResult
: DoInt ( -- )
1 dup intResult dup >r !
begin dup intMax <
while
dup negate r@ +! 1+ dup r@ +! 1+
r@ @ over * r@ ! 1+ r@ @ over / r@ ! 1+
repeat
r> drop drop ;
Forth Benchmarks - Fibonacci 1
Fibonacci Benchmark (recursiv)
: fib1 ( n1 -- n2 )
dup 2 < if drop 1 exit then
dup 1- recursive
swap 2- recursive + ;
: fib1-bench 1000 0 do
10 0 do i fib1 drop loop
loop ;
Forth Benchmarks - Fibonacci 2
Fibonacci Benchmark (iterativ)
: fib2 ( n1 -- n2 )
0 1 rot 0 ?do
over + swap loop
drop ;
: fib2-bench 10000 0 do i fib2 drop loop ;
Forth Benchmarks - Nesting
Nesting Benchmark
\ Forth nesting (NEXT) Benchmark
: bottom ;
: 1st bottom bottom ; : 2nd 1st 1st ; : 3rd 2nd 2nd ;
: 4th 3rd 3rd ; : 5th 4th 4th ; : 6th 5th 5th ;
: 7th 6th 6th ; : 8th 7th 7th ; : 9th 8th 8th ;
: 10th 9th 9th ; : 11th 10th 10th ; : 12th 11th 11th ;
: 13th 12th 12th ; : 14th 13th 13th ; : 15th 14th 14th ;
: 16th 15th 15th ; : 17th 16th 16th ; : 18th 17th 17th ;
: 19th 18th 18th ; : 20th 19th 19th ; : 21th 20th 20th ;
: 22th 21th 21th ; : 23th 22th 22th ; : 24th 23th 23th ;
: 25th 24th 24th ;
: 32million CR ." 32 million nest/unnest operations" 25th ;
: 1million CR ." 1 million nest/unnest operations" 20th ;
Forth Benchmarks - Memory Move
Memory Move Benchmark
\ Forth Memory Move Benchmark cas 20101204
8192 CONSTANT bufsize
VARIABLE buf1 HERE bufsize 1+ allot BUF1 !
VARIABLE buf2 HERE bufsize 1+ allot BUF2 !
: test-CMOVE 49 0 DO BUF1 @ BUF2 @ bufsize CMOVE LOOP ;
: test-CMOVE> 49 0 DO BUF2 @ BUF1 @ bufsize CMOVE> LOOP ;
: test-MOVE> 49 0 DO BUF1 @ BUF2 @ bufsize MOVE LOOP ;
: test-<MOVE 49 0 DO BUF2 @ BUF1 @ bufsize MOVE LOOP ;
: move-bench test-CMOVE test-CMOVE> test-MOVE> test-<MOVE ;
Forth Benchmarks - Count Bits
Count Bits Benchmark
\ Forth Benchmark - count bits in byte
VARIABLE cnt
: countbits ( uu -- #bits )
cnt off
8 0 DO dup $01010101 and cnt +! 2/ LOOP drop
0 cnt 4 bounds DO i C@ + LOOP ;
: count-bits 8192 DO I countbits . LOOP ;
Forth Benchmarks - Sieve
Sieve Benchmark
8192 CONSTANT SIZE VARIABLE FLAGS 0 FLAGS !
SIZE ALLOT
: DO-PRIME ( -- )
FLAGS SIZE 1 FILL ( set array )
0 ( 0 COUNT ) SIZE 0
DO FLAGS I + C@
IF I DUP + 3 + DUP I +
BEGIN DUP SIZE <
WHILE 0 OVER FLAGS + C!
OVER + REPEAT
DROP DROP 1+
THEN
LOOP
. ." Primes" CR ;
Forth Benchmarks - GCD 1
GCD (Greatest Common Divisor) Benchmark
: gcd1 ( a b -- gcd )
OVER IF
BEGIN
DUP WHILE
2DUP U> IF SWAP THEN OVER -
REPEAT DROP ELSE
DUP IF NIP ELSE 2DROP 1 THEN
THEN ;
: gcd1-bench 100 0 DO
100 0 DO j i gcd1 drop loop
loop ;
Forth Benchmarks - GCD 2
GCD (Greatest Common Divisor) Benchmark
: gcd2 ( a b -- gcd )
2DUP D0= IF 2DROP 1 EXIT THEN
DUP 0= IF DROP EXIT THEN
SWAP DUP 0= IF DROP EXIT THEN
BEGIN 2DUP -
WHILE 2DUP < IF OVER -
ELSE SWAP OVER - SWAP
THEN
REPEAT NIP ;
: gcd2-bench 100 0 DO
100 0 DO j i gcd2 drop loop
loop ;
Forth Benchmarks - Takeuchi
Takeuchi Benchmark
: 3dup 2 pick 2 pick 2 pick ;
: tak ( x y z -- t )
over 3 pick < NEGATE IF nip nip exit then
3dup rot 1- -rot recursive >r
3dup swap 1- -rot swap recursive >r
1- -rot recursive
r> swap r> -rot recursive ;
: takbench ( -- )
0 10000 0 DO DROP 18 12 6 tak LOOP ;
Forth Benchmarks - 6502emu
6502emu Benchmark
\ A simple 6502 emulattion benchmark cas
\ only 11 opcodes are implemented. The memory layout is:
\ 2kB RAM at 0000-07FF, mirrored throughout 0800-7FFF
\ 16kB ROM at 8000-BFFF, mirrored at C000
decimal
create ram 2048 allot : >ram $7FF and ram + ;
create rom 16384 allot : >rom $3FFF and rom + ;
\ 6502 registers
variable reg-a variable reg-x variable reg-y
variable reg-s variable reg-pc : reg-pc+ reg-pc +! ;
\ 6502 flags
variable flag-c variable flag-n variable cycle
variable flag-z variable flag-v : cycle+ cycle +! ;
hex ....
Forth Benchmarks - benchme
Benchmark Helper
: beep ( -- ) \ emits an audible beep signal
7 con! ; \ this is hardware and implementation dependent
: benchme ( xt n -- ) \ executes the word with the execution token 'xt' n-times
dup >r \ save number of iterations
beep \ signal of benchmark start
0 do dup execute loop \ execute word. word must have a neutral stack effect
beep \ signal benchmark end
cr r> . ." Iterations." cr \ emit message
;
\ Example: ' fib1-bench 100 benchme
\ this will execute the Fibonacci 1 benchmark 100 times
Forth Benchmarks - Regeln
Benchmark Regeln
Jeder VCFe Teilnehmer kann Teil- oder Komplettergebnisse einreichen
Forth Benchmarks - Regeln
Benchmark Regeln
jeder Teilnehmer kann beliebig viele verschiedene Einreichungen vornehmen
Forth Benchmarks - Regeln
Benchmark Regeln
Jede neue Kombination von CPU/Rechner, Taktfrequenz/Betriebsmodus und Forth-System ist als Einreichung möglich
Forth Benchmarks - Regeln
Benchmark Regeln
Jede Einreichung muß von einer Beschreibung der verwendeten Umgebung (CPU/Rechner/Modus/Forth-System) begleitet werden
Forth Benchmarks - Regeln
Benchmark Regeln
Die verwendete Umgebung muß auf dem VCFe präsent sein. Ausnahmen können in begründeten Fällen von der Wettbewerbsleitung gemacht werden
Forth Benchmarks - Regeln
Benchmark Regeln
Eine Einreichung muß für mindestens 3 (Drei) der Benchmarks ein vollständige Ergebniss beinhalten
Forth Benchmarks - Regeln
Benchmark Regeln
Sind die Ergebnisse hochgerechnet, so mussen der Rechenweg und die Zwischenschritte dokumentiert werden
Forth Benchmarks - Regeln
Benchmark Regeln
Die Wettbewerbsleitung entscheidet endgültig welche Einreichungen angenommen werden
Forth Benchmarks - Regeln
Benchmark Regeln
Für jede angenommene Einreichung wird ein Los vergeben
Forth Benchmarks - Regeln
Benchmark Regeln
Aus allen Losen werden am Ende des Wettbewerbs die Preisträger gezogen
Forth Benchmarks - Regeln
Benchmark Regeln
Die Preise sind direkt auf dem VCFe entgegenzunehmen. Ein späterer Versand erfolgt nicht
Forth Benchmarks - Preise
Benchmark Wettbewerb Preise
- 1 x OpenMoko Freerunner Mobiletelefon (gestiftet von Axel Beckert)
- 2 x Plüsch Drache "SWAP" (gestiftet von der Forth Gesellschaft e.V.)
- 2 x Arduino Duemilanove mit "Danger Shield" Kit und amForth (gestiftet von der Forth Gesellschaft e.V.)
- 2 x Jahresabo der Zeitschrift "Vierte Dimension/VD" (gestiftet von der Forth Gesellschaft e.V.)
Fragen?