NAG Technical Report TR 3/2000

Calling the NAG C Library from Java


  • The Java Native Interface
  • Use of an interface library
  • Examples
  • Building more interfaces
  • References

    1. Motivation
    2. The NAG C Library [1] contains many mathematical and statistical routines which are useful for package builders. Areas covered include linear algebra, optimization, quadrature, differential equations, regression analysis, and time series analysis. Although written in C, the functionality of the library can be accessed from other languages, including C++, and on PCs, DLL versions of the library can be exploited in many ways [2]. It is natural, then, to wonder whether it is possible to call the NAG C Library from the Java programming language [3].

      For someone needing to perform numerical computations, one approach is to create Java classes implementing the required functionality; a group who have made progress in this direction, partly by writing new code and partly by converting pre-existing code from other languages into Java, is the Numerics Working Group of the Java Grande Forum. The JavaNumerics web page [4] gives much useful information, including discussion of the difficulties of using Java for numerical computation due to constraints imposed by Java as it currently stands.

      In this report, we use the alternative approach of calling the NAG C Library directly from Java, thus evading the job of writing or rewriting code, and everything that that entails in the way of testing. Of course, since we propose to call the NAG Library, our application will no longer be portable in the sense that it would have been had it been exclusively written in Java, because now it will rely on the presence of a machine-dependent implementation of the NAG Library at run time. However, it will still be portable in the sense that the NAG C Library is available on almost all commercially significant machines.

      Apart from avoiding the need to first write Java versions of numerical routines, using the NAG C Library has another advantage. Java has been designed to be portable; a compiled program will run on any machine which has an implementation of the Java Virtual Machine (VM). To accomplish this, the Java compiler does not compile to machine-dependent assembler, as do traditional languages such as C or C++, but to a machine-independent byte code. This byte code then gets interpreted at run time by the VM. Although the Java interpreter is efficient, it is clear that it would be hard for any interpreted program to run as fast as a program compiled to assembler code. For many applications this does not matter; but for applications that perform cpu-intensive operations on large amounts of data, it may be significant. By moving those operations out of Java and into the NAG Library, we may therefore hope to cut execution time.

      In order to access the NAG C Library from a Java program, we will make use of the Java Native Interface.

    3. The Java Native Interface
    4. The Java Native Interface (JNI), which comes as part of the Java Development Kit (JDK), gives compile- and run-time support to anyone who would like to call native code from a Java program. By native code, we mean non-Java code, typically C or C++; in this report we will assume C.

      At compile time, the JNI defines the way that Java data types correspond to C data types C programs get this information from JNI header files that come with the JDK. A tool, javah, that comes with the JDK, aids in creating application-specific header files which aim to eliminate mistakes in communication between Java and C routines.

      At run time, the JNI allows the passing of Java objects to the C code, and allows the C code access to Java properties and methods. Thus, for example, the C code can set properties of Java classes, and it is possible to call a Java method from C.

      During preparation of this report, we used JDK version 1.2 (now known as Java 2 SDK, SE v1.2) on two machines

      • a Sun machine running Solaris 8 (SunOS 5.8) with Sun WorkShop Compilers C version 5.0, and Mark 5 of the NAG C Library

      • a PC running Windows 2000 with Microsoft Visual C++ version 5.0, and Mark 5 of the NAG C Library

      Working on UNIX platforms other than Sun/Solaris should be similar to Solaris; the main differences are likely to be in the location of Java include files, and the method of creating a shared object (dynamic library).

      A good introduction to the Java Native Interface can be found at the Sun Microsystems Java Tutorial web site [5].

    5. Use of an interface library
    6. Use of the JNI entails creation of an intermediate shared library (on UNIX systems) or DLL (Microsoft Windows systems). This library acts as the interface between the Java code and the NAG C Library code.

      The interface library is required because when a native method (i.e. function or subroutine) is called from Java, extra arguments are prepended to the argument list of the native routine being called. These extra arguments give the native code access to Java methods and properties, but of course the NAG C Library was not designed to handle these arguments. Furthermore, the types of the arguments passed from Java do not always correspond exactly to standard C types, and so the NAG C Library cannot use them directly. The interface library must handle these issues, make its own calls to the NAG Library, and then send the results back to Java.

      The Java Native Interface as a link between Java and the NAG C Library

      Implementation of a call from Java to the NAG C Library is a three-stage process

      • Write a declaration, in Java, for the native method. This declaration will include the keyword native to signify to the Java compiler that it will be implemented externally.

      • Create a header file for use by the native (C) code. This header file contains the declaration of the native method as viewed by the C compiler, i.e. it includes the extra arguments required for the C function to access Java methods and properties, and also has argument types defined in terms of standard C types.

      • Implement the native method in C. This function will use the header file created above, make calls to the NAG C Library and possibly back to Java methods, and return results to Java. The C code is compiled to build the interface library.

      When the interface library has been built, the Java code that uses it is still machine-independent even though the interface library is not. Thus, we need to build the interface library on all platforms that we are interested in, but we do not have to edit or rebuild the Java code that uses it.

    7. Examples
    8. The process of creating an interface library is most easily understood by demonstration. We give three examples, each showing different aspects of use of the JNI with the NAG C Library.

      • 4.1 Example 1  Bessel function Y(x)
        The simplest possible example: we call a function with only one return value the Y(x) Bessel function routine s17acc. No special code is required to handle the single return value.

      • 4.2 Example 2  Solving a system of linear equations A x = b
        We call a function which returns an array of results the linear equation solver f04arc. Extra code is required to get data from Java to C and results back from C to Java.

      • 4.3 Example 3  Evaluating the definite integral of a user-supplied function f(x)
        We call a function which requires a function as one of its arguments the quadrature routine d01ajc. We demonstrate how the C code can call back to a Java method to evaluate the function to be integrated. Also, we will see how the C code can pass results back to Java by modifying Java class properties.

    9. Building more interfaces
    10. If you have studied all three examples above, you will have learned the basic techniques for passing information between Java and the NAG C Library. You should be able to use these techniques, and perhaps re-use some of the source code presented here, to create interfaces to many other of the routines in the NAG Library. It should be relatively easy to enhance the interfaces presented, for example to return an error message to Java when a NAG routine has failed, instead of just returning an integer code.

      With a little more effort it should also be possible to interface to other NAG Libraries, such as the NAG Fortran 77 Library. In this case, it may be possible to create the interface library for some routines in Fortran rather than C. However, there is little doubt that it would be easier to continue to write the interface in C, and then make calls to the NAG Fortran Library from C. The issue of how C types correspond to Fortran types will arise, and for routines that use multi-dimensional arrays, the storage conventions adopted by the different languages will need to be taken into account; C and Java both use row-major order for 2D arrays, whereas Fortran uses column-major order. This means that at some point, in either the Java or C code, arrays may need to be transposed.

      If you are interested in calling NAG Fortran routines from Java, NAG supplies header files [6] that can help to make it easier to call NAG Fortran 77 Library routines from an interface library written in C.

    11. References

    Copyright 2000 Numerical Algorithms Group