RE: [boost] Re: Insufficient significant digits using lexical_cast
| -Original Message- | From: [EMAIL PROTECTED] | [mailto:[EMAIL PROTECTED] Behalf Of Daniel Spangenberg | Sent: Tuesday, August 19, 2003 9:25 AM | To: [EMAIL PROTECTED] | Subject: [boost] Re: Insufficient significant digits using lexical_cast In the absence of a C99 or numeric_limits significant decimal digits value (and don't forget what is needed is effectively an 'unrounded' value with some 'noisy' guard digits at the end, not just digits10) some tests show that the following if(std::numeric_limits::is_specialized && std::numeric_limits::radix == 2) { stream.precision(2 + std::numeric_limits::digits * 301/1000); } else if(std::numeric_limits::is_specialized && std::numeric_limits::radix == 2) { stream.precision(2 + std::numeric_limits::digits * 301/1000); } uses the correct number of significant decimal digits for ALL builtin bool, char, int and floating point types: And a loopback test like: l == lexical_cast(lexical_cast(l)) is true (correct) for at least some selected values - and I wager a couple of beers for all non-NaN non-Inf values ;-). Possibly a comment warning of possible trouble here would be helpful? // if neither specialized, or unusual radix, then use default stream precision of 6? // Warning: a loopback like // l == lexical_cast(lexical_cast(l)) may be false I believe a test radix == 2 is appropriate because is_iec599 (IEEE754) would fail for integer types, which actually work correctly with the above formula. Paul Dr Paul A Bristow, hetp Chromatography Prizet Farmhouse, Kendal, Cumbria, LA8 8AB UK +44 1539 561830 Mobile +44 7714 33 02 04 mailto:[EMAIL PROTECTED] For the curious I used: template bool test(T l) { cout << l << ' '; string sl = lexical_cast(l); cout << sl << ' '; T ll = lexical_cast(sl); cout << ll << (l == lexical_cast(lexical_cast(l))) // Convert type T to string and back to T. << endl; // eg for long 2147483647 2147483647 2147483647true return (l == lexical_cast(lexical_cast(l))); } // test template bool tests() { if (numeric_limits< T >::is_specialized) { cout << numeric_limits< T >::digits << ' ' << numeric_limits< T >::digits10 << ' ' << 2 + std::numeric_limits::digits * 301/1000 << endl; } else { cout << "Not specialized!" << endl; } return // for a few sample values. test< T >(numeric_limits< T >::max()) // max && test< T >(T(1)) // unity && test< T >(T(0)) // zero && test< T >(T(-1)) // -1 && test< T > (numeric_limits< T >::min()); // min } // tests and tests (); tests (); tests (); tests (); tests (); tests (); tests (); tests (); tests (); tests (); tests (); ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
RE: [boost] Re: Insufficient significant digits using lexical_cast
| -Original Message- | From: [EMAIL PROTECTED] | [mailto:[EMAIL PROTECTED] Behalf Of Daniel Spangenberg | Sent: Tuesday, August 19, 2003 9:25 AM | To: [EMAIL PROTECTED] | Subject: [boost] Re: Insufficient significant digits using lexical_cast | | I think, the correct solution would be the usage of a constant, similar to | DECIMAL_DIG, which is provided from C99 on. 5.2.4.2.2 says: | | " number of decimal digits, n, such that any floating-point number | in the widest | supported floating type with pmax radix b digits can be rounded to a | floating-point | number with n decimal digits and back again without change to the value, | | pmax log10 b if b is a power of 10 | Ceil(1 + pmax log10 b) otherwise | | DECIMAL_DIG 10" | | | My personal opinion is: Extend the DECIMAL_DIG definition for any | floating point type, | similar to digits10 I agree (and indeed have previously and now suggested) that adding to numeric_limits:: would be the best solution. But for the time being to 'fix' lexical cast, I think my suggestion, perhaps with Daryle's refinement to warn if not IEE754, is at least better than the existing formula. I will make a further suggestion when I get a moment to test it. Paul Paul A Bristow, Prizet Farmhouse, Kendal, Cumbria, LA8 8AB UK +44 1539 561830 Mobile +44 7714 33 02 04 mailto:[EMAIL PROTECTED] ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
RE: [boost] Re: Insufficient significant digits using lexical_cast
Agreed - but what do we do if NOT is_iec559? Give up? #error "Can only work with IEEE 754!" Or choose a massive amount of decimal digits? eg 40? Paul Paul A Bristow, Prizet Farmhouse, Kendal, Cumbria, LA8 8AB UK +44 1539 561830 Mobile +44 7714 33 02 04 mailto:[EMAIL PROTECTED] | -Original Message- | From: [EMAIL PROTECTED] | [mailto:[EMAIL PROTECTED] Behalf Of Daryle Walker | Sent: Monday, August 18, 2003 7:05 AM | To: Boost | Subject: [boost] Re: Insufficient significant digits using lexical_cast | | | On Sunday, August 17, 2003, at 10:33 PM, Paul A. Bristow wrote: | | [SNIP] | > But you are right that it would be better to check that | > numeric_limits::digits exists and isn't something silly before using | > the formula. With all the built-in floating point types it should be | > fine, and for other (well) User defined floating point types too. (I | > will look at this). | [TRUNCATE] | | I think you need to check numeric_limits::radix since your algorithm | had a base-2-to-10 conversion (the type may not actually be binary!). | The algorithm was based off a paper about IEEE-754; if IEEE-754 is a | requirement, you may have to check for that too (via | numeric_limits::is_iec559). Remember that even the built-in | floating-point types aren't guaranteed to match IEEE-754! | | Daryle | | ___ | Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost | | ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
RE: [boost] Re: Insufficient significant digits using lexical_cast
Sorry about the long post, but that seemed the easiest way. numeric_limits::digits10 does what it says - the number that are _guaranteed_ to be correct on output, but that isn't what one usually wants for all _significant_ on input (and I suggest again another numeric_limits::significant_digits10 which is what you get from the formaula below). But you are right that it would be better to check that numeric_limits::digits exists and isn't something silly before using the formula. With all the built-in floating point types it should be fine, and for other (well) User defined floating point types too. (I will look at this). But using +3 instead would be 1 decimal digit too many for most of the FP types. Since it is done at compile time, getting it 'just right' with the formula below shouldn't cost anything at run-time. Incidentally a suitable sort of test is float const aFloat = any_value; if (aFloat != lexical_cast(lexical_cast(aFloat ))) ( // problem } I think from previous experience that this can be shown to be true for ALL possible float values (for 32 bit representations) but it would take too long to test all doubles (assuming 64 bit representation). HTH Paul Paul A Bristow, Prizet Farmhouse, Kendal, Cumbria, LA8 8AB UK +44 1539 561830 Mobile +44 7714 33 02 04 mailto:[EMAIL PROTECTED] | -Original Message- | From: [EMAIL PROTECTED] | [mailto:[EMAIL PROTECTED] Behalf Of Daryle Walker | Sent: Tuesday, August 12, 2003 8:56 AM | To: Boost | Subject: [boost] Re: Insufficient significant digits using lexical_cast | | | [Paul claims that lexical_cast prints (floating-point) numbers with too | few precision digits. Currently, limits::digits10 + 1 is used. Paul | wants to change it to "int significant_digits10 = int(ceil(1 + | limits::digits * log10Two));" where "limits" is the numeric-limits | traits class and "log10Two" is the base-10 logarithm of 2.] | | You used an article on IEEE 754 arithmetic. Shouldn't you check if the | number type is compliant with that format? Or can this work for any | suitable type? You also have to check if "limits::digits" is 2! | | Looking at the numbers you had, couldn't you just change | "limits::digits10 + 1" to "limits::digits10 + 3"? It could be argued | that there's just a bug in the definitions of "limits::digits10" (it's | too low). | | | On Saturday, August 9, 2003, at 5:48 PM, Paul A. Bristow wrote: | [CHOP OFF really long article, with long attachments] | | ___ | Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost | | ___ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost