Skip to content

The J DLL and Extended Integers

Vector 13:1, page 149

system interfaces language design

Transcribed from the printed issue; not yet reviewed. Read it in the PDF of the issue, page 149

J DLL

With J Release 3, the J interpreter is packaged as a 32-bit DLL. Any program capable of calling a 32-bit DLL can now call a J subroutine directly.

The file J.DLL has the full J language, including external facilities such as the file system and ODBC interface, but without the Windows GUI functions and the Session Manager. The size is about 450K, compared to 950K for the full J development system. The DLL is freely available, and the current version can be downloaded from the J Web page.

The DLL is also an OLE in-process server and can be accessed via OLE.

The DLL will most likely be of interest to developers in languages such as Visual Basic, Delphi, C++ or Excel, who can now incorporate J as a calculation server in their applications. However it can also be called by Windows APL systems.

Why would anyone want to call J from APL? Well, for one thing it is a nice way to experiment with the DLL — since APL knows how to display arrays, there is no problem in displaying the results from J!

Also, J has some facilities that not are not in all APLs, such as ODBC data access support, complex numbers and extended integers. The DLL allows you to add such features to your own APL applications.

Finally, for those interested in experimenting with the use of J, or perhaps in migrating applications from APL to J, this allows you to call new functions written in J from an existing APL application.

An example using APL*PLUS III

The callable functions supported by the J DLL are a subset of those available using OLE. For the most part, you need only:

Do execute a J sentence
GetM get a J variable (returns the memory address)

To access the J DLL, you must first ensure the DLL is visible — the easiest way to do this is to copy the J.DLL file into your APL directory.

Next, you define associated functions to call J, using ⎕na. These functions behave like user-defined, locked, monadic APL functions. For example, the following defines associated functions for Do and GetM:

    ∇ makejfns;r
[1]   ⍝ defines ⎕na fns:
[2]   ⍝   j_do
[3]   ⍝   j_getm
[4]
[5]   r←⎕ex 'j_do j_getm'
[6]
[7]   r←''
[8]   r←r,'DLL I4←J.JDo(*C1)' ⎕na 'j_do'
[9]   r←r,'DLL I4←J.JGetM(*C1,*I4←,*I4←,*I4←,*I4←)' ⎕na 'j_getm'
[10]
[11]  ⎕error (0∊r)/'could not define ⎕na fns'
    ∇

This function must be run first, to initialize the link with J. If it runs without error, the link is established.

Cover functions

The associated function j_do takes an argument of an enclosed character string terminated with an ASCII zero character, and sends it to J to be executed. The following cover function jdo ensures the argument is in the correct form, sends it to J, and signals any result error:

    ∇ r←jdo str;a0
[1]   ⍝ str is a character string
[2]
[3]   ⍝ ensure is zero terminated:
[4]   a0←⍬⍴⎕av
[5]   str←str,(a0≠¯1↑str)/a0
[6]
[7]   :if 0=r←j_do ⊂str  ⋄ :return ⋄ :end
[8]   ⎕error 'return code: ',⍕r
    ∇

The associated function j_getm takes an enclosed character string that represents a J variable name, terminated with an ASCII zero character, and sends it to J to be retrieved. The result from J is a set of pointers to the variable’s type, rank, shape and data. A utility function jfix (not listed here) reads these pointers and creates the corresponding APL array.

The cover function jget is:

    ∇ r←jget name;a0;pdat;pshape;rank;rc;type
[1]   ⍝ name is a character string
[2]
[3]   ⍝ ensure is zero terminated:
[4]   a0←⍬⍴⎕av
[5]   name←name,(a0≠¯1↑name)/a0
[6]
[7]   (rc type rank pshape pdat)←j_getm (⊂name),4⍴⊂,¯1
[8]
[9]   :if 0≠rc ⋄ ⎕error 'return code: ',⍕rc ⋄ :return ⋄ :end
[10]
[11]  r←type rank pshape jfix pdat

The utility function jcmd calls jdo then jget:

    ∇ r←jcmd exp
[1]   r←jdo 'JXP=: ',exp
[2]   r←jget 'JXP'
    ∇

Examples

      jcmd 'i.2 3 4'              ⍝ same as: 2 3 4 ⍴ ⍳24
  0  1  2  3
  4  5  6  7
  8  9 10 11

 12 13 14 15
 16 17 18 19
 20 21 22 23

      jcmd 'q: 123456'            ⍝ prime factors of 123456
2 2 2 2 2 2 3 643

      ×/jcmd 'q: 123456'
123456

Boxed arrays are returned as APL nested arrays:

      jcmd '''hi there'';i.2 3'
 hi there    0 1 2
             3 4 5

      ds jcmd '''hi there'';i.2 3'   ⍝ display structure

+→-------------------+
| +→-------+ +→-----+ |
| |hi there| | 0 1 2| |
| +--------+ | 3 4 5| |
|            +~-----+ |
+∊-------------------+

Complex numbers are returned as real and imaginary pairs:

      jcmd '_1^(>:i.5)%5'         ⍝ fractional powers of ¯1
 0.80901699 0.58778525
 0.30901699 0.95105652
¯0.30901699 0.95105652
¯0.80901699 0.58778525
¯1          0

Extended integers are returned as character strings:

      jcmd '*/x:p:i.20'         ⍝ product of first 20 primes
557940830126698960967415390x

The overhead of using jcmd is around 2 milliseconds on a P133.

The J DLL and workspace JDLL.W3 can be downloaded from the J Web page www.jsoftware.com.

Extended Integers

J 3.02 includes support for extended precision integers. This is an upwards-compatible extension that leaves the existing treatment of integers unchanged.

If you want to add extended integers to APL, you need only call the J DLL!

An extended integer is entered and displayed with a suffix of ‘x’. Also, the verb x: applies to integers and returns extended precision integers. Various primitives produce extended results if the arguments are extended. For example:

   2^100                      standard
1.26765e30

   2^100x                     extended
1267650600228229401496703205376x

The topic of Multiprecision Arithmetic was recently discussed in a series of articles by John Sullivan in Vector Vol 12, issues 1-4. In fact, John described an implementation for both multiprecision integers and floating point numbers. J3.02 supports only multiprecision integers, though this covers a lot of ground; moreover many floating point calculations can be emulated using extended integers. For example, the following illustrates the convergence of the Taylor series for e, the last value for 40 terms being correct to 48 digits:

   p=. (10^50x)"_
   e=. (p * [: +/ ! % !@i.) <.@% !
   ,. e &> 20 30 40x
271828182845904523492875272833519940029860437269664x
271828182845904523536028747135265860223807331507783x
271828182845904523536028747135266249775724709369870x

Having extended integers in the language is a big benefit in convenience and speed. Indeed, the performance is far better than for defined functions. Here are sample timings in milliseconds on a P133, comparing the new extended integers against the functions in bignum.js, a script distributed with J:

N 1e2 1e3 1e4 1e5 1e6
2^N bignum 93 335 7140 n/a n/a
extended 0.5 2.2 112 9050 n/a
2^N (mod N+1) bignum 132 225 302 374 516
extended 1.6 2.8 3.2 5.8 7.5