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.