boost serialization stream error question

Dear All, I'm using boost serialization and have come across issues with "steam error" when I try to deseriailze from an xml or text archive. Binary archives are fine, but I can't use binary because my users need xml archives. The problem is caused by double values less than DBL_MIN. Apparently, streaming such values in causes the input stream fail_bit to be set, which causes the serialization lib to throw an exception. One work around is to make sure all double values are clamped and finite when the archive is created. I can live with this, esp. since I have algorithms that will from time to time produce non-finite results. So far what I've done is just replace BOOST_SERIALIZATION_NVP macro with the following MAKE_NVP macro that calls "FixReal": #define BOOST_SERIALIZATION_NVP(name) \ boost::serialization::make_nvp(BOOST_PP_STRINGIZE(name), name ) // Use this macro instead of BOOST_SERIALIZATION_NVP because it fixes doubles that are not streamable. // That is, it fixes double values that cause streaming errors. #define MAKE_NVP(name) \ boost::serialization::make_nvp(BOOST_PP_STRINGIZE(name), FixReal(name) ) // note the call to FixReal // does nothing -- just pass all non-double types through template<class T> inline T& FixReal( T& t ) { return t; } /// Routine to make sure doubles are streamable -- Nan, Inf, etc. cause stream errors, so we prevent them. inline double& FixReal( double& d ) { if( d < DBL_MIN ) { d = DBL_MIN; } if( d > DBL_MAX ) { d = DBL_MAX; } if( std::isnan(d) ) { d = 0; } if( std::isinf(d) ){ d = DBL_MAX; } return d; } /// We also need to fix double arrays. The ugly syntax is because // we have to pass and return a reference to an array. inline double (&FixReal( double (&d)[2] ))[2] { for( size_t ii = 0; ii < 2; ii++ ){ FixReal(d[ii]); } return d; } Ok, here's my question: How can I get the "FixReal" functionality above without having to write a specialized function for every possible double signature? For instance, I don't want to have to write inline double (&FixReal( double (&d)[3] ))[3] inline double (&FixReal( double (&d)[4] ))[4] ... etc. or any of the other POD double signatures possible. I just want the serialization library to fix the errant double values when I create the archive. I guess I could modify the "void save(const double t)" function in basic_text_oprimitive.hpp to check all doubles, but that seems like a bad plan. Any suggestions? thanks for your help, Gabe

Gabe Sibley wrote:
Dear All,
I'm using boost serialization and have come across issues with "steam error" when I try to deseriailze from an xml or text archive. Binary archives are fine, but I can't use binary because my users need xml archives.
The problem is caused by double values less than DBL_MIN. Apparently, streaming such values in causes the input stream fail_bit to be set, which causes the serialization lib to throw an exception.
One work around is to make sure all double values are clamped and finite when the archive is created. I can live with this, esp. since I have algorithms that will from time to time produce non-finite results.
So far what I've done is just replace BOOST_SERIALIZATION_NVP macro with the following MAKE_NVP macro that calls "FixReal":
#define BOOST_SERIALIZATION_NVP(name) \ boost::serialization::make_nvp(BOOST_PP_STRINGIZE(name), name )
// Use this macro instead of BOOST_SERIALIZATION_NVP because it fixes doubles that are not streamable. // That is, it fixes double values that cause streaming errors. #define MAKE_NVP(name) \ boost::serialization::make_nvp(BOOST_PP_STRINGIZE(name), FixReal(name) ) // note the call to FixReal
// does nothing -- just pass all non-double types through template<class T> inline T& FixReal( T& t ) { return t; }
/// Routine to make sure doubles are streamable -- Nan, Inf, etc. cause stream errors, so we prevent them. inline double& FixReal( double& d ) { if( d < DBL_MIN ) { d = DBL_MIN; } if( d > DBL_MAX ) { d = DBL_MAX; } if( std::isnan(d) ) { d = 0; } if( std::isinf(d) ){ d = DBL_MAX; } return d; }
/// We also need to fix double arrays. The ugly syntax is because // we have to pass and return a reference to an array. inline double (&FixReal( double (&d)[2] ))[2] { for( size_t ii = 0; ii < 2; ii++ ){ FixReal(d[ii]); } return d; }
Ok, here's my question: How can I get the "FixReal" functionality above without having to write a specialized function for every possible double signature?
For instance, I don't want to have to write
inline double (&FixReal( double (&d)[3] ))[3] inline double (&FixReal( double (&d)[4] ))[4] ... etc.
or any of the other POD double signatures possible.
I just want the serialization library to fix the errant double values when I create the archive.
I guess I could modify the "void save(const double t)" function in basic_text_oprimitive.hpp to check all doubles, but that seems like a bad plan.
Any suggestions?
thanks for your help, Gabe
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

