Share your repls and programming experiences

← Back to all posts
π in Forth
h
AmazingMech2418 (894)

Today, I decided to learn the basics of Forth so, I decided to make a π approximation in Forth!

How it Works

So, I know that Forth is not the most readable language there is, so I decided to give an overview on how this program works.

The Makefile

So, first, the makefile of this simply runs gforth to execute main.fth. I had to use a polygott repl since the normal Forth repl implementation does not support floating point numbers.

Main.fth

Now, for the actual code...

Variable Assignments

The first 3 lines simply define variables. Specifically, the variables p, s, and cntr. In this case, p is the variable used for pi, s is the sign of the specific iteration (this uses the Nilakantha Series), and cntr is a counter used in the Nilakantha Series.

Then, I simply define the original values for these variables. However, this all needs to be done in the floating point stack instead of the integer stack. If you were doing it in the integer stack, you'd do something like

3.0 p !

However, this does not work for a floating point. The 3.0 will just be rounded to 3 which is the same thing, but won't work for solving pi. For a floating point, you need to use

3.0e p f!

For floating points in Forth, you need to use e after every number and f before every operator, including variable assignment operators such as ! and variable reading operators such as @ and even the printing operator ..

Iteration Function

Now, starting in line 7 is our function for each iteration of the Nilakantha Series. First, I begin the function definition with : iter and add a new line for organization. Then, on line 8 is our main iteration code, but we'll get back to that.

On line 9, we multiply the variable s by -1. (I am going with line 9 before line 8 due to the complexity of line 8) However, Forth is stack-oriented, not object-oriented like most well-known languages such as Python, JavaScript, and C++. So, first, we read the variable s with s [email protected] and add it to the stack. Then, we use -1e to add -1 to the floating point stack. Then, we multiply them with f+ and replace both items in the stack with the product (to keep them in, the dup or over commands would be needed, but we won't get into those.). Then, we use s f! to assign the variable s to the product already in the stack to complete this simple operation.

Line 10 is much the same, but uses the cntr variable and adds 2 to it. Now, for line 8. To make this easier to read, I'm going to put this in a list...

Line 8 Steps
1. Add 4 to stack
2. Add the value of cntr to stack
3. Add 3 to stack
4. Add the last two items in the stack and replace those items with the sum (you always replace used items with the result in Forth operations)
5. Add the value of cntr to stack
6. Multiply last two items of stack
7. Add 2 to stack
8. Add last two items of stack
9. Add the value of cntr to stack
10. Multiply last two items of stack
11. Divide last two items of stack (divides 4 by the value from step 10)
12. Add value of s to stack
13. Multiply last two items of stack (applies sign of iteration to the result)
14. Add value of p to stack
15. Add last two items of stack (adds iteration value to pi)
16. Set p to last (and only) number in stack

Finally, on line 11, we add a semicolon to end the function definition.

Loop (l) Function

First, we define our function with : l and add a space to keep everything on the same line. Then, we start our for loop.

In Forth, a for loop of

10 0 do iter loop

is the same as

for(let i = 0; i < 10; i++) {
    iter()
}

in JavaScript (replace "let" with "int" for the typed C-family languages) or

for i in range(0, 10):
    iter()

in Python. In this for loop, we start at 0 and go to 100000, running the iter function each time.

Now that we have our for loop, we close the function definition with a semicolon.

Execution Code

Now, we have the code to execute our functions beginning on line 13 with its powerful one-letter command: l. This calls the function we just defined with the for loop to run everything.

Display Code

Now, on line 14, we display our result. First, we have a text display of ." pi = " which simply displays "pi = " and then, we display the value of p with p [email protected] f.. Finally, we close it off with a new line (or carriage return) with cr and everything is displayed, leaving our function complete.

Credits

This is inspired by @LizFoster 's many π approximation repls and a conversation between her and @Warhawk947 where @Warhawk947 recommended that @LizFoster create a pi approximation in every language and I joined the conversation and said "Imagine pi in LOLCODE or Emoticon or some other esolang..." and @Warhawk947 said not to even think about it, so I then created a LOLCODE pi approximation and then thought, why not do a pi approximation in Forth as well, although not an esolang?

Commentshotnewtop
CodingCactus (3010)

wow, you're not lying about the level of readability, lol

AmazingMech2418 (894)

@CodingCactus LOL! I think it is called Reverse Polish Notation or something like that. It has a very weird syntax.

AmazingMech2418 (894)

@CodingCactus Most programming languages, I can figure out the syntax without a tutorial and with just examples and documentation, but Forth was different. I guess that people in Poland though would find this easier since it is Reverse Polish Notation. However, I guess it is useful to know different types of programming languages, even if some (like Forth) have weird syntaxes.

AmazingMech2418 (894)

@CodingCactus Though the one good thing with Forth is that it is fast. Very fast. This same program freezes in LOLCODE which is even faster (surprisingly) than Node.JS, Python, and even C!

CodingCactus (3010)

@AmazingMech2418 oh, nice. Is that the only advantage with it? :)

