Reputation: 933
I am trying to convert scientific double to decimal double in java. I am sending a value from server (coded on C++) which is running on X86 (little endian) machine and I was using htonl, ntohl methods for convertion before sending data to client (coded on java). But now, I have to sent this value with no conversion like LE to BE. The coversion is being done on client (java) side. Other type can be converted correctly but for double, this is not present. When client receive a double type, this value can not be read correctly. Here is my java code for double conversion.
protected int readInt(InputStream stream) throws IOException {
int i0 = read(stream);
int i1 = read(stream);
int i2 = read(stream);
int i3 = read(stream);
int i=(i0 << 24) + (i1 << 16) + (i2 << 8) + (i3 << 0);
return i;
}
protected double readDouble(InputStream stream) throws IOException {
int i0 = readInt(stream);
int i1 = readInt(stream);
return Double.longBitsToDouble(((long)i0 << 32) + (i1 & 0xffffffffL));
}
After all of these steps, I got 9.534475227E-315 if I sent 0.3 from server.
Thanks and regards.
Upvotes: 1
Views: 6204
Reputation: 78316
If you sent 0.3 from server to client and got back 9.534475227E-315 the last thing you ought to do is convert that value to 0.3 again. The returned value is very close to 0 in f-p terms, and indicates some error in the sending and returning process.
I am puzzled at your question, I did not know that Java implemented a Decimal class but then my Java knowledge is old and scant. Do you perhaps mean a BigDecimal ? Or are you converting string formats of floating-point numbers, which would be a completely different kettle of fish?
Upvotes: 0
Reputation: 933
I solved the my question and thank to you all for your helps. Much appreciated. So here is the solution.
protected double readDouble(InputStream stream) throws IOException {
return Double.longBitsToDouble(((long) read(stream) & 0xff)
| ((long) (read(stream) & 0xff) << 8)
| ((long) (read(stream) & 0xff) << 16)
| ((long) (read(stream) & 0xff) << 24)
| ((long) (read(stream) & 0xff) << 32)
| ((long) (read(stream) & 0xff) << 40)
| ((long) (read(stream) & 0xff) << 48)
| ((long) (read(stream) & 0xff) << 56)); }
When I send a data from server in little endian format, I can convert incoming little endian formatted value to big endian formatted value with this code in java.
Upvotes: 0
Reputation: 48619
Don't roll your own bit twiddling like that. It's in the standard API. See java.nio.ByteBuffer
.
protected int readInt(InputStream stream) throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE);
//buffer.order(ByteOrder.LITTLE_ENDIAN); // optional
stream.read(buffer.array());
return buffer.getInt(0);
}
protected double readDouble(InputStream stream) throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(Double.SIZE / Byte.SIZE);
//buffer.order(ByteOrder.LITTLE_ENDIAN); // optional
stream.read(buffer.array());
return buffer.getDouble(0);
}
Upvotes: 1
Reputation: 584
Your use of the term "scientific notation" sorta suggests you are dealing with text data that looks like "3.0e-1". But I think I understand.
It seems like the problem is just reading binary data written in a non-java word order. Yet why are the integers written big-endian, yet the doubles written little-endian? And why are you reading in such a strange manner? Doesn't your compiler complain about the 'int'? It may have been hiding a problem. (EDIT: my error - I was stuck on 64 bits for the double)
It would be useful for everyone to see a hex dump of your data. Are the bytes flipped, or just the words?
Maybe this code will provide some inspiration. Please excuse the 'get-r-done' use of variables.
// convert CLI argument to double, write to file, and read back
// without args, default is "0.3"
// should try negative numbers!
import java.io.*;
public class BinaryFile {
public static void main(String[] args) {
String strFilePath = "WordFlippedDouble";
boolean WRITEOP = true;
double d, dd = 0.3;
long ddFlip;
if(args.length > 0) {
dd = Double.valueOf(args[0]);
}
System.out.println("Starting with " + dd + " looks like " +
Long.toHexString(Double.doubleToLongBits(dd)));
if(WRITEOP) {
ddFlip = Double.doubleToLongBits(dd);
ddFlip = (ddFlip<<32) | ((ddFlip>>32) & 0xFFFFFFFFL);
System.out.println("WRITE: (flipped) looks like " + Long.toHexString(ddFlip));
try {
FileOutputStream fout = new FileOutputStream(strFilePath);
DataOutputStream dout = new DataOutputStream(fout);
dout.writeLong(ddFlip);
dout.close();
} catch (Exception e) {
System.out.println("ERROR: " + e.getMessage());
}
}
if(false) return; // testing
try {
FileInputStream fin = new FileInputStream(strFilePath);
DataInputStream din = new DataInputStream(fin);
ddFlip = din.readLong();
d = Double.longBitsToDouble((ddFlip<<32) | ((ddFlip>>32) & 0xFFFFFFFFL));
System.out.println("READ: " + Long.toHexString(ddFlip) + " converts to " +
d + " DIFF: " + (dd-d));
din.close();
} catch(FileNotFoundException e) {
System.out.println("FileNotFoundException : " + e);
}
catch(IOException e) {
System.out.println("IOException : " + e);
}
}
}
Upvotes: 1
Reputation: 10321
It sounds like you are reading the value wrong from the client, but in any case, NumberFormat is your friend :) http://java.sun.com/j2se/1.5.0/docs/api/index.html?java/text/NumberFormat.html
EDIT: considering the code sample that you posted, I have to agree with @trashgod that your conversion code is flawed. Perhap DataInputStream can assist -> http://java.sun.com/javase/6/docs/api/java/io/DataInputStream.html
Upvotes: 3