c++ - How many sig figs in a double? -
as know, floating point numbers can't represent numbers. i'm not asking question precision of floats or doubles.
in program, floating point numbers "come somewhere". might originate promoting integer, others numeric literals.
int x = 3; double xd = x; float xf = 3.0f; double xd2 = 3.0;
of course, floating point numbers come calculations involving other numbers.
double yd = std::cos(4.0);
in problem, read in floating point numbers text file, , other times, receive them complex function must treat black box. creator of text file may choose enter many significant figures -- might use three, or perhaps eight.
i perform computations using these numbers , know how many significant figures implied when created.
for argument, consider performing adaptive piecewise least squares fit input points. continue splitting piecewise segments until tolerance achieved. want (in part) base tolerance on significant figures of input data -- don't fit 10^-8 if data rounded nearest 10^-3.
others (below) have asked similar questions (but not quite same). example, i'm not particularly concerned representation output user in pretty form. i'm not particularly concerned recovering same floating point representation output text value.
how calculate number of significant decimal digits of c++ double?
how can test how many significant figures float has in c++?
i'd calculate sig figs based purely on value of double itself. don't want bunch of text processing on original data file.
in cases, floating point numbers end large series of 0000000 or 99999999 in middle of them. intuitive problem statement i'm interested in figuring out repeating 0 or 9 sequence begins. however, i'd prefer not looping rounded string conversion approach. i'm hoping direct , efficient way figure out.
perhaps simple @ looking @ least significant 'on' bit , figure out magnitude?
ok, i've come this....
#include <cstdlib> #include <cstdio> #include <cfloat> #include <cmath> double sigfigs( double x ) { int m = floor( log10( std::abs( x ) ) ); double pow10i; ( int = m; > -26; i-- ) { pow10i = pow( 10, ); double y = round( x / pow10i ) * pow10i; if ( std::abs( x - y ) < std::abs( x ) * 10.0 * dbl_epsilon ) break; } return pow10i; } int main( ) { char fmt[10]; sprintf( fmt, "%%.%de", dbl_dig + 3 ); double x[9] = {1.0, 0.1, 1.2, 1.23, 1.234, 1.2345, 100.2, 103000, 100.3001}; ( int = 0; < 9; i++ ) { printf( "double: " ); printf( fmt, x[i] ); printf( " %f %g.\n", x[i], sigfigs( x[i] ) ); } ( int = 0; < 9; i++ ) { printf( "double: " ); printf( fmt, -x[i] ); printf( " %f %g.\n", -x[i], sigfigs( -x[i] ) ); } exit( 0 ); }
which gives output:
double: 1.000000000000000000e+00 1.000000 1. double: 1.000000000000000056e-01 0.100000 0.1. double: 1.199999999999999956e+00 1.200000 0.1. double: 1.229999999999999982e+00 1.230000 0.01. double: 1.233999999999999986e+00 1.234000 0.001. double: 1.234499999999999931e+00 1.234500 0.0001. double: 1.002000000000000028e+02 100.200000 0.1. double: 1.030000000000000000e+05 103000.000000 1000. double: 1.003001000000000005e+02 100.300100 0.0001. double: -1.000000000000000000e+00 -1.000000 1. double: -1.000000000000000056e-01 -0.100000 0.1. double: -1.199999999999999956e+00 -1.200000 0.1. double: -1.229999999999999982e+00 -1.230000 0.01. double: -1.233999999999999986e+00 -1.234000 0.001. double: -1.234499999999999931e+00 -1.234500 0.0001. double: -1.002000000000000028e+02 -100.200000 0.1. double: -1.030000000000000000e+05 -103000.000000 1000. double: -1.003001000000000005e+02 -100.300100 0.0001.
it seems work desired. pow(10,i) bit unfortunate, estimation of number's base 10 magnitude.
also, estimate of difference between representable doubles crude.
does spot corner cases fails? see obvious ways improve or optimize this? nice if cheap...
rob
Comments
Post a Comment