AmazingMech2418 (894)

@CodingCactus I think it is also very similar in functionality to Assembly, so that would mean it would make it easier to learn Assembly, but I'm not sure.

DynamicSquid (3552)

@CodingCactus i thought programming languages are based off of an "english" syntax, not Czech

xxpertHacker (387)

@DynamicSquid Most are. Not all. There are a key few languages made in other languages from the ground up. I forgot what languages though. I tried converting C++ to Spanish at one point using #define, I failed.

...Thinking about it, amasad can easily make his BASIC non-English if he felt like it.

DynamicSquid (3552)

@StudentFires you tried to turn c++ into Spanish?

xxpertHacker (387)

@DynamicSquid I did not try to turn C++ into Spanish, I tried converting the keywords to their Spanish equivalents.

xxpertHacker (387)

@AmazingMech2418 I realized what you were intending to say, but you actually said:

...LOLCODE ... is even faster than Node.JS, Python, and even C!

I was lost. I actually googled to see if LOLCODE was somehow faster than C. Then I reread it, and saw that there was a misalignment in your intent and the actual words in the sentence.

btw: check out THAIL's notes

AmazingMech2418 (894)

@DynamicSquid Well, Forth is not really based on any language really. It is more of just operators and stuff. However, if you were to say it was based on one language, it would be English. There are keywords like dup (short for "duplicate"), switch, and, or, inverse, do, etc. that are all English. However, the notation is (or at least was) commonly used in Poland, so it is called Reverse Polish Notation.

AmazingMech2418 (894)

@StudentFires No. I actually mean that this same program, I ran in LOLCODE and C and it was faster in LOLCODE.

xxpertHacker (387)

@AmazingMech2418 I saw you're original post on LOLCODE when you made it, so I knew what you were talking about, but the structure of you sentence makes it seem like you're trying to say Forth > LOLCODE > (Node.JS, C, ...)

AmazingMech2418 (894)

@StudentFires Also, with the THAIL notes, the multiline comments don't even need to be multiple types. Once Adapt received some updates, we can just make it work as parentheses.

AmazingMech2418 (894)

@StudentFires Well, in speed, it is Forth > LOLCODE > C > Node.JS > Python ...

xxpertHacker (387)

@AmazingMech2418 I was literally, just about to write more to the notes, on types. Does Adapt even have types?

xxpertHacker (387)

@AmazingMech2418 Umm... LOLCODE > C? I don't know about that.

AmazingMech2418 (894)

@StudentFires Adapt is really just a custom constructor system, so it doesn't even have a native variable/memory system. It really just inherits everything from the host language (JavaScript). So, if you'd prefer, we could create a typed memory system for THAIL...

xxpertHacker (387)

@AmazingMech2418 Well, I had an idea... how about I write it into the notes, instead of here.

AmazingMech2418 (894)

@StudentFires Yes. I'm pretty sure LOLCODE has a better compiling system than C since it is not object-oriented, but I know it is a lot faster. Run my C pi approximations against the LOLCODE ones and see which one takes longer to get to the same accuracy.

LiamDonohue (285)

from now on forth will be named "easy brainf"

jeremykyleisgod (45)

@CodingCactus because your cycle is at 888 which is a gambling sight in the uk honestly it was a joke suggestion and I completely agree with your opinion I also don't like gambling but thought it would be funny to suggest because of your cycle number

jeremykyleisgod (45)

@Codingcactus you need to make a basic gambling game cos of your cycles

jeremykyleisgod (45)

3.1415926535897932384626433832795028841971693993751058209749445923078 164062862089986280348253421170679. done

xxpertHacker (387)

The very fact that there's a built in printing operator... I like it already.

AmazingMech2418 (894)

@StudentFires Good luck with Reverse Polish Notation then! That's the trickiest part of Forth...

xxpertHacker (387)

@AmazingMech2418 Luckily for me, I'm not Polish, so I should be okay.

AmazingMech2418 (894)

@StudentFires What? I'm confused now... How would not being Polish make it so that you would be okay? I'm not Polish either...

xxpertHacker (387)

@AmazingMech2418 Well, I'm not used to the Polish Notation, so technically, I'm already used to the reverse Polish Notation.

AmazingMech2418 (894)

@StudentFires LOL! So, does this make sense to you? 2 3 + 4 *?

AmazingMech2418 (894)

@StudentFires So, what's the answer? The complicated part is the stack manipulation stuff... How about 1 2 3 * +?

theangryepicbanana (1629)

@AmazingMech2418 I believe the idea is that it's basically like backwards Lisp, so 1 2 3 * + means (1 (2 3 *) +) which translates to (+ 1 (* 2 3)) in Lisp

AmazingMech2418 (894)

@theangryepicbanana I'm not really sure about Lisp, but that sounds right. I know with Forth in how it uses Reverse Polish Notation, the operator is after both numbers and applies to the last two items in the stack.