JNI i dodawanie macierzy

0

Witam,
Od kilku dni męczę się z JNI, próbuję zrobić kilka natywnych funkcji dla macierzy, ale uparcie nie wychodzi:"(
mógłby mi ktoś powiedzieć jak np zrobić dodawanie macierzy?

zakładam, że jest klasa Matrix podobna do takiej

class Matrix{
    public Matrix(double a, double b, double c, double d){
        tab=new double[2][2];
        tab[0][0]=a; tab[0][1]=b; tab[1][0]=c; tab[1][1]=d;
    }
    public Matrix(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j){
        tab=new double[3][3];
        tab[0][0]=a; tab[0][1]=b; tab[0][2]=c; 
        tab[1][0]=d; tab[1][1]=e; tab[1][2]=f;
        tab[2][0]=h; tab[2][1]=i; tab[2][2]=j;
    }
    
   public native Matrix add(Matrix m2);
   
   double[][] tab;
}

coś w C w stylu

#include "Matrix.h"
#include <stdio.h>

JNIEXPORT jobject JNICALL Java_Matrix_add(JNIEnv* env, jobject cl, jobject obj)
{ 
   //co tu napisać? próbuję, czytam, znów próbuję i ślęczę przed kompem już od kilku dni, a nie wychodzi:(
}
 

i klasa sprawdzająca

class MatrixTest
{  
   public static void main(String[] args)
   {  
      Matrix m1=new Matrix(1,2,3,4);
      Matrix m2=new Matrix(4,2,3,0);
      Matrix m3=m1.add(m2);
   }

   static
   {  
      System.loadLibrary("Matrix");
   }
}

Mógłby mi ktoś pomóc?
Proszę pomóżcie
Tomek

0

Lektura na dziś:

jclass GetObjectClass(JNIEnv *env, jobject obj)
jfieldID GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *signature)
jobject GetObjectField(JNIEnv *env, jobject obj, jfieldID id)
jsize GetArrayLength(JNIEnv *env, jobjectArray array)
jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index)
jdouble *GetDoubleArrayElements(JNIEnv *env, jdoubleArray array, jboolean *isCopy)
void ReleaseDoubleArrayElements(JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode)

O ile problem masz z JNI, a nie z samym dodawaniem macierzy.

0

dziękuję za odpowiedź iooi. To co podałeś widziałem już, ale nie potrafię zastosować.
Jak skorygować ten kod? na razie chciałbym choć wyświetlić jakiś element przekazanej tablicy.

#include "Matrix.h"
#include <stdio.h>
 
JNIEXPORT jobject JNICALL Java_Matrix_add(JNIEnv* env, jobject cl, jobject obj)
{ 
    jclass klasa=(*env)-> GetObjectClass(env, obj);
    jfieldID id=(*env)->GetFieldID(env, klasa, "tab", "[[D");
    jdoubleArray tab=(*env)->GetObjectField(env, obj, id);
    jsize dlugosc=(*env)->GetArrayLength(env, tab);
    jdouble* a=(*env)->GetDoubleArrayElements(env, tab, NULL);
    fprint("%d\n", tab[0][0]); //i mam błąd:(

    return cl; //chwilowo, by nie wywalało mi błędu wykonania
}
 
1

Bo nie ma prawa Ci działać. Sam deklarujesz tab jako tablicę Doubli (jednowymiarową) a odwołujesz się jak do dwuwymiarowej.
Wielowymiarowość tablic sprowadza się do tworzenia tablic tablic. W java jest tak samo. Tak więc najpierw musisz pobrać Tablice obiektów. Te obiekty będą tablicami wartości double, i dopiero do tych tablic należy się odwoływać.
lektura dla Ciebie:
http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jnistring.html#multi

1
jclass klasa=(*env)-> GetObjectClass(env, obj);
jfieldID id=(*env)->GetFieldID(env, klasa, "tab", "[[D");
jobjectArray tab=(*env)->GetObjectField(env, obj, id);
jsize dlugosc=(*env)->GetArrayLength(env, tab);

jdoubleArray wiersz = (*env)->GetObjectArrayElement(env, tab, 0);  // pobranie tab[0]
jdouble* a=(*env)->GetDoubleArrayElements(env, wiersz, NULL);  // tab[0] do jdouble*
printf("%d\n", a[0]);  // a[0] == twoje tab[0][0]
(*env)->ReleaseDoubleArrayElements(env, wiersz, a, JNI_ABORT);

