Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you keep the `roll` operator straight?

Tags:

postscript

In postscript, the roll operator is very general and difficult to visualize. How do you make sure you're rolling in the right direction?

I want to get a solid handle on roll because I want to be able to transform functions using variables

/f { % x y z
    /z exch def
    /y exch def
    /x exch def
    x dup mul
    y dup mul
    z dup mul add add % x^2+y^2+z^2
} def

into functions using stack manipulations, more like

/f { % x y z
    3 1 roll dup mul % y z x^2
    3 1 roll dup mul % z x^2 y^2
    3 1 roll dup mul % x^2 y^2 z^2
    add add % x^2+y^2+z^2
} def

or

/f { % x y z
    3 { 3 1 roll dup mul } repeat
    2 { add } repeat      % x^2+y^2+z^2
} bind def

These should both execute faster by having fewer name-lookups (hashtable search).

With roll I always have to test it out; and I usually get it wrong on the first try! I'm okay with exch, though

like image 909
luser droog Avatar asked Apr 14 '13 09:04

luser droog


2 Answers

I had difficulty with roll for a very long time. I remember it now using these ways, which are all equivalent:

the rhyme (-ish)

n j roll

  • positive j, to roll away

    7 8 9  3 1 roll
    % 9 7 8

  • negative, to get it back (or "negateeve, to then retrieve")

    % 9 7 8
    3 -1 roll
    % 7 8 9


stack (of things)

Perhaps a better way to think of it is a physical stack (of books, say) so the top of stack is literally "on top".

Then a positive roll goes up:

   for j number of times
     pick up n books
     put the top one on the bottom (shifting the substack "up")
     put them back down

And a negative roll goes down:

   for j number of times
     pick up n books
     put the bottom one on top (shifting the substack "down")
     put them back down

sideways

But I usually picture the stack sideways, the way the objects would look in a file as a sequence of literals. So I think of the positive roll as stashing the top j things behind the nth thing; and the negative roll as snagging j things starting with the nth thing. Give and Take.

Away.

n j roll

__ j > 0 __     move top j elements to the bottom of n

 n            TOS
  -------------|
 |       j     |
 |        -----|
 |       |     |
 V       V     |

 a b c d e f g h

^       |       |
|       |-------|
^           |
 -<-<-<-<-<-
   move

And back.

__ j < 0 __   move j elements from the bottom of n to the top

 n            TOS
  -------------|
 |     j       |
 |-----        |
 |     |       |
 V     V       |

 a b c d e f g h

|       |       ^
|-------|       |
   |           ^
    ->->->->->- 
       move

lint-roller

Still another way is to picture it sideways, and laying a sticky wheel on top (a lint-roller, maybe)

(a) (b) (c) (d) (e) 5 3 roll

           _______
          /       \
          |   3   |
          | / | \ |
          \_______/
 (a) (b) (c) (d) (e)

Then a positive roll goes counterclockwise just like arc and rotate.

       _______ (e)
      /     / \
      |   3 --| (d)
      |     \ |
      \_______/ (c)
 (a) (b)


   (e)__(d)__(c)
     /\  |  /\
     |   3   |
     |       |
     \_______/
   (a) (b)


   (c)_______
     /\      \
 (d) |-- 3   |
     |/      |
     \_______/
  (e) (a) (b)


    _______
   /       \
   |   3   |
   | / | \ |
   \_______/
 (c) (d) (e) (a) (b)

And a negative roll goes clockwise like arcn and a negative rotation.

    _______
   /       \
   |   3   |
   | / | \ |
   \_______/
 (a) (b) (c) (d) (e)


   (a)_______
     /\      \
 (b) |-- 3   |
     |/      |
     \_______/
  (c)       (d) (e)


   (c)__(b)__(a)
     /\  |  /\
     |   3   |
     |       |
     \_______/
   (d) (e)

       _______ (c)
      /     / \
      |   3 --| (b)
      |     \ |
      \_______/ (a)
 (d) (e)
           _______
          /       \
          |   3   |
          | / | \ |
          \_______/
 (d) (e) (a) (b) (c)

eliminate the negative

It shouldn't be difficult to see that negative rolls are entirely unnecessary because if j<0, it can be replaced by n-j. eg.

3 -1 roll  % roll bottom 1 element from 3 to the top
3 2 roll   % roll top 2 elements behind the 3rd

are the same.

16 -4 roll  % roll bottom 4 elements from 16 to the top
16 12 roll  % roll top 12 elements behind the 16th

are the same.


This leads to the final, ultimate simplified view (though each of the above will work, too).

Roll is just a big Swap

You're really just exchanging the top j elements with the n-j elements below that.

Say you have this mess on the stack (where $TOS$ marks the top of the stack), and want to order it properly:

g  h  i  j  k  l  m  n  o  p  q  r  s  t  u  v  w  x  y  z  a  b  c  d  e  f $TOS$

Count up (down) for n and j.

g  h  i  j  k  l  m  n  o  p  q  r  s  t  u  v  w  x  y  z  a  b  c  d  e  f
26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9  8  7  6  5  4  3  2  1
|                                                         | j = 6 .  .  .  .
| n = 26 .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .

> 26 6 roll   pstack

 a  b  c  d  e  f  g  h  i  j  k  l  m  n  o  p  q  r  s  t  u  v  w  x  y  z

A negative value for j simply positions that dividing line relative to the deepest element from among the n elements (it counts from below).

t  u  v  w  x  y  z  a  b  c  d  e  f  g  h  i  j  k  l  m  n  o  p  q  r  s
26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9  8  7  6  5  4  3  2  1
.  .  .  .   j = -7 |                                                      |
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . n = 26 |

> 26 -7 roll  pstack

 a  b  c  d  e  f  g  h  i  j  k  l  m  n  o  p  q  r  s  t  u  v  w  x  y  z

Here is a convenience function that gives an interface to roll that's more closely analogous to the big swap view.

% r0..rN  s0..sM  N  M   swap   s0..sM  r0..rN
% a gentler interface to the power of roll
/swap {
    exch 1 index add exch
    roll
} def
0 1 2 3 /a /b /c 4 3 swap pstack

Output:

GPL Ghostscript 8.62 (2008-02-29)
Copyright (C) 2008 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
3
2
1
0
/c
/b
/a
GS<7>GS<7>
like image 194
luser droog Avatar answered Oct 11 '22 21:10

luser droog


Simple saying: if you make some round object roll, its distance from you will probably be greater after than before, unless you use something else than you hand (e.g.: a magical wand, ...) to make the object roll.

5 1 roll means that the 1 object on the top of the stack will afterwards be at a greater distance from the top of the stack.

10 11 12 13 14 15 16 17 18 19 20 5 1 roll

is the same than

10 11 12 13 14 15 20 16 17 18 19

You see 20 has gone deeper, and last five element changed position.

5 in 5 1 roll means that only the five first objects from the stack may all change position.

-1 and 4 are the same modulo 5, hence it is easy to remember that negative numbers have to be modified to be positive before applying this solution.

like image 28
user2987828 Avatar answered Oct 11 '22 20:10

user2987828