The problem is caused by double values less than DBL_MIN. Apparently, streaming such values in causes the input stream fail_bit to be set, which causes the serialization lib to throw an exception.
The standard stream library writes out NaN values as text, but cannot read them. It shows up in various places besides the serialization library - e.g. lexical_cast. Work has been done on this. I believe that there is code in vault which deals with this. Robert Ramey

On Sun, Jan 31, 2010 at 10:34 AM, Robert Ramey
The problem is caused by double values less than DBL_MIN. Apparently, streaming such values in causes the input stream fail_bit to be set, which causes the serialization lib to throw an exception.
The standard stream library writes out NaN values as text, but cannot read them.
It shows up in various places besides the serialization library - e.g. lexical_cast.
Work has been done on this. I believe that there is code in vault which deals with this.
Why not just memcpy the double into the stream? (or bitcast it to long long or so?)

OvermindDL1 wrote:
On Sun, Jan 31, 2010 at 10:34 AM, Robert Ramey
wrote: The problem is caused by double values less than DBL_MIN. Apparently, streaming such values in causes the input stream fail_bit to be set, which causes the serialization lib to throw an exception.
The standard stream library writes out NaN values as text, but cannot read them.
It shows up in various places besides the serialization library - e.g. lexical_cast.
Work has been done on this. I believe that there is code in vault which deals with this.
Why not just memcpy the double into the stream? (or bitcast it to long long or so?)
text and xml archives are meant to be portable. This would conflict with that requirement. Then there is the fact that putting binary data into the text stream might create some conflicts depending on the characterset etc. In general, one cannot put binary data into a text stream and be able to count on getting it back. So here are a couple of options in order of my personal preference. a) Just avoid saving and restoring NaN's. They just waste space in the archive anyway. There a number ways to do this. b) find the fixup for floating point stream in either the vault and/or sand box and install that. b) wrap the double in a binary_wrapper and serialize that. This would also break portability. Robert Ramey
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

On Sun, Jan 31, 2010 at 6:11 PM, Robert Ramey
OvermindDL1 wrote:
On Sun, Jan 31, 2010 at 10:34 AM, Robert Ramey
wrote: The problem is caused by double values less than DBL_MIN. Apparently, streaming such values in causes the input stream fail_bit to be set, which causes the serialization lib to throw an exception.
The standard stream library writes out NaN values as text, but cannot read them.
It shows up in various places besides the serialization library - e.g. lexical_cast.
Work has been done on this. I believe that there is code in vault which deals with this.
Why not just memcpy the double into the stream? (or bitcast it to long long or so?)
text and xml archives are meant to be portable. This would conflict with that requirement. Then there is the fact that putting binary data into the text stream might create some conflicts depending on the characterset etc. In general, one cannot put binary data into a text stream and be able to count on getting it back.
So here are a couple of options in order of my personal preference.
a) Just avoid saving and restoring NaN's. They just waste space in the archive anyway. There a number ways to do this. b) find the fixup for floating point stream in either the vault and/or sand box and install that. b) wrap the double in a binary_wrapper and serialize that. This would also break portability.
What about for text archives print/read it out in the completely portable C99 Hex floating point constant? It encodes all possible floating point values with no loss (including NaNs and such). It is basically just a hex representation of the memory, see the C99 hex floating point standard for how it works.

