3
(2&*~) 15 7 3 1 

Above is the phrase. At the end is the trace and the final outcome. I understand that the phrase is a monad, I understand that because of ~ it has a left and right argument. The same output happens if you run '15 7 3 1(2&*) 15 7 3 1'. I also get that the right table are powers of 2 to the 1, 3, 7, 15, and the other entries are their base number times that power of 2, but I just do not understand why.

On a related note, this is a phrase from ethopian multiplication on the Rosetta Code website (actually this is, as well, I got this far in trying to figure that out) and '(1>.<.@-:)^:a:' is the phrase.

(1>.<.@-:)^:a: 27
27 13 6 3 1

but (1>.<.@-:)^: 27 returns a box'd version of itself and I would expect it to run 27 times.

On a final of three related questions, (these are all related to decomposing the ethopian multiplication code), the complete code is given as:

double =:  2&*
halve  =:  %&2           NB.  or the primitive  -:
odd    =:  2&|

ethiop =:  +/@(odd@] # (double~ <@#)) (1>.<.@halve)^:a:

and that can be trivially substituted as:

ethiop =:  +/@(2&|@] # (2&*~ <@#)) (1>.<.@-:)^:a:

And that works fine! Flushed with success, I fell completely off of the cliff when I thought, there is a monadic double that works on the command line:

+: 98
196

And a double operator has to be faster than a double with an attached constant, maybe double just shifts, so I would think that

ethiop =:  +/@(2&|@] # (+:~ <@#)) (1>.<.@-:)^:a:

Would work...but it does not.

I have tried caps, conjunctions, and so forth, and nothing gets it to work, it always says, "domain error". I am beginning to think that the code depends on the dyadically called monad to create the doubling table in a way I do not get.

The only good thing is that the J verb odd has nothing to do with testing for an odd number.

Can anyone explain these things to me, maybe with an English explanation of how the program works? Not how the algorithm works, how it implements the algorithm. I recall when I was playing with IBM 1130 APL back in 1970. This was an APL interpreter that ran in 8k words, needless to say, it was limited. For example, it had a roll but no deal. The interpreter phased itself in and out of memory, the 1130 supported code overlays, it would separate your subroutines into groups and when one group called another, it would load the new group off of disk (yes, pseudo swapping in 8k). So I wrote versions of deal, using various schemes, and randomly, we would hit one that could phase in and out without seeking, and that version, no matter how badly written with how many lines and how many interpreter actions would run 10 times as fast as any other. I had no idea what I was doing, I would keep adding ravels and meaningless assignments and breaking statements across lines or combining them until I got one that would run without seeking. (A 52 deal 52 that was seeking could take 45 seconds).

And then last night I calculated the 150,000th Fibonacci number in J. It had to be the 64 bit version, and it took one hour, 17 minutes. I used exact arithmetic, the number has 31349 digits and it starts 1012838344936638038...... And I realized that the 1130 could never have calculated this, the number would not have fit, cause you need three of them and the biggest one made had 32k 16 bit words. I want to learn the language that can do this, but there is something missing from the doc that I am just not getting.

 trace '(2&*) 15 7 3 1' 
 --------------- 4 Conj -------
 2
 &
 *
 2&*
 --------------- 3 Adverb -----
 2&*
 ~
 2&*~
 --------------- 8 Paren ------
 (
 2&*~
 )
 2&*~
 --------------- 0 Monad ------
 2&*~
 15 7 3 1
 491520 229376 98304 32768
   1920    896   384   128
    120     56    24     8
     30     14     6     2
 ==============================
 491520 229376 98304 32768
   1920    896   384   128
    120     56    24     8
     30     14     6     2

Fibonacci Footnote:

]t150k=:6!:2 'a150k =: $ ":r150k=: {:  (,+/@(_2&{.) )^:150000 (0x 1x)'
4631.62

0 60 60 #: t150k
1 17 11.6167
r150k
10128383449366380384728502706681008427227914006240871521944866167854579423510169
50198752571599303492471943589300904953648270811064370506598260395645679940891823
17307901573781852234222080308236027906733606532470814177610613237408102006595571
1949713927351702...
a150k
31349
Nick
  • 199
  • 6
  • 2
    This seems very rambling. What does the Fibonacci number calculation have to do with the question? – Michael J. Barber Sep 19 '11 at 15:26
  • nothing, I just found it amusing that one could calculate a Fibonacci number with that many digits in J. Even if it took over an hour. I guess I just ramble, sorry. But when I have taken a run at a problem, I find that it helps answerers if they understand what direction I've taken to get there. I apologize if it makes it harder for you to understand my question. – Nick Nov 01 '11 at 01:11

