Opened 11 years ago
Closed 11 years ago
#6627 closed Bugs (fixed)
nonfinite_num_put formatting of 0.0 is incorrect
Reported by: | Owned by: | Paul A. Bristow | |
---|---|---|---|
Milestone: | To Be Determined | Component: | math |
Version: | Boost 1.50.0 | Severity: | Problem |
Keywords: | Cc: |
Description
We noticed time strings changed from displaying 00:00.00 to 00:00000 after installing the nonfinite_num facets globally. It appears that formatting for 0.0 isn't behaving as it should when precision and fixed are involved (and potentially others).
#include <boost/math/special_functions/nonfinite_num_facets.hpp> #include <iomanip> #include <iostream> #include <sstream> void writeZero( std::ostream& stream ) { stream << std::fixed << std::setw( 5 ) << std::setfill( '0' ) << std::setprecision( 2 ) << 0.0; } int main() { std::stringstream standardStream; writeZero( standardStream ); std::cout << standardStream.str() << std::endl; std::stringstream nonfiniteStream; std::locale nonfiniteNumLocale( std::locale(), new boost::math::nonfinite_num_put< char >() ); nonfiniteStream.imbue( nonfiniteNumLocale ); writeZero( nonfiniteStream ); std::cout << nonfiniteStream.str() << std::endl; return 0; } // OUTPUT: // // 00.00 // 00000
Attachments (2)
Change History (12)
comment:1 by , 11 years ago
Owner: | changed from | to
---|
comment:2 by , 11 years ago
comment:3 by , 11 years ago
Well this looks a bit more complicated than I feared. There seems to be a difference between sending to cout (00000) and a stringstream (00.00).
cout << std::fixed << std::setw( 5 ) << std::setfill( '0' ) << std::setprecision( 2 ) << 0.0 << endl; // 00000 std::stringstream astream; astream << std::fixed << std::setw( 5 ) << std::setfill( '0' ) << std::setprecision( 2 ) << 0.0; // 00.00
which leaves me more than a bit wary of making any precipitate changes to Johan Rade's nonfinite_num_put code :-( (Before fools step in where angels fear to tread? - again!)
I'd like you to consider if it might be safer to circumnavigate this 'feature'?
Paul
comment:4 by , 11 years ago
Do you have those reversed?
int main() { std::locale::global( std::locale( std::locale(), new boost::math::nonfinite_num_put< char >() ) ); writeZero( std::cout ); std::cout << std::endl; // 00.00 std::stringstream astream; writeZero( astream ); std::cout << astream.str() << std::endl; // 00000 return 0; }
"Changing the global locale does not change the locales of pre-existing streams. If you want to imbue the new global locale on cout, you should call std::cout.imbue(locale()) after calling std::locale::global()." -- http://stdcxx.apache.org/doc/stdlibug/24-3.html
comment:5 by , 11 years ago
I may have a patch that makes the FP_ZERO case only output the '-' if ( flags_ & signed_zero ). It then reduces iosb.width() by 1 and delegates to std::num_put.
by , 11 years ago
Attachment: | nonfinite_num_put_zero_formatting.patch added |
---|
comment:6 by , 11 years ago
OK - if you are keen to fix this properly, I'll try to get to look at this more closely, including writing all the several test cases to check I haven't introduced another bug in fixing this one. You could also email me privately.
by , 11 years ago
Attachment: | nonfinite_num_facets_formatting_2.hpp.patch added |
---|
Patch to try to treat unsigned zero as normal value.
follow-up: 8 comment:7 by , 11 years ago
I have yet to fully understand how this code is intended to work.
You patch seems rather complicated?
Does my 2nd patch (that simply aims to treat an unsigned zero as a normal value) work for you ?
(While I write some tests).
comment:8 by , 11 years ago
Replying to pbristow:
I have now written a much larger collection of tests (though there are an almost infinite number of possible combinations of ostream options like precision, width, letf right, internal, showpos showpoint :-(
And committed a revised version (using code from KR Walker) that passes on MSVC 10 these tests with the signed_zero flag set (and also handles inf and nan as before).
I am not entirely convinced that there is really a need for a signed_zero flag at all.
Are there really any platforms/libraries still out there that do not output negative zero correctly as -0?
Feedback welcome.
comment:9 by , 11 years ago
Tests reveal that, for some combinations of options, there is a difference in output between Dinkumware STL and other STL implementations, for example:
#if defined(_CPPLIB_VER) && (_CPPLIB_VER >= 306) Dinkumware outputs "0.00"
CHECKOUT(std::showpoint << 0., "0.000000"); std::setprecision(6) CHECKOUT(std::setprecision(2) << std::showpoint << 0., "0.00");
#else others output "0.0"
CHECKOUT(std::showpoint << 0., "0.00000"); std::setprecision(6) CHECKOUT(std::setprecision(2) << std::showpoint << 0., "0.0");
#endif
I am unclear if either of these is 'wrong' according the C/C++ Standards, but this is outside control of Boost.Math code, so I propose to declare this fixed in trunk.
(There are also some STL libraries that use two exponent digits rather than three - this is standards conformant).
comment:10 by , 11 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
Version: | Boost 1.48.0 → Boost 1.50.0 |
Since the C++ IO Library Standard is somewhat permissive in output, and the support for signed zero is platform dependent, it is not believed possible to provide a solution which is exactly portable (producing idential output) over all platforms. It is probably wise to avoid using the signed_zero flag.
OK, looks to be a bug. Will look at this in a day or few.