Win a copy of Think Java: How to Think Like a Computer Scientist this week in the Java in General forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

JNI issue with ByteArray

 
Dennis Quelch
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi,
I was wondering if someone could tell me what the following might be a symptom of. I'm making a JNI call from Java to C. Inside the C routine I allocate a ByteArray and populate it with a series of Floats. On the return from the JNI call I go through and parse through the byte array doing a endian swap on all the floats. Nearly all of the floats are correct, but around the middle of the array I start getting NAN returned from my readFloat() call. All the floats before and after this certain section are correct. I've verified on the C side that the byte array is being populated correctly so I'm confident it's not on that end. Note, this doesn't happen on every call to the routine either. I'm using latitude/longitude coordinates for the floats and in some instances the numbers are not reading correctly by the DataInputStream.

Any ideas? If the memory was off in the byte array then wouldn't the floats before or after the trouble section be wrong as well? What would cause readFloat to return NaN?

Code snippet from how I'm reading from the byte array on the java side



Thanks for any help diagnosing!

 
Ernest Friedman-Hill
author and iconoclast
Marshal
Pie
Posts: 24211
35
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi,

Welcome to JavaRanch!

Probably it's the way the byte array is being created, populated, and/or returned from the C side -- let's see how you're doing it.
 
Dennis Quelch
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sure, here is what I'm doing on the C side:



Like I said in my previous post. 95% of the time all the floats pass through just fine, then every so often on the java side the readFloat() call returns NaN. Even though the data going into the byte array looked fine.

Thanks so much for your time helping me figure this out!

Dennis
 
Ernest Friedman-Hill
author and iconoclast
Marshal
Pie
Posts: 24211
35
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Unfortunately I don't see anything obvious here.

Is there possibly anything inside generateLatLonPoints() which is not threadsafe? Might the problems occur when two calls happen almost simultaneously?
 
Dennis Quelch
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Unfortunately I've added some extra code to dump out the data to a file so that I can see what the exact data is when the NaN is encountered. It always looks correct to me, and nothing obvious. There is definitely something happening between the shared library and JNI call when certain floats are sent in. I thought that maybe my compiler was producing a shared library that wasn't quite compatible with what the virtual machine was expecting with regards to a floating point number. Though I would expect this behavior to show up more often than it does though.
 
Rob Spoor
Sheriff
Pie
Posts: 20527
54
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
One thing I find a bit dangerous is your assumption that one LatLon struct is always going to be 8 bytes (the size of a Java float). Whereas a Java float is always 4 bytes, there is no such requirement for C programs / libraries. I would definitely change that part of the writing, to ensure you write 8 bytes each time. Maybe something like this:
sizeof(jfloat) will return 4, so this code is no longer dependent on any compiler specific settings.

Note that in your reading loop you are reading only one float whereas two are written.
 
Dennis Quelch
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks! I'll give that a try. And yes, my java example was missing that extra readFloat(). I had just copied over some code to illustrate what I was doing. The original has both reads in it. I'll post back after testing. Thanks!

 
Dennis Quelch
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hey guys, just wanted to give you an update. I tracked down the problem and it was in the EndianUtil.swapFloat() routine. The standard EndianUtil library that you can find anywhere on the web for swapping a float has issues in about 1% of floats that are sent into it. By reading a float using the readFloat() routine of DataInputStream, converting it to bits using Float.floatToIntBits(), swapping the Integer, then converting it back to float using Float.intBitsToFloat() causes a precision error in certain cases resulting in junk being returned.

The solution is to write a new set of routines that read the bits from the bytestream directly into integers, then perform the byte swapping and converting it back to a float.

Problem solved! Moral of the story, always be wary of seemingly common utilities found on the web.

Thanks

Dennis
 
Ernest Friedman-Hill
author and iconoclast
Marshal
Pie
Posts: 24211
35
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That's great! Thanks very much for the update; this was a real stumper.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic