Network to / from host conversion
GullRaDriel

Hell ho !

I want to be able to send some double values over a network, but as I want to do it the right way I am in search of some converting function.

Have you ever hear about something as ntohd, htond functions ?

CGamesPlay

No such function. Doubles are stored in IEEE-754 format on Intel, the same may be true for Macs. This being the case, you can simply transfer them as data.

Matt Smith

As discussed before, it can often be more efficient to send numbers as text. It can even be more accurate if the numbers are rational e.g. 0.1

CGamesPlay

Not that the gained accuracy means anything, since you'll just convert it to base 2 when you receive it.

piccolo

extern int StringToNumber(string MyString)
{
  istringstream converter(MyString);
  int result;
  converter >> result;
  return result;
}
extern string NumberToString(int Number)
{
  ostringstream converter;
  converter << Number;
  return converter.str();
}

CGamesPlay

Great, and it has nothing to do with doubles ::)

BAF

Just use that templated one posted a while back.

Matt Smith

It's true, but at least you can be sure the other side can convert it to its own format, using strtod() and sprintf()

GullRaDriel

Thanks to All, thanks to piccolo too ( even if you were not seeing what the question was ).

CGamesPlay: I was thinking so but waiting for someone to confirm.
Matt Smith: I got big and tons of values. Using sprintf trick is too much cost.

What I got tested: same byte order in all Intel/Amd. seem reversed for Sun/Aix.

A good job has been made there

I am waiting for BAF and his link !

I want to give cookies !

Quick !

:D

HoHo

You could also use Allegro fixed point datatype. It should have guaranteed percision on all platforms. Only problem is limited range and percsision.

gillius

Basically all machines use IEEE-754 floating point format. However, the endianess of this value is like any other issue. What I did for my network library GNE is to say that all values will be sent little-endian (I chose this because I expect virtually all peers to be little-endian). For floating point I said that I will send in little-endian IEEE-754 single or double precision. Well, Intel and Sun and PPC machines all use IEEE-754, so what the plan is just to say machines that don't support IEEE-754 are just simply "not supported" by any current port of GNE, and if I really need to do it, it isn't too onerous to actually parse a IEEE-754 number by breaking it into its components then using portable C to "convert" it to a float/double. But since I can't find a computer you actually need to do this for nor expect any target user of my library to have one, I never wrote the code.

So, in other words, do whatever you want as long as you precisely define it and give yourself a way out. If that's true, then if the unexpected happens, you can actually perform the work.

BAF

I don't recall what thread it was in, but it was something like (untested code I just wrote):

template<typename t> t ReadNum(std::string src)
{
    t ret;
    std::stringstream s(src);
    s >> ret;
    return ret;
}

template<typename t> std::string WriteNum(t src)
{
    std::stringstream ret;
    s << src;
    return s.str();
}

You would do something like:

string myString = WriteNum(myFloat);
// then:
float myFloat = ReadNum<float>(myString);

Again, untested, but probably works.

orz

What gillius said. Something like:

COMPILE_TIME_ASSERT(sizeof(float) == sizeof(int));
float ntohf ( float net_format ) {
   int r = ntohl((int&)net_format);
   return (float&)r;
}
float htonf ( float net_format ) {
   int r = htonl((int&)net_format);
   return (float&)r;
}

That requires that ints be 32 bit types. There's no pretty (by pretty I mean, without ifdefs) way to do the same for doubles, because doubles are 64 bit and there's no standard endianness conversion function for 64 bit values.

I do not like the use of text for this purpose. The advantages are that it is a variable length format that the standard library already supports. The disadvantages are that it has a space efficiency < 50% and its decimal nature makes it use more cycles than is needed for something as simple as encoding a floating point value.
If you were going to use text-based packets anyway though, why make your packets be stringstreams instead of using ReadNum/WriteNum wrappers?
edit:added missing paren

ImLeftFooted
Baf said:

untested, but probably works.