2 Answers2

6

The answer is documented under Bond (&) where the following identity is noted for dyadic use:

x m&v y ↔ m&v^:x y

In your example m is 2, v is *, and both x and y are the list of four numbers 15 7 3 1 .

The phrasing on the right-hand side of the equality includes ^:x ("to the power x") which is the same as taking the verb and applying it x times. The verb is 2&* so it is applied fifteen times. And also seven times. And also three times. And also once. The results of those four applications make up the four rows of the output.

Focusing on the third one and using parentheses for emphasis, here's what's happening.

   (2&* (2&* (2&* (15 7 3 1))))
  120 56 24 8

which is the same as

   (2&*)^:3 (15 7 3 1)
120 56 24 8

which is the same as

   (3) 2&* (15 7 3 1)
120 56 24 8

Let's apply all the non-negative integers through 3 to see a pattern:

   (0 1 2 3) 2&* (15 7 3 1)
 15  7  3 1
 30 14  6 2
 60 28 12 4
120 56 24 8

At this point the similarity to your original table may make the meaning of that table accessible:

   (15 7 3 1) 2&* (15 7 3 1)
491520 229376 98304 32768
  1920    896   384   128
   120     56    24     8
    30     14     6     2

The same thing is happening, it's just happening more often because you've given some higher numbers.

kaleidic
  • 3,070
  • 1
  • 21
  • 22
2

This is just an initial stab at your questions, since nobody has replied so far:

Adverbs have long left scope:

(2&*~) <-> ((2&*)~)

The dyadic case of the function returned by bond is powered:

(x m&v y) <-> ((m&v)^:x y)

2&* doubles its argument every time it's applied, so powered 2&* multiplies its argument by a power of 2.

(1>.<.@-:)^: 27 defines a verb (since ^: is a conjunction), but does not run it. In the original phrase foo^:a: was the verb, and 27 the argument. When a: is the right argument of ^: it just runs until it converges.

Monadic +: doubles its argument, but the dyadic cases of 2&* and +: aren't related in any way, and can't be interchanged. Note that double~ is the left side of a hook, which is always called dyadically.

The only good thing is that the J verb odd has nothing to do with testing for an odd number.

Actually, 2&| y is 1 if y is an odd integer and 0 if it is an even integer, so it is a test for odd numbers.

Now, to try to explain what the algorithm is doing in plain English, let's look at it phrase by phrase, using 12 ethiop 27 as an example:

+/@(2&|@] # (2&*~ <@#)) (1>.<.@-:)^:a:

is a hook. In hooks the right part is always a monad and the left part is always a dyad.

(1 >. (<. @ -:)) ^: a:

Monad (<. @ -:) = floor @ half, halves its argument and rounds down, and then 1 >. (<. @ -: returns the minimum of that and 1. ^:a: keeps going until convergence and makes a list of the result. Thus (1 >. (<. @ -:)) ^: a: 27 is 27 halved repeatedly until it reaches 1, yielding 27 13 6 3 1

Now let's look at the left half of the hook. (2&|@] # (2&*~ <@#)) is a dyadic fork, with the arguments being the left argument to ethiop and the result of the right part of the aforementioned hook.

2&|@] is 1 if its right argument is odd, 0 otherwise. For the argument 27 13 6 3 1 the result is 1 1 0 1 1

(2&*~ <@#) is a hook again. <@# is applied monadically to 27 13 6 3 1, and boxes the length, returning (<5). Then we get to 2&*~, which as we saw, is powered in the dyadic, so this is (after ~ switches the arguments) +:^:(<5) 12.

f^:m, when m is boxed, does f <: >m times, yielding an m-length list of results (unless m is empty, in which case it runs until convergence). So this will yield 12 * 2 ^ i.5

Then the middle part of the fork is simply #, which with a boolean left argument simply filters its right argument, in this case leaving 12 * those powers of 2 for which 27 is odd.

   1 1 0 1 1 # 12 24 48 96 192
12 24 96 192

Finally +/ is sum

   +/12 24 96 192
324
sverre
  • 6,768
  • 2
  • 27
  • 35