OvermindDL1 wrote:
On Sun, Jan 31, 2010 at 6:11 PM, Robert Ramey
wrote: OvermindDL1 wrote:
On Sun, Jan 31, 2010 at 10:34 AM, Robert Ramey
wrote: The problem is caused by double values less than DBL_MIN. Apparently, streaming such values in causes the input stream fail_bit to be set, which causes the serialization lib to throw an exception.
The standard stream library writes out NaN values as text, but cannot read them.
It shows up in various places besides the serialization library - e.g. lexical_cast.
Work has been done on this. I believe that there is code in vault which deals with this.
Why not just memcpy the double into the stream? (or bitcast it to long long or so?)
text and xml archives are meant to be portable. This would conflict with that requirement. Then there is the fact that putting binary data into the text stream might create some conflicts depending on the characterset etc. In general, one cannot put binary data into a text stream and be able to count on getting it back.
So here are a couple of options in order of my personal preference.
a) Just avoid saving and restoring NaN's. They just waste space in the archive anyway. There a number ways to do this. b) find the fixup for floating point stream in either the vault and/or sand box and install that. b) wrap the double in a binary_wrapper and serialize that. This would also break portability.
What about for text archives print/read it out in the completely portable C99 Hex floating point constant? It encodes all possible floating point values with no loss (including NaNs and such). It is basically just a hex representation of the memory, see the C99 hex floating point standard for how it works.
This is the first I've heard of this. I couldn't find any documentation on it either. I know some people have been working on addressing this and it has been found to be non-trivial. In any case, it's not something that would be in the serialization library but rather in the standard stream or some extension of it. I am surprised to hear about something like this in C99 which hasn't been included in standard stream C++ library. Makes me think I'm missing something here. Robert Ramey
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

On Sun, Jan 31, 2010 at 10:25 PM, Robert Ramey
OvermindDL1 wrote:
On Sun, Jan 31, 2010 at 6:11 PM, Robert Ramey
wrote: OvermindDL1 wrote:
On Sun, Jan 31, 2010 at 10:34 AM, Robert Ramey
wrote: The problem is caused by double values less than DBL_MIN. Apparently, streaming such values in causes the input stream fail_bit to be set, which causes the serialization lib to throw an exception.
The standard stream library writes out NaN values as text, but cannot read them.
It shows up in various places besides the serialization library - e.g. lexical_cast.
Work has been done on this. I believe that there is code in vault which deals with this.
Why not just memcpy the double into the stream? (or bitcast it to long long or so?)
text and xml archives are meant to be portable. This would conflict with that requirement. Then there is the fact that putting binary data into the text stream might create some conflicts depending on the characterset etc. In general, one cannot put binary data into a text stream and be able to count on getting it back.
So here are a couple of options in order of my personal preference.
a) Just avoid saving and restoring NaN's. They just waste space in the archive anyway. There a number ways to do this. b) find the fixup for floating point stream in either the vault and/or sand box and install that. b) wrap the double in a binary_wrapper and serialize that. This would also break portability.
What about for text archives print/read it out in the completely portable C99 Hex floating point constant? It encodes all possible floating point values with no loss (including NaNs and such). It is basically just a hex representation of the memory, see the C99 hex floating point standard for how it works.
This is the first I've heard of this. I couldn't find any documentation on it either. I know some people have been working on addressing this and it has been found to be non-trivial. In any case, it's not something that would be in the serialization library but rather in the standard stream or some extension of it. I am surprised to hear about something like this in C99 which hasn't been included in standard stream C++ library. Makes me think I'm missing something here.
The C++98 standard predates the C99 standard, and it does not include some C99 things (like varadic macros as well as float-hex representations). Hopefully it is included in C++1x though.
participants (3)
-
Gabe Sibley
-
OvermindDL1
-
Robert Ramey