Heres a more optimized version:

template<typename t> t ReadNum(std::string src)
{
    t ret;
    std::istringstream s(src);
    s >> ret;
    return ret;
}

template<typename t> std::string WriteNum(t src)
{
    std::ostringstream ret;
    s << src;
    return s.str();
}

Probably good to overload a reference parm for ReadNum for cases where you need even less overhead.

template<typename t> void ReadNum(std::string src, t &ret)
{
    std::istringstream s(src);
    s >> ret;
}

CGamesPlay

That's not "more optimized", it's just a smaller vtable :P A more worthwhile optimization:

template<typename t> t ReadNum(const std::string& src)
{
    t ret;
    std::istringstream s(src);
    s >> ret;
    return ret;
}

template<typename t> std::string WriteNum(const t& src)
{
    std::ostringstream ret;
    s << src;
    return s.str();
}

ImLeftFooted
Quote:

That's not "more optimized", it's just a smaller vtable

If it wasn't more optimized why would it exist?

GullRaDriel

Well, I got my problem resolved:

On all Intel (PC) computers, nothing to do.

I test the following:

1#include <stdio.h>
2 
3int main(){
4 
5FILE *out;
6 
7double toto = 3.1415926535;
8 
9out = fopen( "test" , "w" );
10 
11fwrite( &toto, sizeof( double ) , 1 , out );
12 
13fclose( out );
14 
15printf("%d\n",sizeof( double) );
16 
17}

On both the output value is 8 meaning that the size is the same.

On Intel bytes are ordered as following:

od -cx said:

od -cx test
0000000 D 027 A T 373 ! \t @
1744 5441 21fb 4009
0000010

On SUN this is the following:

od -cx said:

0000000 @ \t ! 373 T A 027 D
4009 21fb 5441 1744
0000010

So basically we can see that we should swap bytes by pack of two from start to end.

So basically we can see that we should swap bytes from start to end.

;D

Thanks to all !

Cookies time !

EDIT: WTF ! I did as you said in my test code (getting the double value when opening an intel file on a sun ) And I really dunno why I write a so silly mistake. Thanks for pointing it out, orz.

orz
Quote:

So basically we can see that we should swap bytes by pack of two from start to end.

Nope. You should reverse in units of individual bytes, not sets of 2 bytes. The reason why you're seeing it in sets of 2 bytes is because you're printing them as 2-byte values, and the different endianness then hides the sub-2-byte ordering stuff. When changing endianness on any modern computer, the correct method is to reverse order in 1 byte units.

GullRaDriel

Fixed !

CGamesPlay
Quote:

If it wasn't more optimized why would it exist?

If feet aren't meters why do they exist?

ImLeftFooted
Quote:

If feet aren't meters why do they exist?

Because the geniuses who designed C++ didn't create the foot or the meter.

CGamesPlay

Do you actually know the details of how stringstream, istreamstream, and ostringstream work? What about stringbuf?

stringstream, istringstream, and ostringstream all use stringbuf internally. It's the same class.

ImLeftFooted
Quote:

Do you actually know the details of how stringstream, istreamstream, and ostringstream work? What about stringbuf?

Yes sir.

CGamesPlay

Please either rephrase your original statement, support it, retract it or just stop posting.

ImLeftFooted

You've given me so many options...

Anyway, my point that supported it fairly solidly was that the designers of C++ (lets make an acronym form them, how about Good Old [C++] DesierS) put a whole lot of thought into every bit of C++.

If the GODS thought that there should be an istringstream and an ostringstream class as opposed to just a single stringstream class then the GODS must of had a good reason. I don't question the GODS' purpose in this and yet I accept that the GODS are all knowing (in the domain of C++) and therefore I embrace and accept the istringstream into my life.

CGamesPlay

Fair enough. My point is that istringstream isn't any faster than stringstream, it simply has a smaller vtable.

Thread #590526. Printed from Allegro.cc