dirk/C++/c++/print-float


Weingarten, 10-02-16

print-float – Normal versus Exponent Formatting

Somebody told me, that the processing of floating point values is rather slow concerning the scanning as well as the formatted output. One reason might be the localization effort but system issues are also imaginable. However, localization is rather undesired for text file readers, in opposition to performance which is a must.

Some weeks ago, I proved this for scanning (i.e. strtod etc.) I was really surprised and impressed about the speed-up of my own implementation compared to the naïve approach:
char *localeOld = setlocale(LC_NUMERIC, "C");
value = strtod(text);
setlocale(LC_NUMERIC, localeOld);

My own implementation is rather straight forward but the measured speed-up (on MS Windows) was a factor of 60 ... 100! May be, I publish this code one day (currently part of my professional work) together with a test run on Linux. However, multiple source codes are easy to find in the W3 using the search engine of your choice.

This time, I planned to replace the formatted output. My first concern was: how to choose normal or scientific output. I could have search the W3 but decided to make a sample – a rather non-scientific but really quick solution. :-) Thus, I implemented a console application printing the values of in-/de-creasing numbers in a loop.

Source Code

Text Fileprint-float.cc
/** @file sample for formatted output of floating point
 *
 * Last CVS checkin:
 * $Date: $
 * $Author: scheff $
 */

/**************************************************************************/

// standard C/C++ header:
#include <iostream>
#include <string>

/**************************************************************************/

using namespace std;

/** waits for user confirm.
 *
 * @param action text with next action
 */
static void pause(const char *action)
{
  cout << "Press [ENTER] to " << action << ": " << flush;
  string str; getline(cin, str);
}

/** provides the main function of application.
 *
 * @param argc number of command line arguments
 * @param argv pointer to array of pointers to strings with command line
 *        arguments
 * @return 0 ... application exited regularly\n
 *         else ... execution of application aborted
 */
int main(int argc, char *argv[])
{
  pause("start");
  // print floating points as is
  double value1 = 1.0, value2 = 1.0; int i = 0;
  for (;;) {
    cout << '\t' << value1 << '\t' << value2 << endl;
    { double value = value1; value1 *= 0.1; if (value == value1) break; }
    { double value = value2; value2 *= 10.0; if (value == value2) break; }
    if (++i == 10) { pause("continue"); i = 0; }
  }
  // done
  pause("finish");
  return 0;
}

I compiled this sample on Linux with:

                                                                                
> g++ -o print-float print-float.cc> > > > uname -a↵
Linux pc60 2.6.18.2-34-default #1 SMP Mon Nov 27 11:46:27 UTC 2006 i686 i686 i38
6 GNU/Linux
> g++ -v↵
Using built-in specs.
Target: i586-suse-linux
Configured with: ../configure --enable-threads=posix --prefix=/usr --with-local-
prefix=/usr/local --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/us
r/lib --libexecdir=/usr/lib --enable-languages=c,c++,objc,fortran,obj-c++,java,a
da --enable-checking=release --with-gxx-include-dir=/usr/include/c++/4.1.2 --ena
ble-ssp --disable-libssp --disable-libgcj --with-slibdir=/lib --with-system-zlib
 --enable-shared --enable-__cxa_atexit --enable-libstdcxx-allocator=new --progra
m-suffix=-4.1 --enable-version-specific-runtime-libs --without-system-libunwind 
--with-cpu=generic --host=i586-suse-linux
Thread model: posix
gcc version 4.1.2 20061115 (prerelease) (SUSE Linux)
> 

Output

This was a test run on MS Windows XP:

Console:
                                                                                
Press [ENTER] to start: ↵
        1       1
        0.1     10
        0.01    100
        0.001   1000
        0.0001  10000
        1e-005  100000
        1e-006  1e+006
        1e-007  1e+007
        1e-008  1e+008
        1e-009  1e+009
Press [ENTER] to continue: ^C

This was a test run on Linux:

Console:
                                                                                
Press [ENTER] to start: ↵
        1       1
        0.1     10
        0.01    100
        0.001   1000
        0.0001  10000
        1e-05   100000
        1e-06   1e+06
        1e-07   1e+07
        1e-08   1e+08
        1e-09   1e+09
Press [ENTER] to continue: ^C

Conclusion

The switch from common to scientific formatting occurs at the same powers of 10. Next time, I will implement a binary search to find the exact values...

Until now, the resulting code would be:

// decide format: common or scientific
if (value >= 1E6 || value <= -1E6
  || value <= 1E-5 && value >= -1E-5) { // scientific format
} else { // common format
}

Files

Text File print-float.cc...C++ source code
MS Visual C++ 2008 Project File print-float.vcproj...MS Visual C++ 2008 project file

dirk/C++/c++/print-float


Last modified: Sun Feb 28 13:16:40 2010