encoding a float

F

Fei Liu

hurcan said:
Hi all, I am trying to convert a float value to a octet stream for
transmission, I came up with solution like

float deneme=3.14156789;
float deneme2=0.0;
vector<unsigned char> vec; //this is my buffer can con contain
other things besides this float

int* val=reinterpret_cast<int*>(&deneme); // gives me jeebies
vec.push_back((unsigned char) ((*val >> 24) & 0xFF ));
vec.push_back((unsigned char) ((*val >> 16) & 0xFF ));
vec.push_back((unsigned char) ((*val >> 8) & 0xFF ));
vec.push_back((unsigned char) ((*val >> 0) & 0xFF ));
int val2=0;
int _pos=0;
val2+= ((int)vec[_pos++] & 0xFF) << 24;
val2+= ((int)vec[_pos++] & 0xFF) << 16;
val2+= ((int)vec[_pos++] & 0xFF) << 8;
val2+= ((int)vec[_pos++] & 0xFF) << 0;
deneme2=*reinterpret_cast<float*>(&val2); //ditto

it works, but i am not sure that this is the Right Way to do, I
wonder if there is
a safer or cleaner way? I tried memcpy to treat the vector as if
an array it didn't
work out well( although, It should work right?)
Any pointers would be greatly appreciated...
hurcan

Did you look into more general framework such as soap or yaml? Boost
also has a primitive serialization/deserialization framework.

Fei
 
H

hurcan solter

Hi all, I am trying to convert a float value to a octet stream for
transmission, I came up with solution like

float deneme=3.14156789;
float deneme2=0.0;
vector<unsigned char> vec; //this is my buffer can con contain
other things besides this float

int* val=reinterpret_cast<int*>(&deneme); // gives me jeebies
vec.push_back((unsigned char) ((*val >> 24) & 0xFF ));
vec.push_back((unsigned char) ((*val >> 16) & 0xFF ));
vec.push_back((unsigned char) ((*val >> 8) & 0xFF ));
vec.push_back((unsigned char) ((*val >> 0) & 0xFF ));
int val2=0;
int _pos=0;
val2+= ((int)vec[_pos++] & 0xFF) << 24;
val2+= ((int)vec[_pos++] & 0xFF) << 16;
val2+= ((int)vec[_pos++] & 0xFF) << 8;
val2+= ((int)vec[_pos++] & 0xFF) << 0;
deneme2=*reinterpret_cast<float*>(&val2); //ditto

it works, but i am not sure that this is the Right Way to do, I
wonder if there is
a safer or cleaner way? I tried memcpy to treat the vector as if
an array it didn't
work out well( although, It should work right?)
Any pointers would be greatly appreciated...
hurcan
 
R

red floyd

hurcan said:
Hi all, I am trying to convert a float value to a octet stream for
transmission, I came up with solution like

float deneme=3.14156789;
float deneme2=0.0;
vector<unsigned char> vec; //this is my buffer can con contain
other things besides this float

int* val=reinterpret_cast<int*>(&deneme); // gives me jeebies
vec.push_back((unsigned char) ((*val >> 24) & 0xFF ));
vec.push_back((unsigned char) ((*val >> 16) & 0xFF ));
vec.push_back((unsigned char) ((*val >> 8) & 0xFF ));
vec.push_back((unsigned char) ((*val >> 0) & 0xFF ));
Gener
int val2=0;
int _pos=0;
val2+= ((int)vec[_pos++] & 0xFF) << 24;
val2+= ((int)vec[_pos++] & 0xFF) << 16;
val2+= ((int)vec[_pos++] & 0xFF) << 8;
val2+= ((int)vec[_pos++] & 0xFF) << 0;
deneme2=*reinterpret_cast<float*>(&val2); //ditto

it works, but i am not sure that this is the Right Way to do, I
wonder if there is
a safer or cleaner way? I tried memcpy to treat the vector as if
an array it didn't
work out well( although, It should work right?)
Any pointers would be greatly appreciated...
hurcan

What about:

