NAG Technical Report 2/2009

Calling NAG Library Routines from Java


Start of report   Skip to Example 2   Skip to Example 3   Skip to Example 4   Skip to Example 5   Skip to Example 6

4.1. Example 1

A simple example – the Y(x) Bessel Function routine s17acc

Here we show how to call a NAG C Library function with only one return value: the Y(x) Bessel function s17acc.

Contents

  1. Function prototype from the NAG C Library Manual
  2. Declaring the native function in our Java program
  3. Loading the interface library
  4. Compiling the Java program
  5. Generating a header file for use by C
  6. Implementing the native function in C code
  7. Building the shareable library or DLL
  8. Running the program
  9. Quick summary of how to build the Bessel function example

  1. Function prototype from the NAG C Library Manual
  2. According to the C Library Manual, the prototype for function s17acc looks like this:

      #include <nag.h>
      #include <nags.h>
    
      double s17acc(double x, NagError *fail);
    
    The function takes two arguments. The first one is of type double and is the argument x of the Bessel function Y(x). The second argument to s17acc is the error handling argument fail which is of type NagError. See the NAG C Library Manual for more information about the NagError type; we need not be overly concerned with it here except to know that it allows us to get feedback regarding the correct operation of s17acc.

  3. Declaring the native function in our Java program
  4. To keep things as simple as possible for this first example, we are not going to try to pass the contents of the NagError structure back to Java. Thus, in our Java program, we declare the function like this:

      // Declaration of the Native (C) function
      private native double s17acc(double x);
    
    i.e. a method with a double argument, returning double. The native keyword tells the Java compiler that the method will be implemented outside Java.

  5. Loading the interface library
  6. As discussed earlier, we will need to build a shared library to contain the native method that interfaces between Java and the NAG C Library. Something else that the Java program must do is to load that interface library, which we name nagCJavaInterface. We do that by passing its name to a Java System.LoadLibrary() call. Note that even though the interface library may have a slightly different name depending on the operating system, the LoadLibrary call will sort it out. For example, under Solaris, the Java code
      System.loadLibrary("nagCJavaInterface");
    
    will search for a library named "libnagCJavaInterface.so", whereas under Microsoft Windows it will search for a library named "nagCJavaInterface.dll".

  7. Compiling the Java program
  8. Here is the complete source code of our Java program Bessel.java, including the native method declaration and the LoadLibrary call.
      public class Bessel
      {
    
        // Declaration of the Native (C) function
        private native double s17acc(double x);
    
        static
          {
            // The runtime system executes a class's static
            // initializer when it loads the class.
            System.loadLibrary("nagCJavaInterface");
          }
    
        // The main program
        public static void main(String[] args)
          {
            double x, y;
            int i;
    
            /* Check that we've been given an argument */
            if (args.length != 1)
              {
                System.out.println("Usage: java Bessel x");
                System.out.println("       Computes Y0 Bessel function of argument x");
                System.exit(1);
              }
    
            // Create an object of class Bessel
            Bessel bess = new Bessel();
    
            /* Convert the command line argument to a double */
            x = new Double(args[0]).doubleValue();
    
            System.out.println();
            System.out.println("Calls of NAG Y0 Bessel function routine s17acc");
            for (i = 0; i < 10; i++)
              {
                /* Call method s17acc of object bess */
                y = bess.s17acc(x);
                System.out.println("Y0(" + x + ") is " + y);
    
                /* Increase x and repeat */
                x = x + 0.25;
              }
          }
      }
    

    The main program simply gets a value of x from the command line, and calls the native method using that argument and nine other arguments derived from it.

    Now that we have written our Java program, which includes the native declaration of function s17acc, we can compile it with the following command:

      % javac Bessel.java
    

    If all goes well, the compiler should produce a file named Bessel.class.

  9. Generating a header file for use by C
  10. Having compiled Bessel.java, we can use the javah tool that comes with the JDK to create a header file that the C compiler can use. Here is the command that does it:

      % javah -jni Bessel
    

    After this, you should have a file named Bessel.h which looks like this:

      /* DO NOT EDIT THIS FILE - it is machine generated */
      #include <jni.h>
      /* Header for class Bessel */
    
      #ifndef _Included_Bessel
      #define _Included_Bessel
      #ifdef __cplusplus
      extern "C" {
      #endif
      /*
       * Class:     Bessel
       * Method:    s17acc
       * Signature: (D)D
       */
      JNIEXPORT jdouble JNICALL Java_Bessel_s17acc
        (JNIEnv *, jobject, jdouble);
    
      #ifdef __cplusplus
      }
      #endif
      #endif
    

    Points to note about this header file:

  • Implementing the native function in C code
  • Now that we have created the header file Bessel.h, we can write our C code implementation of Java_Bessel_s17acc. Here it is, in file BesselImp.c:

      #include <jni.h>      /* Java Native Interface headers */
      #include "Bessel.h"   /* Auto-generated header created by javah -jni */
    
      #include <nag.h>      /* NAG C Library headers */
      #include <nags.h>
    
      /* Our C definition of the function s17acc declared in Bessel.java */
      JNIEXPORT jdouble JNICALL
      Java_Bessel_s17acc(JNIEnv *env, jobject obj, jdouble x)
      {
        double y = 0.0;
        static NagError fail;
    
        /* Tell the routine we want no output messages on failure */
        fail.print = Nag_FALSE;
    
        /* Call the Y0(x) Bessel function s17acc */
        y = s17acc(x, &fail);
    
        if (fail.code != 0)
          printf("Error: s17acc returned fail code %d for argument %g\n",
                 fail.code, x);
    
        return y;
      }
    
    Points to note:

  • Building the shareable library or DLL
  • This step is operating-system dependent.

  • Running the program
  • Assuming that all has gone well, we can run the program using the command

      % java Bessel 1.0
    
    The expected output looks like this:

      Calls of NAG Y0 Bessel function routine s17acc
      Y0(1.0) is 0.08825696421567678
      Y0(1.25) is 0.25821685159454094
      Y0(1.5) is 0.38244892379775886
      Y0(1.75) is 0.4654926286469062
      Y0(2.0) is 0.510375672649745
      Y0(2.25) is 0.5200647624572783
      Y0(2.5) is 0.4980703596152319
      Y0(2.75) is 0.44865872156913167
      Y0(3.0) is 0.37685001001279034
      Y0(3.25) is 0.288286902673087
    

    Tip: If you get a Java error message saying that the interface library nagCJavaInterface cannot be found, or that the NAG C Library cannot be found, you may need to set an environment variable to tell the system where to look. The environment variable name is operating-system dependent.

  • Quick summary of how to build the Bessel function example
  • Given the two source files Bessel.java and BesselImp.c, issue the following commands:
    Start of report   Skip to Example 2   Skip to Example 3   Skip to Example 4   Skip to Example 5   Skip to Example 6
    Copyright 2009 Numerical Algorithms Group
    Page last updated 2011-01-25 annak
    [NP3671]