Dopisane z palca. Zapuścić do tego tylko pętlę po wierszach i elementach i masz dodawanie.

0

dziękuję:) to działa:)
Wielkie dzięki

Pozdrawiam
Tomek

0

niestety znów mam problem. Próbowałem skończyć to, by funkcja zwracała co należy, ale w ogóle nie mogę zrobić prostej tablicy:(

 
jdoubleArray nowa = (*env)->NewDoubleArray(env, 4);
jdouble dub=2;
(*env)->SetDoubleArrayElement(env, nowa, 0, dub);

czemu to nie działa??

ani to, choć to wycięte ze specyfikacji JNI:(

 
jint tmp[4];
tmp[1]=0;

jak to zrobić?

1
jdoubleArray jArray = (*env)->NewDoubleArray(env, 4);  // tworzysz tablicę javową
jdouble* array = (*env)->GetDoubleArrayElements(env, jArray, NULL);  // uzyskujesz do niej dostęp natywnie
array[0] = 10.0;  // tutaj zwykłe przypisanie, musi działać
(*env)->ReleaseDoubleArrayElements(env, jArray, array, 0);  // zwalniasz array i aktualizujesz javową tablicę wskazywaną przez jArray

Nie ma takiej funkcji jak SetDoubleArrayElement, z prymitywami musisz postępować tak, że albo uzyskujesz dostęp poprzez GetDoubleArrayElements / GetDoubleArrayRegion, modyfikujesz uzyskaną tablicę prymitywów, a potem ją zwalniasz, albo sam taką tworzysz, a potem kopiujesz do oryginału poprzez SetDoubleArrayRegion (i sam zwalniasz).

jint tmp[4];
tmp[1]=0;

To też nie może nie działać, bo jint to tylko zwykły typedef na int / long.

0

Dziękuję za odpowiedź.

niestety trzecia linia (array[0] = 10.0;) powoduje błąd:(

kompilator microsoft Visual C++ wyrzuca:

Matrix.c
Matrix.c(22) : error C2143: syntax error : missing ';' before 'type'
Matrix.c(24) : error C2065: 'j' : undeclared identifier
Matrix.c(24) : error C2065: 'j' : undeclared identifier
Matrix.c(24) : error C2065: 'j' : undeclared identifier
Matrix.c(24) : error C2065: 'j' : undeclared identifier

A jak uzyskać obiekt jakiejś klazy w Javie? np jak w powyższym przykładzie klasy Matrix? W prawdzie nie bedzie mi to raczej potrzebne do tych funkcji co mam zrobić, ale taką metoda też próbowałem i nie szło.

i jeszcze jedno, te całe JNI się przydaje w praktyce?

1

Uzyskać w sensie utworzyć? Dla funkcji add:

/* Klasę Matrix już mamy, nazwa konstruktora to zawsze <init>, typ zwracany to zawsze void. Stąd konstruktor Matrix(double a, double b, double c, double d) ma sygnaturę (DDDD)V. */
jmethodID konstruktor = (*env)->GetMethodID(env, klasa, "<init>", "(DDDD)V");
jdouble a, b, c, d;  // argumenty
jobject nowy = (*env)->NewObject(env, klasa, konstruktor, a, b, c, d);  // mamy nowy obiekt

Czy się przydaje, to na pewno, jeśli tylko musisz wołać kod natywny z poziomu Javy. Mnie się jeszcze nie przydało.

0

o coś tu pytałem, ale chyba już wiem;)

1

Nie zwalniasz tablicy, którą zwróciło GetDoubleArrayElements(env, wiersz1, NULL):

(*env)->ReleaseDoubleArrayElements(env, wiersz1, a1, 0);

Tablica otrzymana przez GetDoubleArrayElements może być kopią, więc zmiany w niej wykonane nie muszą być odzwierciedlone w javowym oryginale. Ostatni argument (0) właśnie oznacza, że tablica ma być skopiowana z powrotem
http://docs.oracle.com/javase/1.4.2/docs/guide/jni/spec/functions.html#wp17454

1 użytkowników online, w tym zalogowanych: 0, gości: 1