float deneme = 3.14159;
const unsigned char *const tmp_p =
reinterpret_cast<unsigned char *>(&deneme);
v.assign(tmp_p, tmp_p + sizeof(&deneme);

float deneme2 = 0;
std::copy(tmp_p.begin(), tmp_p + sizeof(deneme2),
reinterpret_cast<unsigned char *>(&deneme2));

You don't need to worry about byte ordering, etc in an int, or
shift/masking. Just use direct copy.
 
P

Pierre Asselin

In comp.lang.c++.moderated hurcan solter said:
Hi all, I am trying to convert a float value to a octet stream for
transmission, I came up with solution like
[ type-punning code elided ]

Whatever you do, follow http://www.ietf.org/rfc/rfc4506.txt .

Any pointers would be greatly appreciated...

http://xstream.sourceforge.net/ , if an LGPL library works
for you. If not, you can study their XDR code and reimplement
it from scratch, taking care not to create a derivative work.
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

Hi all, I am trying to convert a float value to a octet stream for
transmission, I came up with solution like

float deneme=3.14156789;
float deneme2=0.0;
vector<unsigned char> vec; //this is my buffer can con contain
other things besides this float

int* val=reinterpret_cast<int*>(&deneme); // gives me jeebies
vec.push_back((unsigned char) ((*val >> 24) & 0xFF ));
vec.push_back((unsigned char) ((*val >> 16) & 0xFF ));
vec.push_back((unsigned char) ((*val >> 8) & 0xFF ));
vec.push_back((unsigned char) ((*val >> 0) & 0xFF ));
int val2=0;
int _pos=0;
val2+= ((int)vec[_pos++] & 0xFF) << 24;
val2+= ((int)vec[_pos++] & 0xFF) << 16;
val2+= ((int)vec[_pos++] & 0xFF) << 8;
val2+= ((int)vec[_pos++] & 0xFF) << 0;
deneme2=*reinterpret_cast<float*>(&val2); //ditto

it works, but i am not sure that this is the Right Way to do, I
wonder if there is
a safer or cleaner way? I tried memcpy to treat the vector as if
an array it didn't
work out well( although, It should work right?)
Any pointers would be greatly appreciated...
hurcan

Seems a bit convoluted. What you want is to be able to treat the double
as an array of unsigned chars, I'd do something like this:

#include <iostream>

int main()
{
std::cout.precision(10);
double orig = 2134.4325;
std::cout << orig << std::endl;

unsigned char* bytes = reinterpret_cast<unsigned char*>(&orig);

for (int i = 0; i < sizeof(double); ++i)
{
std::cout << std::hex << (int)bytes << std::endl;
}

double res = *reinterpret_cast<double*>(bytes);

std::cout << res << std::endl;

std::cout << (orig == res) << std::endl;
}

So what I do is to cast a pointer to the double to a pointer to unsigned
char, and as long as I know what type it was from the beginning I can
get the length of the array using sizeof().

As for sending the data there might be some problems. As long as the
sending and receiving computers have the same endianness there should be
no problem but if they don't you have to take that into account.

--
Erik Wikström


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
J

James Kanze

Hi all, I am trying to convert a float value to a octet stream

In what format?
for
transmission, I came up with solution like
float deneme=3.14156789;
float deneme2=0.0;
vector<unsigned char> vec; //this is my buffer can con contain
other things besides this float
int* val=reinterpret_cast<int*>(&deneme); // gives me jeebies
vec.push_back((unsigned char) ((*val >> 24) & 0xFF ));
vec.push_back((unsigned char) ((*val >> 16) & 0xFF ));
vec.push_back((unsigned char) ((*val >> 8) & 0xFF ));
vec.push_back((unsigned char) ((*val >> 0) & 0xFF ));
int val2=0;
int _pos=0;
val2+= ((int)vec[_pos++] & 0xFF) << 24;
val2+= ((int)vec[_pos++] & 0xFF) << 16;
val2+= ((int)vec[_pos++] & 0xFF) << 8;
val2+= ((int)vec[_pos++] & 0xFF) << 0;
deneme2=*reinterpret_cast<float*>(&val2); //ditto
it works, but i am not sure that this is the Right Way to do, I
wonder if there is
a safer or cleaner way?

The first question is the one above: what is the desired format.
The above will only work if the internal format of a float
corresponds exactly to the desired format. And of course, it
also depends on int being the same size as float; I've definitly
worked on machines where it is smaller.
I tried memcpy to treat the vector as if
an array it didn't
work out well( although, It should work right?)

To memcpy, you'd have to first increase the size of the vector,
then pass the address of the target element. And of course,
memcpy is even less portable than the above; it can fail between
two different machines even if both use IEEE floating point (and
I've seen at least one case where it failed between two
different versions of the same compiler, on the same platform).
 
A

andrew_nuss

I have a similar problem. However, I am working within the same
machine, passing float/double from a JVM to native code. Currently, I
am assuming that for JNI implementations of the JVM, sizeof(jint) ==
sizeof(jfloat) and sizeof(jlong) == sizeof(jdouble) but this might not
be safe. I can only assume that a JVM can successfully encode a Java
float as a C++ jfloat and a Java double as a C++ jdouble.
The first question is the one above: what is the desired format.
The above will only work if the internal format of a float
corresponds exactly to the desired format. And of course, it
also depends on int being the same size as float; I've definitly
worked on machines where it is smaller.


To memcpy, you'd have to first increase the size of the vector,
then pass the address of the target element. And of course,
memcpy is even less portable than the above; it can fail between
two different machines even if both use IEEE floating point (and
I've seen at least one case where it failed between two
different versions of the same compiler, on the same platform).

What if I reinterpret the pointer to jdouble and jfloat as an unsigned
char* and then encode as a hexstring. Won't this work as long as my
JVM that produces the doubles and floats is the same machine and
process that consumes them within the native code?

Andy
 
?

=?iso-8859-1?q?Erik_Wikstr=F6m?=

I have a similar problem. However, I am working within the same
machine, passing float/double from a JVM to native code. Currently, I
am assuming that for JNI implementations of the JVM, sizeof(jint) ==
sizeof(jfloat) and sizeof(jlong) == sizeof(jdouble) but this might not
be safe. I can only assume that a JVM can successfully encode a Java
float as a C++ jfloat and a Java double as a C++ jdouble.







What if I reinterpret the pointer to jdouble and jfloat as an unsigned
char* and then encode as a hexstring. Won't this work as long as my
JVM that produces the doubles and floats is the same machine and
process that consumes them within the native code?

Might be, it certainly seems safer than assuming things about the size
of things. But unless this is a performance-critical part I think it
might be worth converting the ints, doubles, etc to a human readable
format (text) and then convert back. This way you can be sure that the
values are preserved.
 
J

James Kanze

I have a similar problem. However, I am working within the same
machine, passing float/double from a JVM to native code. Currently, I
am assuming that for JNI implementations of the JVM, sizeof(jint) ==
sizeof(jfloat) and sizeof(jlong) == sizeof(jdouble) but this might not
be safe. I can only assume that a JVM can successfully encode a Java
float as a C++ jfloat and a Java double as a C++ jdouble.

JNI is a different situation, and you should check the JNI
documentation to be sure, but I believe that at the JNI
interface, you'll get native format, regardless of what the JVM
uses internally.
What if I reinterpret the pointer to jdouble and jfloat as an unsigned
char* and then encode as a hexstring. Won't this work as long as my
JVM that produces the doubles and floats is the same machine and
process that consumes them within the native code?

It depends on who's reading the stream, and why. I don't really
understand what you are trying to do; you can pass float and
double directly over the JNI interface, and they should be in
native format, ready for immediate use. If you're streaming
data (e.g. into a ByteArray), then you have to follow the same
rules as everyone else: decide on a format, and ensure that
everyone codes to it. (Converting to a hex string seems off
hand to combine the worst aspects of both binary and text. I
wouldn't do it unless it was required by some external format.)
 
J

John Moeller

I have a similar problem. However, I am working within the same
machine, passing float/double from a JVM to native code. Currently, I
am assuming that for JNI implementations of the JVM, sizeof(jint) ==
sizeof(jfloat) and sizeof(jlong) == sizeof(jdouble) but this might not
be safe. I can only assume that a JVM can successfully encode a Java
float as a C++ jfloat and a Java double as a C++ jdouble.
....

What if I reinterpret the pointer to jdouble and jfloat as an unsigned
char* and then encode as a hexstring. Won't this work as long as my
JVM that produces the doubles and floats is the same machine and
process that consumes them within the native code?

There may be better alternatives depending upon what you want to do.
If you want to encode the floating-point numbers as bytes, and you
have a lot of them, you may want to use a java.nio.ByteBuffer. You
can create a double or float view of the ByteBuffer, and the byte
order is always big-endian by default. If the ByteBuffer is created
with allocateDirect, you can pass it to native functions, and get
access to the byte data directly in native code. You can do the same
in reverse to get it back.

If you're talking only a few values, you probably just want to use the
text-encoding methods described earlier. The only problem with text-
encoding numbers (especially floating-point), however, is
localization. E.g., a "," in Germany means the same as a "." in the
U.S. or Britain. We've run into this problem before at my company,
and we decided that internally-represented numbers would just use the
one localization.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,565
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top