In the last section, we learned some basic arithmetic using
+
and *
. However, froth
incorporates a host of arithmetic expressions. Eagle-eyed readers may
have spotted that we’ve only been working with commutative operations,
meaning the order doesn’t matter (a+b = b+a
). What happens
when we use non-commutative expressions, such as division or
exponentiation?
When froth
executes words, it always treats the top of
the stack as the last argument to the expression. This means
that, for something like a b /
, b
is on the
top of the stack and the result is a / b
.
froth
uses R for its mathematical operations, so you don’t
have to worry about things like converting between integers and doubles,
or double vs. single length numbers.
The following mathematical operations are all built into
froth
:
/ ( a b -- n )
: division
(5 2 / => 2.5
)%/% ( a b -- n)
: integer division
(5 2 %/% => 2
)mod ( a b -- rem )
: remainder when dividing
a / b
/mod ( a b -- rem quot )
: integer divides
a %/% b
, pushes the remainder and then the quotient^ ( a b -- n )
: raises a^b
negate ( a -- n )
: negates a
abs ( a -- n )
: takes the absolute value of
a
min ( a b -- min )
: pushes min(a,b)
max ( a b -- max )
: pushes max(a,b)
sqrt ( a -- root )
: pushes sqrt(a)
Unfortunately, there are some problems that just can’t be solved with
stacks and postfix…at least, not without more tools. Consider the
equation (a-b)/c
. In postfix, this would be
a b - c /
. Now, if we wanted to write a word with
definition ( c a b -- d )
that applies the function
(a-b)/c
, you’d find that it isn’t quite possible with the
tools we have. Defining : SOLUTION? - /
would instead apply
c / (a - b)
, which isn’t quite right. What we need is a way
to swap the top two values, so that we run
(a-b)/c
.
This is where stack operators come in handy. The operator we’re
looking for is the aptly named SWAP ( a b -- b a )
. which
swaps the first two elements of the stack. Using this, we can write our
definition:
fr> : TRYTHIS ( c a b -- d ) - swap / ;
ok.
fr> 4 2 1 trythis .
0.25 ok.
(2-1)/4 = 1/4 = 0.25
, so this works! Here are a couple
other stack operators that are often useful:
SWAP ( a b -- b a )
: swap top two stack elementsDUP ( n -- n n )
: duplicate the top stack elementOVER ( a b -- a b a )
: duplicate the second element to
the top of the stackROT ( a b c -- b c a )
: rotate the third item to the
topDROP ( n -- )
: discard the top element of the
stack.S ( -- )
: print out the contents of the stackWe also have a set of stack operators that work on pairs of numbers, but perform the same functions:
2SWAP ( a b c d -- c d a b )
: swap the top two
pairs2DUP ( a b -- a b a b )
: duplicate the top pair2OVER ( p1 p2 -- p1 p2 p1 )
: duplicate the second pair
(p1
) to the top2DROP ( a b -- )
: discard the top pairfroth
actually has two stacks. The main one, the
parameter stack, is what you’ll spend the majority of your time working
with. Whenever we “push to the stack”, that’s referring to the parameter
stack.
However, froth
also has a second stack called the Return
Stack. It’s possible for you to use this stack as a sort of “temporary
space” to hold values while you process other things. It’s very
important to ensure you clear the values on this temporary stack before
you finish processing! froth
is much more forgiving than
Forth on this point, but it’s good to get in the practice of good Forth
code.
>R ( n -- )
: moves the value on the parameter stack
to the return stackR> ( -- n )
: moves the value on the return stack to
the parameter stackR@ ( -- n )
: copies the value on the return stack to
the parameter stackThis can sometimes be very useful. For instance, say we wanted to
swap the second and third elements of the stack (that is, go from
2 3 1
to 3 2 1
). We can do this with:
fr> 2 3 1
ok.
fr> >R SWAP R>
ok.
fr> .s
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
[[4]]
NULL
ok.
Fundamental Forth gives an excellent example of using these
operators: suppose we want to write a function
quadratic ( a b c x -- n )
that returns
ax^2 + bx + c
.
fr> : QUADRATIC ( a b c x -- n ) >r swap rot r@ * + r> * + ;
ok.
fr> 2 7 9 3 quadratic .
48 ok.
For completeness, here are some other arithmetic operations:
1+ ( n1 -- n2 )
: adds 11- ( n1 -- n2 )
: subtracts 12+ ( n1 -- n2 )
: adds 22- ( n1 -- n2 )
: subtracts 22* ( n1 -- n2 )
: multiplies by 22/ ( n1 -- n2 )
: divides by 2We also have some funky double operators:
*/ ( a b c -- n )
: pushes (a*b) / c
*/mod ( a b c -- rem quot )
: pushes the remainder and
quotient of (a*b) %/% c
If you’re coming from Forth, you may recognize these are operations
using double-length values as intermediates for increased precision.
However, since froth
uses R internals for operations,
there’s no difference between single and double length values.
/ ( a b -- n )
: division
(5 2 / => 2.5
)%/% ( a b -- n)
: integer division
(5 2 %/% => 2
)mod ( a b -- rem )
: remainder when dividing
a / b
/mod ( a b -- rem quot )
: integer divides
a %/% b
, pushes the remainder and then the quotient^ ( a b -- n )
: raises a^b
negate ( a -- n )
: negates a
abs ( a -- n )
: takes the absolute value of
a
min ( a b -- min )
: pushes min(a,b)
max ( a b -- max )
: pushes max(a,b)
sqrt ( a -- root )
: pushes sqrt(a)
SWAP ( a b -- b a )
: swap top two stack elementsDUP ( n -- n n )
: duplicate the top stack elementOVER ( a b -- a b a )
: duplicate the second element to
the top of the stackROT ( a b c -- b c a )
: rotate the third item to the
topDROP ( n -- )
: discard the top element of the
stack.S ( -- )
: print out the contents of the stack2SWAP ( a b c d -- c d a b )
: swap the top two
pairs2DUP ( a b -- a b a b )
: duplicate the top pair2OVER ( p1 p2 -- p1 p2 p1 )
: duplicate the second pair
(p1
) to the top2DROP ( a b -- )
: discard the top pair>R ( n -- )
: moves the value on the parameter stack
to the return stackR> ( -- n )
: moves the value on the return stack to
the parameter stackR@ ( -- n )
: copies the value on the return stack to
the parameter stack1+ ( n1 -- n2 )
: adds 11- ( n1 -- n2 )
: subtracts 12+ ( n1 -- n2 )
: adds 22- ( n1 -- n2 )
: subtracts 22* ( n1 -- n2 )
: multiplies by 22/ ( n1 -- n2 )
: divides by 2*/ ( a b c -- n )
: pushes (a*b) / c
*/mod ( a b c -- rem quot )
: pushes the remainder and
quotient of (a*b) %/% c