Re: different rounding behavior with float and double
Raymond Li <faihk1@gmail.com> writes:
The numbers are always 'nice' because there are constraints, e.g. the
I just wrote the following code that comes with no guarantee whatsoever.
#include <iostream> // ::std::cout, ::std::cin
#include <ostream> // <<
#include <string> // ::std::string
#include <limits> // ::std::numeric_limits
#include <cmath> // ::std::pow, ::std::round
#include <sstream> // ::std::stringstream
#include <cstdlib> // ::std::rand, RAND_MAX
/* fill with zeros at the left until the length is n */
::std::string fill( ::std::string s, size_t const n )
{ while( s.length() < n )s = "0" + s; return s; }
/* insert a dot a the position n from the right
(n is the distance from the right end of the string) */
::std::string dot( ::std::string s, int const n )
{ size_t const len{ s.length() };
return s.substr( 0, len - n ) + "." + s.substr( len - n, n )+( n ? "" : "0" ); }
template< typename T >
::std::string to_string( T const v )
{ ::std::stringstream s; s << v; return s.str(); }
/* convert v/10^i to a string */
::std::string tostring( double const v, int const i )
{ ::std::string s{ to_string(( long )v )};
::std::string t{ fill( s, i + 1 )};
return i ? dot( t, i ): t + ".0" ; }
/* round so that the number looks nice in the decimal system
if there is a nice number near
n: how many positions to try after the dot
m: how many zeros or nines approximately
are required to trigger the special rounding */
::std::string myround( double const x )
{ int n = 0.4 * ::std::numeric_limits<double>::digits10
- ::std::log( x )/::std::log( 10 );
int m = 0.4 * ::std::numeric_limits<double>::digits10;
double v = x;
for( int i = 0; i < n; ++i )
{ double const r = fabs( v - round( v ));
if( r < ::std::pow( 10, -m ))
return tostring( round( v ), i );
v *= 10.; }
return to_string( x ); }
int main()
{ ::std::cout << myround( 0.300000001 )<< '\n';
::std::cout << myround( 0.299999999 )<< "\n\n";
::std::cout << myround( 1.300000001 )<< '\n';
::std::cout << myround( 1.299999999 )<< "\n\n";
::std::cout << myround( 1.000000001 )<< '\n';
::std::cout << myround( 0.999999999 )<< "\n\n";
::std::cout << myround( 10.00000001 )<< '\n';
::std::cout << myround( 9.999999999 )<< "\n\n";
::std::cout << myround( 100.0000001 )<< '\n';
::std::cout << myround( 99.99999999 )<< "\n\n";
::std::cout << myround( 0.100000001 )<< '\n';
::std::cout << myround( 0.099999999 )<< "\n\n";
::std::cout << myround( 0.010000001 )<< '\n';
::std::cout << myround( 0.009999999 )<< "\n\n\n\n";
for( int i = 0; i < 6; ++i )
{ double const v{ ::std::pow( 10, 4 - 8 * ::std::rand() /( 1. + RAND_MAX )) };
::std::cout << v << '\n' << myround( v ) << "\n\n"; }}