Well, thats cool.
Just got an old copy of LIPS: A gentle introduction to symbolic computation by Touretzky. In my searching, I came across an old link that mentioned a David Betz as creating XLisp. Now I don't have to ask.
Maybe because infix is more similar to many natural languages:
The emphasis here is on the "many". I don't believe infix or post fix is hard wired into the human brain. Any more than writing from left to right or top to bottom.
An example. In Finnish "The cat is on the table." is "Kissa on p
propgcc cmm (no fcache):
fibo(26) = 121393 (04792ms) (383407984 ticks)
I searched the forums and found this number for Spin for fibo(8):
Spin 137360 25
The ebasic3/mince number for fibo(8) is:
fibo(8) = 21 (1ms) (112512 ticks)
That makes ebasic3/mince a little faster than Spin for this benchmark. However, don't take that too seriously since I didn't run the test myself and there might have been a difference in the methodology.
Another example is JavaScript. A language that is far removed from C in it's semantics and a lot more expressive language. But it was demanded that Brendan Eich make it look like C with all the squiggly brackets, the same operators and so on. JavaScript is a lot more like Lisp or Self than C but it was felt those syntaxes would not be popular.
I llike Lisp syntax. It is very regular and it's easy to construct programatically. The zillions of parens don't bother me at all. However, I know I'm in a small minority.
Finally got back to try out the fibo benchmark and these are the results:
[FONT=courier new]: fibo ( n -- f )
0 1 ROT 0 OVER IF DO OVER + SWAP LOOP ELSE 2DROP THEN DROP
; ok
ok
DECIMAL ok
0 27 ADO CR ." fibo(" I . ." ) = " NEWCNT I fibo .LAP ." result =" . LOOP
fibo(0) = 13us result =0
fibo(1) = 19us result =1
fibo(2) = 22us result =1
fibo(3) = 26us result =2
fibo(4) = 29us result =3
fibo(5) = 32us result =5
fibo(6) = 35us result =8
fibo(7) = 38us result =13
fibo(8) = 42us result =21
fibo(9) = 45us result =34
fibo(10) = 48us result =55
fibo(11) = 51us result =89
fibo(12) = 54us result =144
fibo(13) = 58us result =233
fibo(14) = 61us result =377
fibo(15) = 64us result =610
fibo(16) = 67us result =987
fibo(17) = 70us result =1597
fibo(18) = 74us result =2584
fibo(19) = 77us result =4181
fibo(20) = 80us result =6765
fibo(21) = 83us result =10946
fibo(22) = 86us result =17711
fibo(23) = 90us result =28657
fibo(24) = 93us result =46368
fibo(25) = 96us result =75025
fibo(26) = 99us result =121393 ok
[/FONT]
Finally got back to try out the fibo benchmark and these are the results:
[FONT=courier new]: fibo ( n -- f )
0 1 ROT 0 OVER IF DO OVER + SWAP LOOP ELSE 2DROP THEN DROP
; ok
ok
DECIMAL ok
0 27 ADO CR ." fibo(" I . ." ) = " NEWCNT I fibo .LAP ." result =" . LOOP
fibo(0) = 13us result =0
fibo(1) = 19us result =1
fibo(2) = 22us result =1
fibo(3) = 26us result =2
fibo(4) = 29us result =3
fibo(5) = 32us result =5
fibo(6) = 35us result =8
fibo(7) = 38us result =13
fibo(8) = 42us result =21
fibo(9) = 45us result =34
fibo(10) = 48us result =55
fibo(11) = 51us result =89
fibo(12) = 54us result =144
fibo(13) = 58us result =233
fibo(14) = 61us result =377
fibo(15) = 64us result =610
fibo(16) = 67us result =987
fibo(17) = 70us result =1597
fibo(18) = 74us result =2584
fibo(19) = 77us result =4181
fibo(20) = 80us result =6765
fibo(21) = 83us result =10946
fibo(22) = 86us result =17711
fibo(23) = 90us result =28657
fibo(24) = 93us result =46368
fibo(25) = 96us result =75025
fibo(26) = 99us result =121393 ok
[/FONT]
Wow! That's impressive. I'm not sure I understand how it works though. Is it a recursive algorithm? I don't see a call to fibo in its body? Or is that what DO does?
Okay, I have a question. Which of these is easier to understand?
Iterative Forth:
\ fibonacci - iterative method - but skip test for n = 0
: fibo ( n -- f )
0 1 \ Setup initial calculations "0 1"
ROT \ rotate n to top of stack - for n times
FOR
OVER + SWAP \ next iteration -> result prev
NEXT
DROP \ discard the prev result, leave the current result
;
Recursive Forth:
: fibo ( n -- result ) dup 2 >= if dup 1- fibo swap 2- fibo + then ;
C:
unsigned int fibo (unsigned int n)
{
if (n < 2)
{
return (n);
}
else
{
return fibo(n - 1) + fibo(n - 2);
}
}
ebasic3:
def fibo(n)
if n < 2 then
return n
else
return fibo(n - 1) + fibo(n - 2)
end if
end def
I readily admit that the last two are more familiar to me because I know those languages. Does a Forth programmer find the first example as easy to follow as the other two?
Okay, that was a quick and dirty one liner, not meant for reading, just doing. Here is a slight refinement and it runs faster again.
[FONT=courier new]\ fibonacci - iterative method - but skip test for n = 0
: fibo ( n -- f )
0 1 \ Setup initial calculations "0 1"
ROT \ rotate n to top of stack - for n times
FOR
OVER + SWAP \ next iteration -> result prev
NEXT
DROP \ discard the prev result, leave the current result
;
\ fibonacci test - just a Q&D one liner
DECIMAL
1 26 ADO CR ." fibo(" I . ." ) = " NEWCNT I fibo .LAP ." result =" . LOOP
fibo(1) = 13us result =1
fibo(2) = 16us result =1
fibo(3) = 19us result =2
fibo(4) = 22us result =3
fibo(5) = 25us result =5
fibo(6) = 28us result =8
fibo(7) = 31us result =13
fibo(8) = 34us result =21
fibo(9) = 37us result =34
fibo(10) = 40us result =55
fibo(11) = 43us result =89
fibo(12) = 46us result =144
fibo(13) = 49us result =233
fibo(14) = 52us result =377
fibo(15) = 55us result =610
fibo(16) = 58us result =987
fibo(17) = 61us result =1597
fibo(18) = 64us result =2584
fibo(19) = 67us result =4181
fibo(20) = 70us result =6765
fibo(21) = 73us result =10946
fibo(22) = 76us result =17711
fibo(23) = 79us result =28657
fibo(24) = 82us result =46368
fibo(25) = 85us result =75025
fibo(26) = 88us result =121393 ok
[/FONT]
It would be interesting to ask that question of people who have never programmed or even seen a program before.
Clearly option 3 would be the winner. Assuming they speak English and know a little mathematics they could probably just read that like they would other instructions in English.
The Forth is of course gibberish.
That Forth line has "LOOP" in it. This makes me suspicious that it is not recursive. Not in the spirit of the benchmark.
For me the C and the Mince versions are easier to understand. The Forth example requires following values on the stack, which makes it less obvious. However, I think an experienced Forth programmer could follow the Forth example as easily as the other two.
For me the C and the Mince versions are easier to understand. The Forth example requires following values on the stack, which makes it less obvious. However, I think an experienced Forth programmer could follow the Forth example as easily as the other two.
That's what I was wondering. I know APL programmers used to be able to understand one-liners that I found totally opaque. The Forth version is certainly more concise than either of the other two and seems to be faster although I think it's an interative algorithm. I'll bet the recursive one will still be faster though.
: fibo ( n -- result ) dup 2 >= if dup 1- fibo swap 2- fibo + then ;
However, in ANS Forth a word calls itself using the RECURSE word. That's because fibo is not supposed to be in the dictionary until the ";" is encountered. pfth currently adds a compiled word to the dictionary when processing the ":" word. I'll fix that someday.
Mince is interesting too bad it is too large. Given that ZiCog exists, shouldn't it be possible to port a Z80 interpreted language to the Propeller? There were some pretty compact interpreters on the Z80 which should allow for comparison of a hub executed language to Forth.
Actually, it does fit in hub memory using PropGCC's CMM memory mode if you leave out the filesystem code. That is rather large in PropGCC.
Given that ZiCog exists, shouldn't it be possible to port a Z80 interpreted language to the Propeller? There were some pretty compact interpreters on the Z80 which should allow for comparison of a hub executed language to Forth.
Does ZiCog run CP/M without requiring any external memory?
: fibo ( n -- result ) dup 2 >= if dup 1- fibo swap 2- fibo + then ;
However, in ANS Forth a word calls itself using the RECURSE word. That's because fibo is not supposed to be in the dictionary until the ";" is encountered. pfth currently adds a compiled word to the dictionary when processing the ":" word. I'll fix that someday.
Thanks Dave. Any chance you could run fibo(26) and report the elapsed time?
I don't know. I was thinking that you would leave out file system and just run the binary from hub ram. But it sounds Mince does that already.
Yes, it can. I could probably add LOAD and SAVE commands to save programs to high EEPROM and still fit in hub memory although I haven't done that yet. I could also implement a block filesystem like some Forths do. I'm not sure if that's the way Tachyon or pfth do that though.
Does ZiCog run CP/M without requiring any external memory?
Back in the day when we only emulated the 8080 (PropAltair) it was possible to have 24K of HUB free for 8080 code.
It would run MS 4K and 8K BASIC for example.
CP/M will run in that but it's hardly useful. Not enough to run the BDS C compiler for example.
Latest builds had a FAT file system thrown which ate all the HUB forcing all Z80 space out to external RAM.
Back in the day when we only emulated the 8080 (PropAltair) it was possible to have 24K of HUB free for 8080 code.
It would run MS 4K and 8K BASIC for example.
CP/M will run in that but it's hardly useful. Not enough to run the BDS C compiler for example.
Latest builds had a FAT file system thrown which ate all the HUB forcing all Z80 space out to external RAM.
Thanks for the info. I guess it would be hard to write a recursive fibo function in MS 4K or 8K Basic but it seems like 24K of hub memory would be enough to run some more capable languages. I'm pretty sure that an early verison of xlisp ran in 32k of memory under CP/M. It certainly ran in slightly less than that on a PDP-11.
Edit: No, I'm wrong about the PDP-11. Mine had 60K of RAM.
That's what I was wondering. I know APL programmers used to be able to understand one-liners that I found totally opaque. The Forth version is certainly more concise than either of the other two and seems to be faster although I think it's an interative algorithm. I'll bet the recursive one will still be faster though.
Thanks for the iterative C version! Here is the equivalent in ebasic3:
def fiboi(n)
dim fibo, fibo1, fibo2, j
fibo = 1
if n >= 3 then
fibo1 = 1
fibo2 = 1
for j = 3 to n
fibo = fibo1 + fibo2
fibo2 = fibo1
fibo1 = fibo
next j
end if
return fibo
end def
Under pfth the recursive fibo(26) is 5.5 seconds, and the iterative fibo(26) is 286 micro-seconds.
Nice! Thanks for running the test. As I said in the first post in this thread, Forth certainly seems to have beaten my attempts at creating a small fast infix language.
Mince isn't bad compared to bash. The iterative fibo(26) takes 13 seconds in spinix bash. It's a little faster running in Cygwin on my PC. fibo(26) takes about one-tenth second. I didn't even consider trying the recursive fibo.
Mince isn't bad compared to bash. The iterative fibo(26) takes 13 seconds in spinix bash. It's a little faster running in Cygwin on my PC. fibo(26) takes about one-tenth second. I didn't even consider trying the recursive fibo.
I don't think Mince is bad. It seems to be about the same speed as Spin. I could speed it up a bit by simplifying its memory access to use direct inline rdlong/wrlong instead of calling a function to fetch each long. I did that because it is the VM from xbasic and xbasic can execute code from external memory through a cache. I also do some validity checking like making sure a bytecode is in range and checking for stack overflows and divide by zero which I could eliminate to gain some speed. It seems unlikely though that I'd be able to achieve Tachyon's or even pfth's performance.
One thing I thought of doing with Mince either in its Basic or C syntax version is to use it to make a Propeller BasicStamp or CStamp by writing it to the EEPROM on the new Prop Mini module that has a 64k EEPROM. I could use the second 32k as a small filesystem to store programs and would end up with a stamp-like module that is self-hosted. Of course, you could do the same thing with any of the Forths and have a faster system. Some people might like the infix syntax though, especially people coming from the BasicStamp/pbasic world.
Comments
I can see the campaign now, "Just say No to Forth! Do it for the children."
Good info.
How does that compare with other Interpreter choices ?
Well, thats cool.
Just got an old copy of LIPS: A gentle introduction to symbolic computation by Touretzky. In my searching, I came across an old link that mentioned a David Betz as creating XLisp. Now I don't have to ask.
An example. In Finnish "The cat is on the table." is "Kissa on p
propgcc lmm:
fibo(26) = 121393 (00927ms) (74224848 ticks)
propgcc cmm (no fcache):
fibo(26) = 121393 (04792ms) (383407984 ticks)
I searched the forums and found this number for Spin for fibo(8):
Spin 137360 25
The ebasic3/mince number for fibo(8) is:
fibo(8) = 21 (1ms) (112512 ticks)
That makes ebasic3/mince a little faster than Spin for this benchmark. However, don't take that too seriously since I didn't run the test myself and there might have been a difference in the methodology.
Iterative Forth:
Recursive Forth:
C:
ebasic3:
I readily admit that the last two are more familiar to me because I know those languages. Does a Forth programmer find the first example as easy to follow as the other two?
Clearly option 3 would be the winner. Assuming they speak English and know a little mathematics they could probably just read that like they would other instructions in English.
The Forth is of course gibberish.
That Forth line has "LOOP" in it. This makes me suspicious that it is not recursive. Not in the spirit of the benchmark.
Could someone confirm this?
That looks better.
Can we have the proper recursive version?
I don't know. I was thinking that you would leave out file system and just run the binary from hub ram. But it sounds Mince does that already.
Back in the day when we only emulated the 8080 (PropAltair) it was possible to have 24K of HUB free for 8080 code.
It would run MS 4K and 8K BASIC for example.
CP/M will run in that but it's hardly useful. Not enough to run the BDS C compiler for example.
Latest builds had a FAT file system thrown which ate all the HUB forcing all Z80 space out to external RAM.
Edit: No, I'm wrong about the PDP-11. Mine had 60K of RAM.
That is sad, given that I littered what APL I wrote with lamps.
And the results:
Not nearly as good as Tachyon.
One thing I thought of doing with Mince either in its Basic or C syntax version is to use it to make a Propeller BasicStamp or CStamp by writing it to the EEPROM on the new Prop Mini module that has a 64k EEPROM. I could use the second 32k as a small filesystem to store programs and would end up with a stamp-like module that is self-hosted. Of course, you could do the same thing with any of the Forths and have a faster system. Some people might like the infix syntax though, especially people coming from the BasicStamp/pbasic world.